summaryrefslogtreecommitdiff
path: root/vendor/windows-core/src/com_object.rs
blob: bcd1926a50bc40e5f37d97386e8e3b7308e2e550 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
use crate::imp::Box;
use crate::{IUnknown, IUnknownImpl, Interface, InterfaceRef};
use core::any::Any;
use core::borrow::Borrow;
use core::ops::Deref;
use core::ptr::NonNull;

/// Identifies types that can be placed in [`ComObject`].
///
/// This trait links types that can be placed in `ComObject` with the types generated by the
/// `#[implement]` macro. The `#[implement]` macro generates implementations of this trait.
/// The generated types contain the vtable layouts and refcount-related fields for the COM
/// object implementation.
///
/// This trait is an implementation detail of the Windows crates.
/// User code should not deal directly with this trait.
///
/// This trait is sort of the reverse of [`IUnknownImpl`]. This trait allows user code to use
/// [`ComObject<T>`] instead of `ComObject<T_Impl>`.
pub trait ComObjectInner: Sized {
    /// The generated `<foo>_Impl` type (aka the "boxed" type or "outer" type).
    type Outer: IUnknownImpl<Impl = Self>;

    /// Moves an instance of this type into a new ComObject box and returns it.
    ///
    /// # Safety
    ///
    /// It is important that safe Rust code never be able to acquire an owned instance of a
    /// generated "outer" COM object type, e.g. `<foo>_Impl`. This would be unsafe because the
    /// `<foo>_Impl` object contains a reference count field and provides methods that adjust
    /// the reference count, and destroy the object when the reference count reaches zero.
    ///
    /// Safe Rust code must only be able to interact with these values by accessing them via a
    /// `ComObject` reference. `ComObject` handles adjusting reference counts and associates the
    /// lifetime of a `&<foo>_Impl` with the lifetime of the related `ComObject`.
    ///
    /// The `#[implement]` macro generates the implementation of this `into_object` method.
    /// The generated `into_object` method encapsulates the construction of the `<foo>_Impl`
    /// object and immediately places it into the heap and returns a `ComObject` reference to it.
    /// This ensures that our requirement -- that safe Rust code never own a `<foo>_Impl` value
    /// directly -- is met.
    fn into_object(self) -> ComObject<Self>;
}

/// Describes the COM interfaces implemented by a specific COM object.
///
/// The `#[implement]` macro generates implementations of this trait. Implementations are attached
/// to the "outer" types generated by `#[implement]`, e.g. the `MyApp_Impl` type. Each
/// implementation knows how to locate the interface-specific field within `MyApp_Impl`.
///
/// This trait is an implementation detail of the Windows crates.
/// User code should not deal directly with this trait.
pub trait ComObjectInterface<I: Interface> {
    /// Gets a borrowed interface that is implemented by `T`.
    fn as_interface_ref(&self) -> InterfaceRef<'_, I>;
}

/// A counted pointer to a type that implements COM interfaces, where the object has been
/// placed in the heap (boxed).
///
/// This type exists so that you can place an object into the heap and query for COM interfaces,
/// without losing the safe reference to the implementation object.
///
/// Because the pointer inside this type is known to be non-null, `Option<ComObject<T>>` should
/// always have the same size as a single pointer.
///
/// # Safety
///
/// The contained `ptr` field is an owned, reference-counted pointer to a _pinned_ `Pin<Box<T::Outer>>`.
/// Although this code does not currently use `Pin<T>`, it takes care not to expose any unsafe semantics
/// to safe code. However, code that calls unsafe functions on [`ComObject`] must, like all unsafe code,
/// understand and preserve invariants.
#[repr(transparent)]
pub struct ComObject<T: ComObjectInner> {
    ptr: NonNull<T::Outer>,
}

impl<T: ComObjectInner> ComObject<T> {
    /// Allocates a heap cell (box) and moves `value` into it. Returns a counted pointer to `value`.
    pub fn new(value: T) -> Self {
        T::into_object(value)
    }

    /// Creates a new `ComObject` that points to an existing boxed instance.
    ///
    /// # Safety
    ///
    /// The caller must ensure that `ptr` points to a valid, heap-allocated instance of `T::Outer`.
    /// Normally, this pointer comes from using `Box::into_raw(Box::new(...))`.
    ///
    /// The pointed-to box must have a reference count that is greater than zero.
    ///
    /// This function takes ownership of the existing pointer; it does not call `AddRef`.
    /// The reference count must accurately reflect all outstanding references to the box,
    /// including `ptr` in the count.
    pub unsafe fn from_raw(ptr: NonNull<T::Outer>) -> Self {
        Self { ptr }
    }

