• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::fmt::display;
2 use crate::kind::Trivial;
3 use crate::string::CxxString;
4 use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
5 use crate::ExternType;
6 use core::ffi::c_void;
7 use core::fmt::{self, Debug, Display};
8 use core::marker::PhantomData;
9 use core::mem::MaybeUninit;
10 use core::ops::Deref;
11 
12 /// Binding to C++ `std::shared_ptr<T>`.
13 #[repr(C)]
14 pub struct SharedPtr<T>
15 where
16     T: SharedPtrTarget,
17 {
18     repr: [MaybeUninit<*mut c_void>; 2],
19     ty: PhantomData<T>,
20 }
21 
22 impl<T> SharedPtr<T>
23 where
24     T: SharedPtrTarget,
25 {
26     /// Makes a new SharedPtr wrapping a null pointer.
27     ///
28     /// Matches the behavior of default-constructing a std::shared\_ptr.
null() -> Self29     pub fn null() -> Self {
30         let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
31         let new = shared_ptr.as_mut_ptr().cast();
32         unsafe {
33             T::__null(new);
34             shared_ptr.assume_init()
35         }
36     }
37 
38     /// Allocates memory on the heap and makes a SharedPtr owner for it.
new(value: T) -> Self where T: ExternType<Kind = Trivial>,39     pub fn new(value: T) -> Self
40     where
41         T: ExternType<Kind = Trivial>,
42     {
43         let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
44         let new = shared_ptr.as_mut_ptr().cast();
45         unsafe {
46             T::__new(value, new);
47             shared_ptr.assume_init()
48         }
49     }
50 
51     /// Checks whether the SharedPtr does not own an object.
52     ///
53     /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
is_null(&self) -> bool54     pub fn is_null(&self) -> bool {
55         let this = self as *const Self as *const c_void;
56         let ptr = unsafe { T::__get(this) };
57         ptr.is_null()
58     }
59 
60     /// Returns a reference to the object owned by this SharedPtr if any,
61     /// otherwise None.
as_ref(&self) -> Option<&T>62     pub fn as_ref(&self) -> Option<&T> {
63         let this = self as *const Self as *const c_void;
64         unsafe { T::__get(this).as_ref() }
65     }
66 
67     /// Constructs new WeakPtr as a non-owning reference to the object managed
68     /// by `self`. If `self` manages no object, the WeakPtr manages no object
69     /// too.
70     ///
71     /// Matches the behavior of [std::weak_ptr\<T\>::weak_ptr(const std::shared_ptr\<T\> \&)](https://en.cppreference.com/w/cpp/memory/weak_ptr/weak_ptr).
downgrade(self: &SharedPtr<T>) -> WeakPtr<T> where T: WeakPtrTarget,72     pub fn downgrade(self: &SharedPtr<T>) -> WeakPtr<T>
73     where
74         T: WeakPtrTarget,
75     {
76         let this = self as *const Self as *const c_void;
77         let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
78         let new = weak_ptr.as_mut_ptr().cast();
79         unsafe {
80             T::__downgrade(this, new);
81             weak_ptr.assume_init()
82         }
83     }
84 }
85 
86 unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
87 unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
88 
89 impl<T> Clone for SharedPtr<T>
90 where
91     T: SharedPtrTarget,
92 {
clone(&self) -> Self93     fn clone(&self) -> Self {
94         let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
95         let new = shared_ptr.as_mut_ptr().cast();
96         let this = self as *const Self as *mut c_void;
97         unsafe {
98             T::__clone(this, new);
99             shared_ptr.assume_init()
100         }
101     }
102 }
103 
104 // SharedPtr is not a self-referential type and is safe to move out of a Pin,
105 // regardless whether the pointer's target is Unpin.
106 impl<T> Unpin for SharedPtr<T> where T: SharedPtrTarget {}
107 
108 impl<T> Drop for SharedPtr<T>
109 where
110     T: SharedPtrTarget,
111 {
drop(&mut self)112     fn drop(&mut self) {
113         let this = self as *mut Self as *mut c_void;
114         unsafe { T::__drop(this) }
115     }
116 }
117 
118 impl<T> Deref for SharedPtr<T>
119 where
120     T: SharedPtrTarget,
121 {
122     type Target = T;
123 
deref(&self) -> &Self::Target124     fn deref(&self) -> &Self::Target {
125         match self.as_ref() {
126             Some(target) => target,
127             None => panic!(
128                 "called deref on a null SharedPtr<{}>",
129                 display(T::__typename),
130             ),
131         }
132     }
133 }
134 
135 impl<T> Debug for SharedPtr<T>
136 where
137     T: Debug + SharedPtrTarget,
138 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result139     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
140         match self.as_ref() {
141             None => formatter.write_str("nullptr"),
142             Some(value) => Debug::fmt(value, formatter),
143         }
144     }
145 }
146 
147 impl<T> Display for SharedPtr<T>
148 where
149     T: Display + SharedPtrTarget,
150 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result151     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
152         match self.as_ref() {
153             None => formatter.write_str("nullptr"),
154             Some(value) => Display::fmt(value, formatter),
155         }
156     }
157 }
158 
159 /// Trait bound for types which may be used as the `T` inside of a
160 /// `SharedPtr<T>` in generic code.
161 ///
162 /// This trait has no publicly callable or implementable methods. Implementing
163 /// it outside of the CXX codebase is not supported.
164 ///
165 /// # Example
166 ///
167 /// A bound `T: SharedPtrTarget` may be necessary when manipulating
168 /// [`SharedPtr`] in generic code.
169 ///
170 /// ```
171 /// use cxx::memory::{SharedPtr, SharedPtrTarget};
172 /// use std::fmt::Display;
173 ///
174 /// pub fn take_generic_ptr<T>(ptr: SharedPtr<T>)
175 /// where
176 ///     T: SharedPtrTarget + Display,
177 /// {
178 ///     println!("the shared_ptr points to: {}", *ptr);
179 /// }
180 /// ```
181 ///
182 /// Writing the same generic function without a `SharedPtrTarget` trait bound
183 /// would not compile.
184 pub unsafe trait SharedPtrTarget {
185     #[doc(hidden)]
__typename(f: &mut fmt::Formatter) -> fmt::Result186     fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
187     #[doc(hidden)]
__null(new: *mut c_void)188     unsafe fn __null(new: *mut c_void);
189     #[doc(hidden)]
__new(value: Self, new: *mut c_void) where Self: Sized,190     unsafe fn __new(value: Self, new: *mut c_void)
191     where
192         Self: Sized,
193     {
194         // Opoaque C types do not get this method because they can never exist
195         // by value on the Rust side of the bridge.
196         let _ = value;
197         let _ = new;
198         unreachable!()
199     }
200     #[doc(hidden)]
__clone(this: *const c_void, new: *mut c_void)201     unsafe fn __clone(this: *const c_void, new: *mut c_void);
202     #[doc(hidden)]
__get(this: *const c_void) -> *const Self203     unsafe fn __get(this: *const c_void) -> *const Self;
204     #[doc(hidden)]
__drop(this: *mut c_void)205     unsafe fn __drop(this: *mut c_void);
206 }
207 
208 macro_rules! impl_shared_ptr_target {
209     ($segment:expr, $name:expr, $ty:ty) => {
210         unsafe impl SharedPtrTarget for $ty {
211             fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
212                 f.write_str($name)
213             }
214             unsafe fn __null(new: *mut c_void) {
215                 extern "C" {
216                     attr! {
217                         #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
218                         fn __null(new: *mut c_void);
219                     }
220                 }
221                 unsafe { __null(new) }
222             }
223             unsafe fn __new(value: Self, new: *mut c_void) {
224                 extern "C" {
225                     attr! {
226                         #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
227                         fn __uninit(new: *mut c_void) -> *mut c_void;
228                     }
229                 }
230                 unsafe { __uninit(new).cast::<$ty>().write(value) }
231             }
232             unsafe fn __clone(this: *const c_void, new: *mut c_void) {
233                 extern "C" {
234                     attr! {
235                         #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
236                         fn __clone(this: *const c_void, new: *mut c_void);
237                     }
238                 }
239                 unsafe { __clone(this, new) }
240             }
241             unsafe fn __get(this: *const c_void) -> *const Self {
242                 extern "C" {
243                     attr! {
244                         #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
245                         fn __get(this: *const c_void) -> *const c_void;
246                     }
247                 }
248                 unsafe { __get(this) }.cast()
249             }
250             unsafe fn __drop(this: *mut c_void) {
251                 extern "C" {
252                     attr! {
253                         #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
254                         fn __drop(this: *mut c_void);
255                     }
256                 }
257                 unsafe { __drop(this) }
258             }
259         }
260     };
261 }
262 
263 macro_rules! impl_shared_ptr_target_for_primitive {
264     ($ty:ident) => {
265         impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
266     };
267 }
268 
269 impl_shared_ptr_target_for_primitive!(bool);
270 impl_shared_ptr_target_for_primitive!(u8);
271 impl_shared_ptr_target_for_primitive!(u16);
272 impl_shared_ptr_target_for_primitive!(u32);
273 impl_shared_ptr_target_for_primitive!(u64);
274 impl_shared_ptr_target_for_primitive!(usize);
275 impl_shared_ptr_target_for_primitive!(i8);
276 impl_shared_ptr_target_for_primitive!(i16);
277 impl_shared_ptr_target_for_primitive!(i32);
278 impl_shared_ptr_target_for_primitive!(i64);
279 impl_shared_ptr_target_for_primitive!(isize);
280 impl_shared_ptr_target_for_primitive!(f32);
281 impl_shared_ptr_target_for_primitive!(f64);
282 
283 impl_shared_ptr_target!("string", "CxxString", CxxString);
284