1 use crate::shared_ptr::{SharedPtr, SharedPtrTarget}; 2 use crate::string::CxxString; 3 use core::ffi::c_void; 4 use core::fmt::{self, Debug}; 5 use core::marker::PhantomData; 6 use core::mem::MaybeUninit; 7 8 /// Binding to C++ `std::weak_ptr<T>`. 9 /// 10 /// The typical way to construct a WeakPtr from Rust is by [downgrading] from a 11 /// SharedPtr. 12 /// 13 /// [downgrading]: crate::SharedPtr::downgrade 14 #[repr(C)] 15 pub struct WeakPtr<T> 16 where 17 T: WeakPtrTarget, 18 { 19 repr: [MaybeUninit<*mut c_void>; 2], 20 ty: PhantomData<T>, 21 } 22 23 impl<T> WeakPtr<T> 24 where 25 T: WeakPtrTarget, 26 { 27 /// Makes a new WeakPtr wrapping a null pointer. 28 /// 29 /// Matches the behavior of default-constructing a std::weak\_ptr. null() -> Self30 pub fn null() -> Self { 31 let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit(); 32 let new = weak_ptr.as_mut_ptr().cast(); 33 unsafe { 34 T::__null(new); 35 weak_ptr.assume_init() 36 } 37 } 38 39 /// Upgrades a non-owning reference into an owning reference if possible, 40 /// otherwise to a null reference. 41 /// 42 /// Matches the behavior of [std::weak_ptr\<T\>::lock](https://en.cppreference.com/w/cpp/memory/weak_ptr/lock). upgrade(&self) -> SharedPtr<T> where T: SharedPtrTarget,43 pub fn upgrade(&self) -> SharedPtr<T> 44 where 45 T: SharedPtrTarget, 46 { 47 let this = self as *const Self as *const c_void; 48 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit(); 49 let new = shared_ptr.as_mut_ptr().cast(); 50 unsafe { 51 T::__upgrade(this, new); 52 shared_ptr.assume_init() 53 } 54 } 55 } 56 57 unsafe impl<T> Send for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {} 58 unsafe impl<T> Sync for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {} 59 60 impl<T> Clone for WeakPtr<T> 61 where 62 T: WeakPtrTarget, 63 { clone(&self) -> Self64 fn clone(&self) -> Self { 65 let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit(); 66 let new = weak_ptr.as_mut_ptr().cast(); 67 let this = self as *const Self as *mut c_void; 68 unsafe { 69 T::__clone(this, new); 70 weak_ptr.assume_init() 71 } 72 } 73 } 74 75 impl<T> Drop for WeakPtr<T> 76 where 77 T: WeakPtrTarget, 78 { drop(&mut self)79 fn drop(&mut self) { 80 let this = self as *mut Self as *mut c_void; 81 unsafe { T::__drop(this) } 82 } 83 } 84 85 impl<T> Debug for WeakPtr<T> 86 where 87 T: Debug + WeakPtrTarget + SharedPtrTarget, 88 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result89 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 90 Debug::fmt(&self.upgrade(), formatter) 91 } 92 } 93 94 /// Trait bound for types which may be used as the `T` inside of a `WeakPtr<T>` 95 /// in generic code. 96 /// 97 /// This trait has no publicly callable or implementable methods. Implementing 98 /// it outside of the CXX codebase is not supported. 99 pub unsafe trait WeakPtrTarget { 100 #[doc(hidden)] __typename(f: &mut fmt::Formatter) -> fmt::Result101 fn __typename(f: &mut fmt::Formatter) -> fmt::Result; 102 #[doc(hidden)] __null(new: *mut c_void)103 unsafe fn __null(new: *mut c_void); 104 #[doc(hidden)] __clone(this: *const c_void, new: *mut c_void)105 unsafe fn __clone(this: *const c_void, new: *mut c_void); 106 #[doc(hidden)] __downgrade(shared: *const c_void, new: *mut c_void)107 unsafe fn __downgrade(shared: *const c_void, new: *mut c_void); 108 #[doc(hidden)] __upgrade(weak: *const c_void, shared: *mut c_void)109 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void); 110 #[doc(hidden)] __drop(this: *mut c_void)111 unsafe fn __drop(this: *mut c_void); 112 } 113 114 macro_rules! impl_weak_ptr_target { 115 ($segment:expr, $name:expr, $ty:ty) => { 116 unsafe impl WeakPtrTarget for $ty { 117 #[doc(hidden)] 118 fn __typename(f: &mut fmt::Formatter) -> fmt::Result { 119 f.write_str($name) 120 } 121 #[doc(hidden)] 122 unsafe fn __null(new: *mut c_void) { 123 extern "C" { 124 attr! { 125 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")] 126 fn __null(new: *mut c_void); 127 } 128 } 129 unsafe { __null(new) } 130 } 131 #[doc(hidden)] 132 unsafe fn __clone(this: *const c_void, new: *mut c_void) { 133 extern "C" { 134 attr! { 135 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")] 136 fn __clone(this: *const c_void, new: *mut c_void); 137 } 138 } 139 unsafe { __clone(this, new) } 140 } 141 #[doc(hidden)] 142 unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) { 143 extern "C" { 144 attr! { 145 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")] 146 fn __downgrade(shared: *const c_void, weak: *mut c_void); 147 } 148 } 149 unsafe { __downgrade(shared, weak) } 150 } 151 #[doc(hidden)] 152 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) { 153 extern "C" { 154 attr! { 155 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")] 156 fn __upgrade(weak: *const c_void, shared: *mut c_void); 157 } 158 } 159 unsafe { __upgrade(weak, shared) } 160 } 161 #[doc(hidden)] 162 unsafe fn __drop(this: *mut c_void) { 163 extern "C" { 164 attr! { 165 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")] 166 fn __drop(this: *mut c_void); 167 } 168 } 169 unsafe { __drop(this) } 170 } 171 } 172 }; 173 } 174 175 macro_rules! impl_weak_ptr_target_for_primitive { 176 ($ty:ident) => { 177 impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty); 178 }; 179 } 180 181 impl_weak_ptr_target_for_primitive!(bool); 182 impl_weak_ptr_target_for_primitive!(u8); 183 impl_weak_ptr_target_for_primitive!(u16); 184 impl_weak_ptr_target_for_primitive!(u32); 185 impl_weak_ptr_target_for_primitive!(u64); 186 impl_weak_ptr_target_for_primitive!(usize); 187 impl_weak_ptr_target_for_primitive!(i8); 188 impl_weak_ptr_target_for_primitive!(i16); 189 impl_weak_ptr_target_for_primitive!(i32); 190 impl_weak_ptr_target_for_primitive!(i64); 191 impl_weak_ptr_target_for_primitive!(isize); 192 impl_weak_ptr_target_for_primitive!(f32); 193 impl_weak_ptr_target_for_primitive!(f64); 194 195 impl_weak_ptr_target!("string", "CxxString", CxxString); 196