    /// Gets a reference to the shared object stored in the box.
    ///
    /// [`ComObject`] also implements [`Deref`], so you can often deref directly into the object.
    /// For those situations where using the [`Deref`] impl is inconvenient, you can use
    /// this method to explicitly get a reference to the contents.
    #[inline(always)]
    pub fn get(&self) -> &T {
        self.get_box().get_impl()
    }

    /// Gets a reference to the shared object's heap box.
    #[inline(always)]
    fn get_box(&self) -> &T::Outer {
        unsafe { self.ptr.as_ref() }
    }

    // Note that we _do not_ provide a way to get a mutable reference to the outer box.
    // It's ok to return `&mut T`, but not `&mut T::Outer`. That would allow someone to replace the
    // contents of the entire object (box and reference count), which could lead to UB.
    // This could maybe be solved by returning `Pin<&mut T::Outer>`, but that requires some
    // additional thinking.

    /// Gets a mutable reference to the object stored in the box, if the reference count
    /// is exactly 1. If there are multiple references to this object then this returns `None`.
    #[inline(always)]
    pub fn get_mut(&mut self) -> Option<&mut T> {
        if self.is_reference_count_one() {
            // SAFETY: We must only return &mut T, *NOT* &mut T::Outer.
            // Returning T::Outer would allow swapping the contents of the object, which would
            // allow (incorrectly) modifying the reference count.
            unsafe { Some(self.ptr.as_mut().get_impl_mut()) }
        } else {
            None
        }
    }

    /// If this object has only a single object reference (i.e. this [`ComObject`] is the only
    /// reference to the heap allocation), then this method will extract the inner `T`
    /// (and return it in an `Ok`) and then free the heap allocation.
    ///
    /// If there is more than one reference to this object, then this returns `Err(self)`.
    #[inline(always)]
    pub fn take(self) -> Result<T, Self> {
        if self.is_reference_count_one() {
            let outer_box: Box<T::Outer> = unsafe { core::mem::transmute(self) };
            Ok(outer_box.into_inner())
        } else {
            Err(self)
        }
    }

    /// Casts to a given interface type.
    ///
    /// This always performs a `QueryInterface`, even if `T` is known to implement `I`.
    /// If you know that `T` implements `I`, then use [`Self::as_interface`] or [`Self::to_interface`] because
    /// those functions do not require a dynamic `QueryInterface` call.
    #[inline(always)]
    pub fn cast<I: Interface>(&self) -> windows_core::Result<I>
    where
        T::Outer: ComObjectInterface<IUnknown>,
    {
        let unknown = self.as_interface::<IUnknown>();
        unknown.cast()
    }

    /// Gets a borrowed reference to an interface that is implemented by `T`.
    ///
    /// The returned reference does not have an additional reference count.
    /// You can AddRef it by calling [`InterfaceRef::to_owned`].
    #[inline(always)]
    pub fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I>
    where
        T::Outer: ComObjectInterface<I>,
    {
        self.get_box().as_interface_ref()
    }

    /// Gets an owned (counted) reference to an interface that is implemented by this [`ComObject`].
    #[inline(always)]
    pub fn to_interface<I: Interface>(&self) -> I
    where
        T::Outer: ComObjectInterface<I>,
    {
        self.as_interface::<I>().to_owned()
    }

    /// Converts `self` into an interface that it implements.
    ///
    /// This does not need to adjust reference counts because `self` is consumed.
    #[inline(always)]
    pub fn into_interface<I: Interface>(self) -> I
    where
        T::Outer: ComObjectInterface<I>,
    {
        unsafe {
            let raw = self.get_box().as_interface_ref().as_raw();
            core::mem::forget(self);
            I::from_raw(raw)
        }
    }

    /// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer"
    /// object, e.g. `MyApp_Impl`, not the inner `MyApp` object.
    ///
    /// `T` must be a type that has been annotated with `#[implement]`; this is checked at
    /// compile-time by the generic constraints of this method. However, note that the
    /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
    /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
    ///
    /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
    /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
    ///
    /// The returned value is an owned (counted) reference; this function calls `AddRef` on the
    /// underlying COM object. If you do not need an owned reference, then you can use the
    /// [`Interface::cast_object_ref`] method instead, and avoid the cost of `AddRef` / `Release`.
    pub fn cast_from<I>(interface: &I) -> crate::Result<Self>
    where
        I: Interface,
        T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
    {
        interface.cast_object()
    }
}

