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 fn __typename(f: &mut fmt::Formatter) -> fmt::Result { 118 f.write_str($name) 119 } 120 unsafe fn __null(new: *mut c_void) { 121 extern "C" { 122 attr! { 123 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")] 124 fn __null(new: *mut c_void); 125 } 126 } 127 unsafe { __null(new) } 128 } 129 unsafe fn __clone(this: *const c_void, new: *mut c_void) { 130 extern "C" { 131 attr! { 132 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")] 133 fn __clone(this: *const c_void, new: *mut c_void); 134 } 135 } 136 unsafe { __clone(this, new) } 137 } 138 unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) { 139 extern "C" { 140 attr! { 141 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")] 142 fn __downgrade(shared: *const c_void, weak: *mut c_void); 143 } 144 } 145 unsafe { __downgrade(shared, weak) } 146 } 147 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) { 148 extern "C" { 149 attr! { 150 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")] 151 fn __upgrade(weak: *const c_void, shared: *mut c_void); 152 } 153 } 154 unsafe { __upgrade(weak, shared) } 155 } 156 unsafe fn __drop(this: *mut c_void) { 157 extern "C" { 158 attr! { 159 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")] 160 fn __drop(this: *mut c_void); 161 } 162 } 163 unsafe { __drop(this) } 164 } 165 } 166 }; 167 } 168 169 macro_rules! impl_weak_ptr_target_for_primitive { 170 ($ty:ident) => { 171 impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty); 172 }; 173 } 174 175 impl_weak_ptr_target_for_primitive!(bool); 176 impl_weak_ptr_target_for_primitive!(u8); 177 impl_weak_ptr_target_for_primitive!(u16); 178 impl_weak_ptr_target_for_primitive!(u32); 179 impl_weak_ptr_target_for_primitive!(u64); 180 impl_weak_ptr_target_for_primitive!(usize); 181 impl_weak_ptr_target_for_primitive!(i8); 182 impl_weak_ptr_target_for_primitive!(i16); 183 impl_weak_ptr_target_for_primitive!(i32); 184 impl_weak_ptr_target_for_primitive!(i64); 185 impl_weak_ptr_target_for_primitive!(isize); 186 impl_weak_ptr_target_for_primitive!(f32); 187 impl_weak_ptr_target_for_primitive!(f64); 188 189 impl_weak_ptr_target!("string", "CxxString", CxxString); 190