blob: ba744618460aedf66ed64ed18e1f75d8c442a3e2 [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{
19 repr: [*mut c_void; 2],
20 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 Tolnay215e77f2020-12-28 17:09:48 -080094// Methods are private; not intended to be implemented outside of cxxbridge
95// codebase.
96pub unsafe trait WeakPtrTarget {
97 #[doc(hidden)]
David Tolnayac5af502021-03-25 00:29:06 -040098 fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
David Tolnay215e77f2020-12-28 17:09:48 -080099 #[doc(hidden)]
100 unsafe fn __null(new: *mut c_void);
101 #[doc(hidden)]
102 unsafe fn __clone(this: *const c_void, new: *mut c_void);
103 #[doc(hidden)]
David Tolnay85b6bc42020-12-28 17:47:51 -0800104 unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
105 #[doc(hidden)]
David Tolnay7a487852020-12-28 18:02:25 -0800106 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void);
107 #[doc(hidden)]
David Tolnay215e77f2020-12-28 17:09:48 -0800108 unsafe fn __drop(this: *mut c_void);
109}
110
111macro_rules! impl_weak_ptr_target {
112 ($segment:expr, $name:expr, $ty:ty) => {
113 unsafe impl WeakPtrTarget for $ty {
David Tolnayac5af502021-03-25 00:29:06 -0400114 fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
115 f.write_str($name)
116 }
David Tolnay215e77f2020-12-28 17:09:48 -0800117 unsafe fn __null(new: *mut c_void) {
118 extern "C" {
119 attr! {
120 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")]
121 fn __null(new: *mut c_void);
122 }
123 }
124 __null(new);
125 }
126 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
127 extern "C" {
128 attr! {
129 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")]
130 fn __clone(this: *const c_void, new: *mut c_void);
131 }
132 }
133 __clone(this, new);
134 }
David Tolnay85b6bc42020-12-28 17:47:51 -0800135 unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
136 extern "C" {
137 attr! {
138 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")]
139 fn __downgrade(shared: *const c_void, weak: *mut c_void);
140 }
141 }
142 __downgrade(shared, weak);
143 }
David Tolnay7a487852020-12-28 18:02:25 -0800144 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) {
145 extern "C" {
146 attr! {
147 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")]
148 fn __upgrade(weak: *const c_void, shared: *mut c_void);
149 }
150 }
151 __upgrade(weak, shared);
152 }
David Tolnay215e77f2020-12-28 17:09:48 -0800153 unsafe fn __drop(this: *mut c_void) {
154 extern "C" {
155 attr! {
156 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")]
157 fn __drop(this: *mut c_void);
158 }
159 }
160 __drop(this);
161 }
162 }
163 };
164}
165
166macro_rules! impl_weak_ptr_target_for_primitive {
167 ($ty:ident) => {
168 impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
169 };
170}
171
172impl_weak_ptr_target_for_primitive!(bool);
173impl_weak_ptr_target_for_primitive!(u8);
174impl_weak_ptr_target_for_primitive!(u16);
175impl_weak_ptr_target_for_primitive!(u32);
176impl_weak_ptr_target_for_primitive!(u64);
177impl_weak_ptr_target_for_primitive!(usize);
178impl_weak_ptr_target_for_primitive!(i8);
179impl_weak_ptr_target_for_primitive!(i16);
180impl_weak_ptr_target_for_primitive!(i32);
181impl_weak_ptr_target_for_primitive!(i64);
182impl_weak_ptr_target_for_primitive!(isize);
183impl_weak_ptr_target_for_primitive!(f32);
184impl_weak_ptr_target_for_primitive!(f64);
185
186impl_weak_ptr_target!("string", "CxxString", CxxString);