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