blob: 2c06d36aa244d5ad4297f802724f8645f6be65fd [file] [log] [blame]
David Tolnay7a487852020-12-28 18:02:25 -08001use crate::shared_ptr::{SharedPtr, SharedPtrTarget};
David Tolnay215e77f2020-12-28 17:09:48 -08002use crate::string::CxxString;
3use core::ffi::c_void;
David Tolnayac5af502021-03-25 00:29:06 -04004use core::fmt::{self, Debug};
David Tolnay215e77f2020-12-28 17:09:48 -08005use core::marker::PhantomData;
6use core::mem::MaybeUninit;
7
8/// Binding to C++ `std::weak_ptr<T>`.
David Tolnay85b6bc42020-12-28 17:47:51 -08009///
10/// The typical way to construct a WeakPtr from Rust is by [downgrading] from a
11/// SharedPtr.
12///
13/// [downgrading]: crate::SharedPtr::downgrade
David Tolnay215e77f2020-12-28 17:09:48 -080014#[repr(C)]
15pub struct WeakPtr<T>
16where
17 T: WeakPtrTarget,
18{
David Tolnay46cff542021-05-02 10:59:57 -070019 repr: [MaybeUninit<*mut c_void>; 2],
David Tolnay215e77f2020-12-28 17:09:48 -080020 ty: PhantomData<T>,
21}
22
23impl<T> WeakPtr<T>
24where
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.
30 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 }
David Tolnay7a487852020-12-28 18:02:25 -080038
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).
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 }
David Tolnay215e77f2020-12-28 17:09:48 -080055}
56
57unsafe impl<T> Send for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
58unsafe impl<T> Sync for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
59
60impl<T> Clone for WeakPtr<T>
61where
62 T: WeakPtrTarget,
63{
64 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
75impl<T> Drop for WeakPtr<T>
76where
77 T: WeakPtrTarget,
78{
79 fn drop(&mut self) {
80 let this = self as *mut Self as *mut c_void;
81 unsafe { T::__drop(this) }
82 }
83}
84
David Tolnay18ed79b2020-12-28 18:21:46 -080085impl<T> Debug for WeakPtr<T>
86where
87 T: Debug + WeakPtrTarget + SharedPtrTarget,
88{
89 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
90 Debug::fmt(&self.upgrade(), formatter)
91 }
92}
93
David Tolnayd0019c62021-04-16 16:12:22 -070094/// 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.
David Tolnay215e77f2020-12-28 17:09:48 -080099pub unsafe trait WeakPtrTarget {
100 #[doc(hidden)]
David Tolnayac5af502021-03-25 00:29:06 -0400101 fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
David Tolnay215e77f2020-12-28 17:09:48 -0800102 #[doc(hidden)]
103 unsafe fn __null(new: *mut c_void);
104 #[doc(hidden)]
105 unsafe fn __clone(this: *const c_void, new: *mut c_void);
106 #[doc(hidden)]
David Tolnay85b6bc42020-12-28 17:47:51 -0800107 unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
108 #[doc(hidden)]
David Tolnay7a487852020-12-28 18:02:25 -0800109 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void);
110 #[doc(hidden)]
David Tolnay215e77f2020-12-28 17:09:48 -0800111 unsafe fn __drop(this: *mut c_void);
112}
113
114macro_rules! impl_weak_ptr_target {
115 ($segment:expr, $name:expr, $ty:ty) => {
116 unsafe impl WeakPtrTarget for $ty {
David Tolnayb99359b2021-03-25 02:05:20 -0400117 #[doc(hidden)]
David Tolnayac5af502021-03-25 00:29:06 -0400118 fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
119 f.write_str($name)
120 }
David Tolnayb99359b2021-03-25 02:05:20 -0400121 #[doc(hidden)]
David Tolnay215e77f2020-12-28 17:09:48 -0800122 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 __null(new);
130 }
David Tolnayb99359b2021-03-25 02:05:20 -0400131 #[doc(hidden)]
David Tolnay215e77f2020-12-28 17:09:48 -0800132 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 __clone(this, new);
140 }
David Tolnayb99359b2021-03-25 02:05:20 -0400141 #[doc(hidden)]
David Tolnay85b6bc42020-12-28 17:47:51 -0800142 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 __downgrade(shared, weak);
150 }
David Tolnayb99359b2021-03-25 02:05:20 -0400151 #[doc(hidden)]
David Tolnay7a487852020-12-28 18:02:25 -0800152 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 __upgrade(weak, shared);
160 }
David Tolnayb99359b2021-03-25 02:05:20 -0400161 #[doc(hidden)]
David Tolnay215e77f2020-12-28 17:09:48 -0800162 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 __drop(this);
170 }
171 }
172 };
173}
174
175macro_rules! impl_weak_ptr_target_for_primitive {
176 ($ty:ident) => {
177 impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
178 };
179}
180
181impl_weak_ptr_target_for_primitive!(bool);
182impl_weak_ptr_target_for_primitive!(u8);
183impl_weak_ptr_target_for_primitive!(u16);
184impl_weak_ptr_target_for_primitive!(u32);
185impl_weak_ptr_target_for_primitive!(u64);
186impl_weak_ptr_target_for_primitive!(usize);
187impl_weak_ptr_target_for_primitive!(i8);
188impl_weak_ptr_target_for_primitive!(i16);
189impl_weak_ptr_target_for_primitive!(i32);
190impl_weak_ptr_target_for_primitive!(i64);
191impl_weak_ptr_target_for_primitive!(isize);
192impl_weak_ptr_target_for_primitive!(f32);
193impl_weak_ptr_target_for_primitive!(f64);
194
195impl_weak_ptr_target!("string", "CxxString", CxxString);