1use crate::fmt::display; 2use crate::kind::Trivial; 3use crate::string::CxxString; 4use crate::weak_ptr::{WeakPtr, WeakPtrTarget}; 5use crate::ExternType; 6use core::ffi::c_void; 7use core::fmt::{self, Debug, Display}; 8use core::marker::PhantomData; 9use core::mem::MaybeUninit; 10use core::ops::Deref; 11 12/// Binding to C++ `std::shared_ptr<T>`. 13#[repr(C)] 14pub struct SharedPtr<T> 15where 16 T: SharedPtrTarget, 17{ 18 repr: [MaybeUninit<*mut c_void>; 2], 19 ty: PhantomData<T>, 20} 21 22impl<T> SharedPtr<T> 23where 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. 29 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. 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). 54 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. 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). 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 86unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {} 87unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {} 88 89impl<T> Clone for SharedPtr<T> 90where 91 T: SharedPtrTarget, 92{ 93 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. 106impl<T> Unpin for SharedPtr<T> where T: SharedPtrTarget {} 107 108impl<T> Drop for SharedPtr<T> 109where 110 T: SharedPtrTarget, 111{ 112 fn drop(&mut self) { 113 let this = self as *mut Self as *mut c_void; 114 unsafe { T::__drop(this) } 115 } 116} 117 118impl<T> Deref for SharedPtr<T> 119where 120 T: SharedPtrTarget, 121{ 122 type Target = T; 123 124 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 135impl<T> Debug for SharedPtr<T> 136where 137 T: Debug + SharedPtrTarget, 138{ 139 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 147impl<T> Display for SharedPtr<T> 148where 149 T: Display + SharedPtrTarget, 150{ 151 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. 184pub unsafe trait SharedPtrTarget { 185 #[doc(hidden)] 186 fn __typename(f: &mut fmt::Formatter) -> fmt::Result; 187 #[doc(hidden)] 188 unsafe fn __null(new: *mut c_void); 189 #[doc(hidden)] 190 unsafe fn __new(value: Self, new: *mut c_void) 191 where 192 Self: Sized, 193 { 194 // Opaque C types do not get this method because they can never exist by 195 // value on the Rust side of the bridge. 196 let _ = value; 197 let _ = new; 198 unreachable!() 199 } 200 #[doc(hidden)] 201 unsafe fn __clone(this: *const c_void, new: *mut c_void); 202 #[doc(hidden)] 203 unsafe fn __get(this: *const c_void) -> *const Self; 204 #[doc(hidden)] 205 unsafe fn __drop(this: *mut c_void); 206} 207 208macro_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 263macro_rules! impl_shared_ptr_target_for_primitive { 264 ($ty:ident) => { 265 impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty); 266 }; 267} 268 269impl_shared_ptr_target_for_primitive!(bool); 270impl_shared_ptr_target_for_primitive!(u8); 271impl_shared_ptr_target_for_primitive!(u16); 272impl_shared_ptr_target_for_primitive!(u32); 273impl_shared_ptr_target_for_primitive!(u64); 274impl_shared_ptr_target_for_primitive!(usize); 275impl_shared_ptr_target_for_primitive!(i8); 276impl_shared_ptr_target_for_primitive!(i16); 277impl_shared_ptr_target_for_primitive!(i32); 278impl_shared_ptr_target_for_primitive!(i64); 279impl_shared_ptr_target_for_primitive!(isize); 280impl_shared_ptr_target_for_primitive!(f32); 281impl_shared_ptr_target_for_primitive!(f64); 282 283impl_shared_ptr_target!("string", "CxxString", CxxString); 284