• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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