cxx/
shared_ptr.rs

1use crate::extern_type::ExternType;
2use crate::fmt::display;
3use crate::kind::Trivial;
4use crate::string::CxxString;
5use crate::unique_ptr::{UniquePtr, UniquePtrTarget};
6use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
7use core::cmp::Ordering;
8use core::ffi::c_void;
9use core::fmt::{self, Debug, Display};
10use core::hash::{Hash, Hasher};
11use core::marker::PhantomData;
12use core::mem::MaybeUninit;
13use core::ops::Deref;
14use core::pin::Pin;
15use core::ptr;
16
17/// Binding to C++ `std::shared_ptr<T>`.
18///
19/// <div class="warning">
20///
21/// **WARNING:** Unlike Rust's `Arc<T>`, a C++ shared pointer manipulates
22/// pointers to 2 separate objects in general.
23///
24/// 1. One is the **managed** pointer, and its identity is associated with
25///    shared ownership of a strong and weak count shared by other SharedPtr and
26///    WeakPtr instances having the same managed pointer.
27///
28/// 2. The other is the **stored** pointer, which is commonly either the same as
29///    the managed pointer, or is a pointer into some member of the managed
30///    object, but can be any unrelated pointer in general.
31///
32/// The managed pointer is the one passed to a deleter upon the strong count
33/// reaching zero, but the stored pointer is the one accessed by deref
34/// operations and methods such as `is_null`.
35///
36/// A shared pointer is considered **empty** if the strong count is zero,
37/// meaning the managed pointer has been deleted or is about to be deleted. A
38/// shared pointer is considered **null** if the stored pointer is the null
39/// pointer. All combinations are possible. To be explicit, a shared pointer can
40/// be nonempty and nonnull, or nonempty and null, or empty and nonnull, or
41/// empty and null. In general all of these cases need to be considered when
42/// handling a SharedPtr.
43///
44/// </div>
45#[repr(C)]
46pub struct SharedPtr<T>
47where
48    T: SharedPtrTarget,
49{
50    repr: [MaybeUninit<*mut c_void>; 2],
51    ty: PhantomData<T>,
52}
53
54impl<T> SharedPtr<T>
55where
56    T: SharedPtrTarget,
57{
58    /// Makes a new SharedPtr that is both **empty** and **null**.
59    ///
60    /// Matches the behavior of default-constructing a std::shared\_ptr.
61    pub fn null() -> Self {
62        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
63        let new = shared_ptr.as_mut_ptr().cast();
64        unsafe {
65            T::__null(new);
66            shared_ptr.assume_init()
67        }
68    }
69
70    /// Allocates memory on the heap and makes a SharedPtr owner for it.
71    ///
72    /// The shared pointer will be **nonempty** and **nonnull**.
73    pub fn new(value: T) -> Self
74    where
75        T: ExternType<Kind = Trivial>,
76    {
77        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
78        let new = shared_ptr.as_mut_ptr().cast();
79        unsafe {
80            T::__new(value, new);
81            shared_ptr.assume_init()
82        }
83    }
84
85    /// Creates a shared pointer from a C++ heap-allocated pointer.
86    ///
87    /// Matches the behavior of std::shared\_ptr's constructor `explicit shared_ptr(T*)`.
88    ///
89    /// The SharedPtr gains ownership of the pointer and will call
90    /// `std::default_delete` on it when the refcount goes to zero.
91    ///
92    /// The object pointed to by the input pointer is not relocated by this
93    /// operation, so any pointers into this data structure elsewhere in the
94    /// program continue to be valid.
95    ///
96    /// The resulting shared pointer is **nonempty** regardless of whether the
97    /// input pointer is null, but may be either **null** or **nonnull**.
98    ///
99    /// # Panics
100    ///
101    /// Panics if `T` is an incomplete type (including `void`) or is not
102    /// destructible.
103    ///
104    /// # Safety
105    ///
106    /// Pointer must either be null or point to a valid instance of T
107    /// heap-allocated in C++ by `new`.
108    #[track_caller]
109    pub unsafe fn from_raw(raw: *mut T) -> Self {
110        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
111        let new = shared_ptr.as_mut_ptr().cast();
112        unsafe {
113            T::__raw(new, raw);
114            shared_ptr.assume_init()
115        }
116    }
117
118    /// Checks whether the SharedPtr holds a null stored pointer.
119    ///
120    /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
121    ///
122    /// <div class="warning">
123    ///
124    /// This method is unrelated to the state of the reference count. It is
125    /// possible to have a SharedPtr that is nonnull but empty (has a refcount
126    /// of 0), typically from having been constructed using the alias
127    /// constructors in C++. Inversely, it is also possible to be null and
128    /// nonempty.
129    ///
130    /// </div>
131    pub fn is_null(&self) -> bool {
132        let this = ptr::from_ref::<Self>(self).cast::<c_void>();
133        let ptr = unsafe { T::__get(this) };
134        ptr.is_null()
135    }
136
137    /// Returns a reference to the object pointed to by the stored pointer if
138    /// nonnull, otherwise None.
139    ///
140    /// <div class="warning">
141    ///
142    /// The shared pointer's managed object may or may not already have been
143    /// destroyed.
144    ///
145    /// </div>
146    pub fn as_ref(&self) -> Option<&T> {
147        let ptr = self.as_ptr();
148        unsafe { ptr.as_ref() }
149    }
150
151    /// Returns a mutable pinned reference to the object pointed to by the
152    /// stored pointer.
153    ///
154    /// <div class="warning">
155    ///
156    /// The shared pointer's managed object may or may not already have been
157    /// destroyed.
158    ///
159    /// </div>
160    ///
161    /// # Panics
162    ///
163    /// Panics if the SharedPtr holds a null stored pointer.
164    ///
165    /// # Safety
166    ///
167    /// This method makes no attempt to ascertain the state of the reference
168    /// count. In particular, unlike `Arc::get_mut`, we do not enforce absence
169    /// of other SharedPtr and WeakPtr referring to the same data as this one.
170    /// As always, it is Undefined Behavior to have simultaneous references to
171    /// the same value while a Rust exclusive reference to it exists anywhere in
172    /// the program.
173    ///
174    /// For the special case of CXX [opaque C++ types], this method can be used
175    /// to safely call thread-safe non-const member functions on a C++ object
176    /// without regard for whether the reference is exclusive. This capability
177    /// applies only to opaque types `extern "C++" { type T; }`. It does not
178    /// apply to extern types defined with a non-opaque Rust representation
179    /// `extern "C++" { type T = ...; }`.
180    ///
181    /// [opaque C++ types]: https://cxx.rs/extern-c++.html#opaque-c-types
182    pub unsafe fn pin_mut_unchecked(&mut self) -> Pin<&mut T> {
183        let ptr = self.as_mut_ptr();
184        match unsafe { ptr.as_mut() } {
185            Some(target) => unsafe { Pin::new_unchecked(target) },
186            None => panic!(
187                "called pin_mut_unchecked on a null SharedPtr<{}>",
188                display(T::__typename),
189            ),
190        }
191    }
192
193    /// Returns the SharedPtr's stored pointer as a raw const pointer.
194    pub fn as_ptr(&self) -> *const T {
195        let this = ptr::from_ref::<Self>(self).cast::<c_void>();
196        unsafe { T::__get(this) }
197    }
198
199    /// Returns the SharedPtr's stored pointer as a raw mutable pointer.
200    ///
201    /// As with [std::shared_ptr\<T\>::get](https://en.cppreference.com/w/cpp/memory/shared_ptr/get),
202    /// this doesn't require that you hold an exclusive reference to the
203    /// SharedPtr. This differs from Rust norms, so extra care should be taken
204    /// in the way the pointer is used.
205    pub fn as_mut_ptr(&self) -> *mut T {
206        self.as_ptr().cast_mut()
207    }
208
209    /// Constructs new WeakPtr as a non-owning reference to the object managed
210    /// by `self`. If `self` manages no object, the WeakPtr manages no object
211    /// too.
212    ///
213    /// Matches the behavior of [std::weak_ptr\<T\>::weak_ptr(const std::shared_ptr\<T\> \&)](https://en.cppreference.com/w/cpp/memory/weak_ptr/weak_ptr).
214    pub fn downgrade(&self) -> WeakPtr<T>
215    where
216        T: WeakPtrTarget,
217    {
218        let this = ptr::from_ref::<Self>(self).cast::<c_void>();
219        let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
220        let new = weak_ptr.as_mut_ptr().cast();
221        unsafe {
222            T::__downgrade(this, new);
223            weak_ptr.assume_init()
224        }
225    }
226}
227
228unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
229unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
230
231impl<T> Clone for SharedPtr<T>
232where
233    T: SharedPtrTarget,
234{
235    fn clone(&self) -> Self {
236        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
237        let new = shared_ptr.as_mut_ptr().cast();
238        let this = ptr::from_ref::<Self>(self).cast::<c_void>();
239        unsafe {
240            T::__clone(this, new);
241            shared_ptr.assume_init()
242        }
243    }
244}
245
246// SharedPtr is not a self-referential type and is safe to move out of a Pin,
247// regardless whether the pointer's target is Unpin.
248impl<T> Unpin for SharedPtr<T> where T: SharedPtrTarget {}
249
250impl<T> Drop for SharedPtr<T>
251where
252    T: SharedPtrTarget,
253{
254    fn drop(&mut self) {
255        let this = ptr::from_mut::<Self>(self).cast::<c_void>();
256        unsafe { T::__drop(this) }
257    }
258}
259
260impl<T> Deref for SharedPtr<T>
261where
262    T: SharedPtrTarget,
263{
264    type Target = T;
265
266    fn deref(&self) -> &Self::Target {
267        match self.as_ref() {
268            Some(target) => target,
269            None => panic!(
270                "called deref on a null SharedPtr<{}>",
271                display(T::__typename),
272            ),
273        }
274    }
275}
276
277impl<T> Debug for SharedPtr<T>
278where
279    T: Debug + SharedPtrTarget,
280{
281    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
282        match self.as_ref() {
283            None => formatter.write_str("nullptr"),
284            Some(value) => Debug::fmt(value, formatter),
285        }
286    }
287}
288
289impl<T> Display for SharedPtr<T>
290where
291    T: Display + SharedPtrTarget,
292{
293    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
294        match self.as_ref() {
295            None => formatter.write_str("nullptr"),
296            Some(value) => Display::fmt(value, formatter),
297        }
298    }
299}
300
301impl<T> PartialEq for SharedPtr<T>
302where
303    T: PartialEq + SharedPtrTarget,
304{
305    fn eq(&self, other: &Self) -> bool {
306        self.as_ref() == other.as_ref()
307    }
308}
309
310impl<T> Eq for SharedPtr<T> where T: Eq + SharedPtrTarget {}
311
312impl<T> PartialOrd for SharedPtr<T>
313where
314    T: PartialOrd + SharedPtrTarget,
315{
316    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
317        PartialOrd::partial_cmp(&self.as_ref(), &other.as_ref())
318    }
319}
320
321impl<T> Ord for SharedPtr<T>
322where
323    T: Ord + SharedPtrTarget,
324{
325    fn cmp(&self, other: &Self) -> Ordering {
326        Ord::cmp(&self.as_ref(), &other.as_ref())
327    }
328}
329
330impl<T> Hash for SharedPtr<T>
331where
332    T: Hash + SharedPtrTarget,
333{
334    fn hash<H>(&self, hasher: &mut H)
335    where
336        H: Hasher,
337    {
338        self.as_ref().hash(hasher);
339    }
340}
341
342impl<T> From<UniquePtr<T>> for SharedPtr<T>
343where
344    T: UniquePtrTarget + SharedPtrTarget,
345{
346    fn from(unique: UniquePtr<T>) -> Self {
347        unsafe { SharedPtr::from_raw(UniquePtr::into_raw(unique)) }
348    }
349}
350
351/// Trait bound for types which may be used as the `T` inside of a
352/// `SharedPtr<T>` in generic code.
353///
354/// This trait has no publicly callable or implementable methods. Implementing
355/// it outside of the CXX codebase is not supported.
356///
357/// # Example
358///
359/// A bound `T: SharedPtrTarget` may be necessary when manipulating
360/// [`SharedPtr`] in generic code.
361///
362/// ```
363/// use cxx::memory::{SharedPtr, SharedPtrTarget};
364/// use std::fmt::Display;
365///
366/// pub fn take_generic_ptr<T>(ptr: SharedPtr<T>)
367/// where
368///     T: SharedPtrTarget + Display,
369/// {
370///     println!("the shared_ptr points to: {}", *ptr);
371/// }
372/// ```
373///
374/// Writing the same generic function without a `SharedPtrTarget` trait bound
375/// would not compile.
376pub unsafe trait SharedPtrTarget {
377    #[doc(hidden)]
378    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
379    #[doc(hidden)]
380    unsafe fn __null(new: *mut c_void);
381    #[doc(hidden)]
382    unsafe fn __new(value: Self, new: *mut c_void)
383    where
384        Self: Sized,
385    {
386        // Opaque C types do not get this method because they can never exist by
387        // value on the Rust side of the bridge.
388        let _ = value;
389        let _ = new;
390        unreachable!()
391    }
392    #[doc(hidden)]
393    unsafe fn __raw(new: *mut c_void, raw: *mut Self);
394    #[doc(hidden)]
395    unsafe fn __clone(this: *const c_void, new: *mut c_void);
396    #[doc(hidden)]
397    unsafe fn __get(this: *const c_void) -> *const Self;
398    #[doc(hidden)]
399    unsafe fn __drop(this: *mut c_void);
400}
401
402macro_rules! impl_shared_ptr_target {
403    ($segment:expr, $name:expr, $ty:ty) => {
404        unsafe impl SharedPtrTarget for $ty {
405            fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
406                f.write_str($name)
407            }
408            unsafe fn __null(new: *mut c_void) {
409                extern "C" {
410                    #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
411                    fn __null(new: *mut c_void);
412                }
413                unsafe { __null(new) }
414            }
415            unsafe fn __new(value: Self, new: *mut c_void) {
416                extern "C" {
417                    #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
418                    fn __uninit(new: *mut c_void) -> *mut c_void;
419                }
420                unsafe { __uninit(new).cast::<$ty>().write(value) }
421            }
422            unsafe fn __raw(new: *mut c_void, raw: *mut Self) {
423                extern "C" {
424                    #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$raw")]
425                    fn __raw(new: *mut c_void, raw: *mut c_void);
426                }
427                unsafe { __raw(new, raw.cast::<c_void>()) }
428            }
429            unsafe fn __clone(this: *const c_void, new: *mut c_void) {
430                extern "C" {
431                    #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
432                    fn __clone(this: *const c_void, new: *mut c_void);
433                }
434                unsafe { __clone(this, new) }
435            }
436            unsafe fn __get(this: *const c_void) -> *const Self {
437                extern "C" {
438                    #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
439                    fn __get(this: *const c_void) -> *const c_void;
440                }
441                unsafe { __get(this) }.cast()
442            }
443            unsafe fn __drop(this: *mut c_void) {
444                extern "C" {
445                    #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
446                    fn __drop(this: *mut c_void);
447                }
448                unsafe { __drop(this) }
449            }
450        }
451    };
452}
453
454macro_rules! impl_shared_ptr_target_for_primitive {
455    ($ty:ident) => {
456        impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
457    };
458}
459
460impl_shared_ptr_target_for_primitive!(bool);
461impl_shared_ptr_target_for_primitive!(u8);
462impl_shared_ptr_target_for_primitive!(u16);
463impl_shared_ptr_target_for_primitive!(u32);
464impl_shared_ptr_target_for_primitive!(u64);
465impl_shared_ptr_target_for_primitive!(usize);
466impl_shared_ptr_target_for_primitive!(i8);
467impl_shared_ptr_target_for_primitive!(i16);
468impl_shared_ptr_target_for_primitive!(i32);
469impl_shared_ptr_target_for_primitive!(i64);
470impl_shared_ptr_target_for_primitive!(isize);
471impl_shared_ptr_target_for_primitive!(f32);
472impl_shared_ptr_target_for_primitive!(f64);
473
474impl_shared_ptr_target!("string", "CxxString", CxxString);