cxx/
weak_ptr.rs

1use crate::shared_ptr::{SharedPtr, SharedPtrTarget};
2use crate::string::CxxString;
3use core::ffi::c_void;
4use core::fmt::{self, Debug};
5use core::marker::PhantomData;
6use 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)]
15pub struct WeakPtr<T>
16where
17    T: WeakPtrTarget,
18{
19    repr: [MaybeUninit<*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    }
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).
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
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
85impl<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
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.
99pub unsafe trait WeakPtrTarget {
100    #[doc(hidden)]
101    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
102    #[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)]
107    unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
108    #[doc(hidden)]
109    unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void);
110    #[doc(hidden)]
111    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 {
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                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")]
123                    fn __null(new: *mut c_void);
124                }
125                unsafe { __null(new) }
126            }
127            unsafe fn __clone(this: *const c_void, new: *mut c_void) {
128                extern "C" {
129                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")]
130                    fn __clone(this: *const c_void, new: *mut c_void);
131                }
132                unsafe { __clone(this, new) }
133            }
134            unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
135                extern "C" {
136                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")]
137                    fn __downgrade(shared: *const c_void, weak: *mut c_void);
138                }
139                unsafe { __downgrade(shared, weak) }
140            }
141            unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) {
142                extern "C" {
143                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")]
144                    fn __upgrade(weak: *const c_void, shared: *mut c_void);
145                }
146                unsafe { __upgrade(weak, shared) }
147            }
148            unsafe fn __drop(this: *mut c_void) {
149                extern "C" {
150                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")]
151                    fn __drop(this: *mut c_void);
152                }
153                unsafe { __drop(this) }
154            }
155        }
156    };
157}
158
159macro_rules! impl_weak_ptr_target_for_primitive {
160    ($ty:ident) => {
161        impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
162    };
163}
164
165impl_weak_ptr_target_for_primitive!(bool);
166impl_weak_ptr_target_for_primitive!(u8);
167impl_weak_ptr_target_for_primitive!(u16);
168impl_weak_ptr_target_for_primitive!(u32);
169impl_weak_ptr_target_for_primitive!(u64);
170impl_weak_ptr_target_for_primitive!(usize);
171impl_weak_ptr_target_for_primitive!(i8);
172impl_weak_ptr_target_for_primitive!(i16);
173impl_weak_ptr_target_for_primitive!(i32);
174impl_weak_ptr_target_for_primitive!(i64);
175impl_weak_ptr_target_for_primitive!(isize);
176impl_weak_ptr_target_for_primitive!(f32);
177impl_weak_ptr_target_for_primitive!(f64);
178
179impl_weak_ptr_target!("string", "CxxString", CxxString);