com_scrape_types/ptr.rs
1use std::marker::PhantomData;
2use std::mem;
3use std::ptr::NonNull;
4
5use super::{Inherits, Interface};
6
7/// Trait for types that represent a smart pointer to a COM object.
8///
9/// Implemented by [`ComPtr`] and [`ComRef`].
10///
11/// The purpose of this trait is to enable blanket implementations of interface traits for all
12/// smart pointers with a compatible target for that interface. For each interface `IInterface`,
13/// `com-scrape` will generate a blanket implementation of `IInterfaceTrait` as follows:
14///
15/// ```ignore
16/// impl<P> IInterfaceTrait for P
17/// where
18/// P: SmartPtr,
19/// P::Target: Inherits<IInterface>,
20/// {
21/// /* ... */
22/// }
23/// ```
24///
25/// This makes it possible to call the methods of `IInterface` directly on a `ComPtr<IInterface>`,
26/// or on any `ComPtr<IOtherInterface>` where `IOtherInterface` is derived from from `IInterface`.
27pub trait SmartPtr {
28 /// The interface type pointed to by this smart pointer.
29 type Target;
30
31 /// Gets the raw pointer held by this smart pointer.
32 fn ptr(&self) -> *mut Self::Target;
33}
34
35/// A non-owning smart pointer to a COM object.
36///
37/// A `ComRef<'a, I>` represents a borrowed reference to a COM object implementing interface `I`.
38/// Like [`ComPtr`], `ComRef` can be used to call interface methods on the referenced object.
39/// Unlike [`ComPtr`], `ComRef` does not manage the object's reference count, i.e. it will *not*
40/// call the release method of the object it points to when going out of scope. See the
41/// [crate-level documentation](crate#reference-counting) for more information.
42///
43/// A `ComRef` can be created safely from a [`ComPtr`] via [`ComPtr::as_com_ref`], or from a
44/// [`ComWrapper`][crate::ComWrapper] via [`ComWrapper::as_com_ref`][crate::ComWrapper::as_com_ref].
45/// It can also be created unsafely via [`ComRef::from_raw`].
46pub struct ComRef<'a, I: Interface> {
47 ptr: NonNull<I>,
48 _marker: PhantomData<&'a I>,
49}
50
51impl<'a, I: Interface> SmartPtr for ComRef<'a, I> {
52 type Target = I;
53
54 #[inline]
55 fn ptr(&self) -> *mut I {
56 self.ptr.as_ptr()
57 }
58}
59
60impl<'a, I: Interface> Copy for ComRef<'a, I> {}
61
62impl<'a, I: Interface> Clone for ComRef<'a, I> {
63 #[inline]
64 fn clone(&self) -> ComRef<'a, I> {
65 ComRef {
66 ptr: self.ptr,
67 _marker: PhantomData,
68 }
69 }
70}
71
72unsafe impl<'a, I: Interface> Send for ComRef<'a, I> where I: Sync + Send {}
73
74unsafe impl<'a, I: Interface> Sync for ComRef<'a, I> where I: Sync + Send {}
75
76impl<'a, I: Interface> ComRef<'a, I> {
77 /// Gets the wrapped interface pointer.
78 ///
79 /// Does not perform any reference counting operations.
80 #[inline]
81 pub fn as_ptr(&self) -> *mut I {
82 self.ptr.as_ptr() as *mut I
83 }
84
85 /// Creates a `ComRef` from a raw interface pointer if the pointer is non-null.
86 ///
87 /// Does not perform any reference counting operations.
88 ///
89 /// `from_raw` will check if `ptr` is null (and return `None` if so), but this method is still
90 /// unsafe, as the caller must still ensure that `ptr` is a valid interface pointer (see below)
91 /// if it is non-null.
92 ///
93 /// # Safety
94 ///
95 /// If `ptr` is non-null, it must be a valid pointer to a value of type `I`, and if `*ptr` is
96 /// reinterpreted as `*const I::Vtbl` (see the [safety documentation](Interface#safety) for
97 /// [`Interface`]), it must in turn be a valid pointer to `I::Vtbl`.
98 #[inline]
99 pub unsafe fn from_raw(ptr: *mut I) -> Option<ComRef<'a, I>> {
100 NonNull::new(ptr).map(|ptr| ComRef {
101 ptr,
102 _marker: PhantomData,
103 })
104 }
105
106 /// Creates a `ComRef` from a raw interface pointer.
107 ///
108 /// Does not perform any reference counting operations.
109 ///
110 /// # Safety
111 ///
112 /// `ptr` must be a valid pointer to a value of type `I`, and if `*ptr` is reinterpreted as
113 /// `*const I::Vtbl` (see the [safety documentation](Interface#safety) for [`Interface`]), it
114 /// must in turn be a valid pointer to `I::Vtbl`.
115 #[inline]
116 pub unsafe fn from_raw_unchecked(ptr: *mut I) -> ComRef<'a, I> {
117 ComRef {
118 ptr: NonNull::new_unchecked(ptr),
119 _marker: PhantomData,
120 }
121 }
122
123 /// Upgrades the `ComRef` to a [`ComPtr`].
124 ///
125 /// Increments the reference count of the object that the `ComRef` points to.
126 #[inline]
127 pub fn to_com_ptr(&self) -> ComPtr<I> {
128 unsafe {
129 let ptr = self.ptr.as_ptr();
130
131 I::add_ref(ptr);
132
133 ComPtr::from_raw_unchecked(ptr)
134 }
135 }
136
137 /// Casts the `ComRef` from a derived interface to a base interface.
138 ///
139 /// Does not perform any reference counting operations.
140 #[inline]
141 pub fn upcast<J: Interface>(self) -> ComRef<'a, J>
142 where
143 I: Inherits<J>,
144 {
145 unsafe { ComRef::from_raw_unchecked(self.as_ptr() as *mut J) }
146 }
147
148 /// Attempts to cast from one interface to another, returning a [`ComPtr`] if successful.
149 ///
150 /// If the cast is successful, increments the reference count of the object that the `ComRef`
151 /// points to.
152 #[inline]
153 pub fn cast<J: Interface>(&self) -> Option<ComPtr<J>> {
154 unsafe {
155 if let Some(ptr) = I::query_interface(self.ptr.as_ptr(), &J::IID) {
156 ComPtr::from_raw(ptr as *mut J)
157 } else {
158 None
159 }
160 }
161 }
162}
163
164/// An owning smart pointer to a COM object.
165///
166/// A `ComPtr<I>` represents an owning reference to a COM object implementing interface `I`. Like
167/// [`ComRef`], `ComPtr` can be used to call interface methods on the referenced object. Unlike
168/// [`ComRef`], `ComPtr` manages the object's reference count, i.e. it *will* call the release
169/// method of the object it points to when going out of scope. See the
170/// [crate-level documentation](crate#reference-counting) for more information.
171///
172/// A `ComPtr` can be created safely from a [`ComRef`] via [`ComRef::to_com_ptr`], or from a
173/// [`ComWrapper`][crate::ComWrapper] via [`ComWrapper::to_com_ptr`][crate::ComWrapper::to_com_ptr].
174/// It can also be created unsafely via [`ComPtr::from_raw`].
175pub struct ComPtr<I: Interface> {
176 ptr: NonNull<I>,
177}
178
179impl<I: Interface> SmartPtr for ComPtr<I> {
180 type Target = I;
181
182 #[inline]
183 fn ptr(&self) -> *mut I {
184 self.ptr.as_ptr()
185 }
186}
187
188impl<I: Interface> Clone for ComPtr<I> {
189 #[inline]
190 fn clone(&self) -> ComPtr<I> {
191 unsafe {
192 I::add_ref(self.ptr.as_ptr());
193 }
194
195 ComPtr { ptr: self.ptr }
196 }
197}
198
199unsafe impl<I: Interface> Send for ComPtr<I> where I: Sync + Send {}
200
201unsafe impl<I: Interface> Sync for ComPtr<I> where I: Sync + Send {}
202
203impl<I: Interface> Drop for ComPtr<I> {
204 #[inline]
205 fn drop(&mut self) {
206 unsafe {
207 I::release(self.ptr.as_ptr());
208 }
209 }
210}
211
212impl<I: Interface> ComPtr<I> {
213 /// Gets the wrapped interface pointer.
214 ///
215 /// Does not perform any reference counting operations.
216 #[inline]
217 pub fn as_ptr(&self) -> *mut I {
218 self.ptr.as_ptr() as *mut I
219 }
220
221 /// Creates a `ComPtr` from a raw interface pointer if the pointer is non-null.
222 ///
223 /// When the resulting `ComPtr` is dropped, the reference count of the object it points to will
224 /// be decremented. Thus, using this method can be thought of as "taking ownership" of a
225 /// pointer to a COM object.
226 ///
227 /// `from_raw` will check if `ptr` is null (and return `None` if so), but this method is still
228 /// unsafe, as the caller must still ensure that `ptr` is a valid interface pointer (see below)
229 /// if it is non-null.
230 ///
231 /// # Safety
232 ///
233 /// If `ptr` is non-null, it must be a valid pointer to a value of type `I`, and if `*ptr` is
234 /// reinterpreted as `*const I::Vtbl` (see the [safety documentation](Interface#safety) for
235 /// [`Interface`]), it must in turn be a valid pointer to `I::Vtbl`.
236 #[inline]
237 pub unsafe fn from_raw(ptr: *mut I) -> Option<ComPtr<I>> {
238 NonNull::new(ptr).map(|ptr| ComPtr { ptr })
239 }
240
241 /// Creates a `ComPtr` from a raw interface pointer.
242 ///
243 /// When the resulting `ComPtr` is dropped, the reference count of the object it points to will
244 /// be decremented. Thus, using this method can be thought of as "taking ownership" of a
245 /// pointer to a COM object.
246 ///
247 /// # Safety
248 ///
249 /// `ptr` must be a valid pointer to a value of type `I`, and if `*ptr` is reinterpreted as
250 /// `*const I::Vtbl` (see the [safety documentation](Interface#safety) for [`Interface`]), it
251 /// must in turn be a valid pointer to `I::Vtbl`.
252 #[inline]
253 pub unsafe fn from_raw_unchecked(ptr: *mut I) -> ComPtr<I> {
254 ComPtr {
255 ptr: NonNull::new_unchecked(ptr),
256 }
257 }
258
259 /// Consumes the `ComPtr`, returning the wrapped interface pointer.
260 ///
261 /// Since this method consumes the `ComPtr`, it prevents the `ComPtr` from decrementing the
262 /// reference count of the object it points to. Thus, using this method can be thought of as
263 /// "relinquishing ownership" of a pointer to a COM object.
264 #[inline]
265 pub fn into_raw(self) -> *mut I {
266 let ptr = self.ptr.as_ptr();
267 mem::forget(self);
268 ptr
269 }
270
271 /// Returns a [`ComRef`] pointing to the same object as this `ComPtr`. Can be thought of as a
272 /// borrow.
273 ///
274 /// Does not perform any reference counting operations.
275 #[inline]
276 pub fn as_com_ref<'a>(&'a self) -> ComRef<'a, I> {
277 unsafe { ComRef::from_raw_unchecked(self.ptr.as_ptr()) }
278 }
279
280 /// Does not perform any reference counting operations.
281 #[inline]
282 pub fn upcast<J: Interface>(self) -> ComPtr<J>
283 where
284 I: Inherits<J>,
285 {
286 unsafe { ComPtr::from_raw_unchecked(self.into_raw() as *mut J) }
287 }
288
289 /// Attempts to cast from one interface to another, returning another [`ComPtr`] if successful.
290 ///
291 /// If the cast is successful, increments the reference count of the object that the `ComPtr`
292 /// points to.
293 #[inline]
294 pub fn cast<J: Interface>(&self) -> Option<ComPtr<J>> {
295 unsafe {
296 if let Some(ptr) = I::query_interface(self.ptr.as_ptr(), &J::IID) {
297 ComPtr::from_raw(ptr as *mut J)
298 } else {
299 None
300 }
301 }
302 }
303}