impl<T: ComObjectInner + Default> Default for ComObject<T> {
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<T: ComObjectInner> Drop for ComObject<T> {
    fn drop(&mut self) {
        unsafe {
            T::Outer::Release(self.ptr.as_ptr());
        }
    }
}

impl<T: ComObjectInner> Clone for ComObject<T> {
    #[inline(always)]
    fn clone(&self) -> Self {
        unsafe {
            self.ptr.as_ref().AddRef();
            Self { ptr: self.ptr }
        }
    }
}

impl<T: ComObjectInner> AsRef<T> for ComObject<T> {
    #[inline(always)]
    fn as_ref(&self) -> &T {
        self.get()
    }
}

impl<T: ComObjectInner> Deref for ComObject<T> {
    type Target = T::Outer;

    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        self.get_box()
    }
}

// There is no DerefMut implementation because we cannot statically guarantee
// that the reference count is 1, which is a requirement for getting exclusive
// access to the contents of the object. Use get_mut() for dynamically-checked
// exclusive access.

impl<T: ComObjectInner> From<T> for ComObject<T> {
    fn from(value: T) -> ComObject<T> {
        ComObject::new(value)
    }
}

// Delegate hashing, if implemented.
impl<T: ComObjectInner + core::hash::Hash> core::hash::Hash for ComObject<T> {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        self.get().hash(state);
    }
}

// If T is Send (or Sync) then the ComObject<T> is also Send (or Sync).
// Since the actual object storage is in the heap, the object is never moved.
unsafe impl<T: ComObjectInner + Send> Send for ComObject<T> {}
unsafe impl<T: ComObjectInner + Sync> Sync for ComObject<T> {}

impl<T: ComObjectInner + PartialEq> PartialEq for ComObject<T> {
    fn eq(&self, other: &ComObject<T>) -> bool {
        let inner_self: &T = self.get();
        let other_self: &T = other.get();
        inner_self == other_self
    }
}

impl<T: ComObjectInner + Eq> Eq for ComObject<T> {}

impl<T: ComObjectInner + PartialOrd> PartialOrd for ComObject<T> {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        let inner_self: &T = self.get();
        let other_self: &T = other.get();
        <T as PartialOrd>::partial_cmp(inner_self, other_self)
    }
}

impl<T: ComObjectInner + Ord> Ord for ComObject<T> {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        let inner_self: &T = self.get();
        let other_self: &T = other.get();
        <T as Ord>::cmp(inner_self, other_self)
    }
}

impl<T: ComObjectInner + core::fmt::Debug> core::fmt::Debug for ComObject<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        <T as core::fmt::Debug>::fmt(self.get(), f)
    }
}

impl<T: ComObjectInner + core::fmt::Display> core::fmt::Display for ComObject<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        <T as core::fmt::Display>::fmt(self.get(), f)
    }
}

impl<T: ComObjectInner> Borrow<T> for ComObject<T> {
    fn borrow(&self) -> &T {
        self.get()
    }
}

/// Enables applications to define COM objects using static storage. This is useful for factory
/// objects, stateless objects, or objects which use need to contain or use mutable global state.
///
/// COM objects that are defined using `StaticComObject` have their storage placed directly in
/// static storage; they are not stored in the heap.
///
/// COM objects defined using `StaticComObject` do have a reference count and this reference
/// count is adjusted when owned COM interface references (e.g. `IFoo` and `IUnknown`) are created
/// for the object. The reference count is initialized to 1.
///
/// # Example
///
/// ```rust,ignore
/// #[implement(IFoo)]
/// struct MyApp {
///     // ...
/// }
///
/// static MY_STATIC_APP: StaticComObject<MyApp> = MyApp { ... }.into_static();
///
/// fn get_my_static_ifoo() -> IFoo {
///     MY_STATIC_APP.to_interface()
/// }
/// ```
pub struct StaticComObject<T>
where
    T: ComObjectInner,
{
    outer: T::Outer,
}

// IMPORTANT: Do not expose any methods that return mutable access to the contents of StaticComObject.
// Doing so would violate our safety invariants. For example, we provide a Deref impl but it would
// be unsound to provide a DerefMut impl.
impl<T> StaticComObject<T>
where
    T: ComObjectInner,
{
    /// Wraps `outer` in a `StaticComObject`.
    pub const fn from_outer(outer: T::Outer) -> Self {
        Self { outer }
    }
}

impl<T> StaticComObject<T>
where
    T: ComObjectInner,
{
    /// Gets access to the contained value.
    pub const fn get(&'static self) -> &'static T::Outer {
        &self.outer
    }
}

impl<T> core::ops::Deref for StaticComObject<T>
where
    T: ComObjectInner,
{
    type Target = T::Outer;

    fn deref(&self) -> &Self::Target {
        &self.outer
    }
}