blob: 3875a7828e171aacdd7978877e4094bdcbb6dff2 [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;
4use core::fmt::Display;
5use 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
85// Methods are private; not intended to be implemented outside of cxxbridge
86// codebase.
87pub unsafe trait WeakPtrTarget {
88 #[doc(hidden)]
89 const __NAME: &'static dyn Display;
90 #[doc(hidden)]
91 unsafe fn __null(new: *mut c_void);
92 #[doc(hidden)]
93 unsafe fn __clone(this: *const c_void, new: *mut c_void);
94 #[doc(hidden)]
David Tolnay85b6bc42020-12-28 17:47:51 -080095 unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
96 #[doc(hidden)]
David Tolnay7a487852020-12-28 18:02:25 -080097 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void);
98 #[doc(hidden)]
David Tolnay215e77f2020-12-28 17:09:48 -080099 unsafe fn __drop(this: *mut c_void);
100}
101
102macro_rules! impl_weak_ptr_target {
103 ($segment:expr, $name:expr, $ty:ty) => {
104 unsafe impl WeakPtrTarget for $ty {
105 const __NAME: &'static dyn Display = &$name;
106 unsafe fn __null(new: *mut c_void) {
107 extern "C" {
108 attr! {
109 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")]
110 fn __null(new: *mut c_void);
111 }
112 }
113 __null(new);
114 }
115 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
116 extern "C" {
117 attr! {
118 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")]
119 fn __clone(this: *const c_void, new: *mut c_void);
120 }
121 }
122 __clone(this, new);
123 }
David Tolnay85b6bc42020-12-28 17:47:51 -0800124 unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
125 extern "C" {
126 attr! {
127 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")]
128 fn __downgrade(shared: *const c_void, weak: *mut c_void);
129 }
130 }
131 __downgrade(shared, weak);
132 }
David Tolnay7a487852020-12-28 18:02:25 -0800133 unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) {
134 extern "C" {
135 attr! {
136 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")]
137 fn __upgrade(weak: *const c_void, shared: *mut c_void);
138 }
139 }
140 __upgrade(weak, shared);
141 }
David Tolnay215e77f2020-12-28 17:09:48 -0800142 unsafe fn __drop(this: *mut c_void) {
143 extern "C" {
144 attr! {
145 #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")]
146 fn __drop(this: *mut c_void);
147 }
148 }
149 __drop(this);
150 }
151 }
152 };
153}
154
155macro_rules! impl_weak_ptr_target_for_primitive {
156 ($ty:ident) => {
157 impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
158 };
159}
160
161impl_weak_ptr_target_for_primitive!(bool);
162impl_weak_ptr_target_for_primitive!(u8);
163impl_weak_ptr_target_for_primitive!(u16);
164impl_weak_ptr_target_for_primitive!(u32);
165impl_weak_ptr_target_for_primitive!(u64);
166impl_weak_ptr_target_for_primitive!(usize);
167impl_weak_ptr_target_for_primitive!(i8);
168impl_weak_ptr_target_for_primitive!(i16);
169impl_weak_ptr_target_for_primitive!(i32);
170impl_weak_ptr_target_for_primitive!(i64);
171impl_weak_ptr_target_for_primitive!(isize);
172impl_weak_ptr_target_for_primitive!(f32);
173impl_weak_ptr_target_for_primitive!(f64);
174
175impl_weak_ptr_target!("string", "CxxString", CxxString);