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;
7use core::ptr;
8
9/// Binding to C++ `std::weak_ptr<T>`.
10///
11/// The typical way to construct a WeakPtr from Rust is by [downgrading] from a
12/// SharedPtr.
13///
14/// [downgrading]: crate::SharedPtr::downgrade
15#[repr(C)]
16pub struct WeakPtr<T>
17where
18    T: WeakPtrTarget,
19{
20    repr: [MaybeUninit<*mut c_void>; 2],
21    ty: PhantomData<T>,
22}
23
24impl<T> WeakPtr<T>
25where
26    T: WeakPtrTarget,
27{
28    /// Makes a new WeakPtr wrapping a null pointer.
29    ///
30    /// Matches the behavior of default-constructing a std::weak\_ptr.
31    pub fn null() -> Self {
32        let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
33        let new = weak_ptr.as_mut_ptr().cast();
34        unsafe {
35            T::__null(new);
36            weak_ptr.assume_init()
37        }
38    }
39
40    /// Upgrades a non-owning reference into an owning reference if possible,
41    /// otherwise to a null reference.
42    ///
43    /// Matches the behavior of [std::weak_ptr\<T\>::lock](https://en.cppreference.com/w/cpp/memory/weak_ptr/lock).
44    pub fn upgrade(&self) -> SharedPtr<T>
45    where
46        T: SharedPtrTarget,
47    {
48        let this = ptr::from_ref::<Self>(self).cast::<c_void>();
49        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
50        let new = shared_ptr.as_mut_ptr().cast();
51        unsafe {
52            T::__upgrade(this, new);
53            shared_ptr.assume_init()
54        }
55    }
56}
57
58unsafe impl<T> Send for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
59unsafe impl<T> Sync for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
60
61impl<T> Clone for WeakPtr<T>
62where
63    T: WeakPtrTarget,
64{
65    fn clone(&self) -> Self {
66        let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
67        let new = weak_ptr.as_mut_ptr().cast();
68        let this = ptr::from_ref::<Self>(self).cast::<c_void>();
69        unsafe {
70            T::__clone(this, new);
71            weak_ptr.assume_init()
72        }
73    }
74}
75
76impl<T> Drop for WeakPtr<T>
77where
78    T: WeakPtrTarget,
79{
80    fn drop(&mut self) {
81        let this = ptr::from_mut::<Self>(self).cast::<c_void>();
82        unsafe { T::__drop(this) }
83    }
84}
85
86impl<T> Debug for WeakPtr<T>
87where
88    T: Debug + WeakPtrTarget + SharedPtrTarget,
89{
90    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
91        Debug::fmt(&self.upgrade(), formatter)
92    }
93}
94
95/// Trait bound for types which may be used as the `T` inside of a `WeakPtr<T>`
96/// in generic code.
97///
98/// This trait has no publicly callable or implementable methods. Implementing
99/// it outside of the CXX codebase is not supported.
100pub unsafe trait WeakPtrTarget {
101    #[doc(hidden)]
102    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
103    #[doc(hidden)]
104    unsafe fn __null(new: *mut c_void);
105    #[doc(hidden)]
106    unsafe fn __clone(this: *const c_void, new: *mut c_void);
107    #[doc(hidden)]
108    unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
109    #[doc(hidden)]
110    unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void);
111    #[doc(hidden)]
112    unsafe fn __drop(this: *mut c_void);
113}
114
115macro_rules! impl_weak_ptr_target {
116    ($segment:expr, $name:expr, $ty:ty) => {
117        unsafe impl WeakPtrTarget for $ty {
118            fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
119                f.write_str($name)
120            }
121            unsafe fn __null(new: *mut c_void) {
122                extern "C" {
123                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")]
124                    fn __null(new: *mut c_void);
125                }
126                unsafe { __null(new) }
127            }
128            unsafe fn __clone(this: *const c_void, new: *mut c_void) {
129                extern "C" {
130                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")]
131                    fn __clone(this: *const c_void, new: *mut c_void);
132                }
133                unsafe { __clone(this, new) }
134            }
135            unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
136                extern "C" {
137                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")]
138                    fn __downgrade(shared: *const c_void, weak: *mut c_void);
139                }
140                unsafe { __downgrade(shared, weak) }
141            }
142            unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) {
143                extern "C" {
144                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")]
145                    fn __upgrade(weak: *const c_void, shared: *mut c_void);
146                }
147                unsafe { __upgrade(weak, shared) }
148            }
149            unsafe fn __drop(this: *mut c_void) {
150                extern "C" {
151                    #[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")]
152                    fn __drop(this: *mut c_void);
153                }
154                unsafe { __drop(this) }
155            }
156        }
157    };
158}
159
160macro_rules! impl_weak_ptr_target_for_primitive {
161    ($ty:ident) => {
162        impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
163    };
164}
165
166impl_weak_ptr_target_for_primitive!(bool);
167impl_weak_ptr_target_for_primitive!(u8);
168impl_weak_ptr_target_for_primitive!(u16);
169impl_weak_ptr_target_for_primitive!(u32);
170impl_weak_ptr_target_for_primitive!(u64);
171impl_weak_ptr_target_for_primitive!(usize);
172impl_weak_ptr_target_for_primitive!(i8);
173impl_weak_ptr_target_for_primitive!(i16);
174impl_weak_ptr_target_for_primitive!(i32);
175impl_weak_ptr_target_for_primitive!(i64);
176impl_weak_ptr_target_for_primitive!(isize);
177impl_weak_ptr_target_for_primitive!(f32);
178impl_weak_ptr_target_for_primitive!(f64);
179
180impl_weak_ptr_target!("string", "CxxString", CxxString);