blob: 317773d424f22241ac35d53b908cf026326b4274 [file] [log] [blame]
David Tolnayac5af502021-03-25 00:29:06 -04001use crate::fmt::display;
David Tolnayb3b24a12020-12-01 15:27:43 -08002use crate::kind::Trivial;
David Tolnaybac25822020-12-12 23:13:51 -08003use crate::string::CxxString;
David Tolnay85b6bc42020-12-28 17:47:51 -08004use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
David Tolnayb3b24a12020-12-01 15:27:43 -08005use crate::ExternType;
6use core::ffi::c_void;
7use core::fmt::{self, Debug, Display};
8use core::marker::PhantomData;
9use core::mem::MaybeUninit;
David Tolnay9df2aac2020-12-10 20:06:56 -080010use core::ops::Deref;
David Tolnayb3b24a12020-12-01 15:27:43 -080011
David Tolnay40f4b562020-12-28 15:04:54 -080012/// Binding to C++ `std::shared_ptr<T>`.
David Tolnayb3b24a12020-12-01 15:27:43 -080013#[repr(C)]
14pub struct SharedPtr<T>
15where
16 T: SharedPtrTarget,
17{
David Tolnay46cff542021-05-02 10:59:57 -070018 repr: [MaybeUninit<*mut c_void>; 2],
David Tolnayb3b24a12020-12-01 15:27:43 -080019 ty: PhantomData<T>,
20}
21
22impl<T> SharedPtr<T>
23where
24 T: SharedPtrTarget,
25{
26 /// Makes a new SharedPtr wrapping a null pointer.
27 ///
28 /// Matches the behavior of default-constructing a std::shared\_ptr.
29 pub fn null() -> Self {
30 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
31 let new = shared_ptr.as_mut_ptr().cast();
32 unsafe {
33 T::__null(new);
34 shared_ptr.assume_init()
35 }
36 }
37
38 /// Allocates memory on the heap and makes a SharedPtr owner for it.
39 pub fn new(value: T) -> Self
40 where
41 T: ExternType<Kind = Trivial>,
42 {
43 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
44 let new = shared_ptr.as_mut_ptr().cast();
45 unsafe {
46 T::__new(value, new);
47 shared_ptr.assume_init()
48 }
49 }
50
Vitaly Shukelacbad4f32021-01-15 09:25:41 +030051 /// Checks whether the SharedPtr does not own an object.
David Tolnayb3b24a12020-12-01 15:27:43 -080052 ///
53 /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
54 pub fn is_null(&self) -> bool {
55 let this = self as *const Self as *const c_void;
56 let ptr = unsafe { T::__get(this) };
57 ptr.is_null()
58 }
59
60 /// Returns a reference to the object owned by this SharedPtr if any,
61 /// otherwise None.
62 pub fn as_ref(&self) -> Option<&T> {
63 let this = self as *const Self as *const c_void;
64 unsafe { T::__get(this).as_ref() }
65 }
David Tolnay85b6bc42020-12-28 17:47:51 -080066
67 /// Constructs new WeakPtr as a non-owning reference to the object managed
68 /// by `self`. If `self` manages no object, the WeakPtr manages no object
69 /// too.
70 ///
71 /// 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).
72 pub fn downgrade(self: &SharedPtr<T>) -> WeakPtr<T>
73 where
74 T: WeakPtrTarget,
75 {
76 let this = self as *const Self as *const c_void;
77 let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
78 let new = weak_ptr.as_mut_ptr().cast();
79 unsafe {
80 T::__downgrade(this, new);
81 weak_ptr.assume_init()
82 }
83 }
David Tolnayb3b24a12020-12-01 15:27:43 -080084}
85
86unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
87unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
88
89impl<T> Clone for SharedPtr<T>
90where
91 T: SharedPtrTarget,
92{
93 fn clone(&self) -> Self {
94 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
95 let new = shared_ptr.as_mut_ptr().cast();
96 let this = self as *const Self as *mut c_void;
97 unsafe {
98 T::__clone(this, new);
99 shared_ptr.assume_init()
100 }
101 }
102}
103
104impl<T> Drop for SharedPtr<T>
105where
106 T: SharedPtrTarget,
107{
108 fn drop(&mut self) {
109 let this = self as *mut Self as *mut c_void;
110 unsafe { T::__drop(this) }
111 }
112}
113
114impl<T> Deref for SharedPtr<T>
115where
116 T: SharedPtrTarget,
117{
118 type Target = T;
119
120 fn deref(&self) -> &Self::Target {
121 match self.as_ref() {
122 Some(target) => target,
David Tolnayac5af502021-03-25 00:29:06 -0400123 None => panic!(
124 "called deref on a null SharedPtr<{}>",
125 display(T::__typename),
126 ),
David Tolnayb3b24a12020-12-01 15:27:43 -0800127 }
128 }
129}
130
David Tolnayb3b24a12020-12-01 15:27:43 -0800131impl<T> Debug for SharedPtr<T>
132where
133 T: Debug + SharedPtrTarget,
134{
135 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
136 match self.as_ref() {
137 None => formatter.write_str("nullptr"),
138 Some(value) => Debug::fmt(value, formatter),
139 }
140 }
141}
142
143impl<T> Display for SharedPtr<T>
144where
145 T: Display + SharedPtrTarget,
146{
147 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
148 match self.as_ref() {
149 None => formatter.write_str("nullptr"),
150 Some(value) => Display::fmt(value, formatter),
151 }
152 }
153}
154
David Tolnay9291d522021-03-25 02:04:44 -0400155/// Trait bound for types which may be used as the `T` inside of a
156/// `SharedPtr<T>` in generic code.
157///
158/// This trait has no publicly callable or implementable methods. Implementing
159/// it outside of the CXX codebase is not supported.
160///
161/// # Example
162///
163/// A bound `T: SharedPtrTarget` may be necessary when manipulating
164/// [`SharedPtr`] in generic code.
165///
166/// ```
167/// use cxx::memory::{SharedPtr, SharedPtrTarget};
168/// use std::fmt::Display;
169///
170/// pub fn take_generic_ptr<T>(ptr: SharedPtr<T>)
171/// where
172/// T: SharedPtrTarget + Display,
173/// {
174/// println!("the shared_ptr points to: {}", *ptr);
175/// }
176/// ```
177///
178/// Writing the same generic function without a `SharedPtrTarget` trait bound
179/// would not compile.
David Tolnayb3b24a12020-12-01 15:27:43 -0800180pub unsafe trait SharedPtrTarget {
181 #[doc(hidden)]
David Tolnayac5af502021-03-25 00:29:06 -0400182 fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
David Tolnayb3b24a12020-12-01 15:27:43 -0800183 #[doc(hidden)]
184 unsafe fn __null(new: *mut c_void);
185 #[doc(hidden)]
186 unsafe fn __new(value: Self, new: *mut c_void)
187 where
188 Self: Sized,
189 {
190 // Opoaque C types do not get this method because they can never exist
191 // by value on the Rust side of the bridge.
192 let _ = value;
193 let _ = new;
194 unreachable!()
195 }
196 #[doc(hidden)]
197 unsafe fn __clone(this: *const c_void, new: *mut c_void);
198 #[doc(hidden)]
199 unsafe fn __get(this: *const c_void) -> *const Self;
200 #[doc(hidden)]
201 unsafe fn __drop(this: *mut c_void);
202}
David Tolnay5b163402020-12-10 19:26:02 -0800203
204macro_rules! impl_shared_ptr_target {
205 ($segment:expr, $name:expr, $ty:ty) => {
206 unsafe impl SharedPtrTarget for $ty {
David Tolnayb99359b2021-03-25 02:05:20 -0400207 #[doc(hidden)]
David Tolnayac5af502021-03-25 00:29:06 -0400208 fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
209 f.write_str($name)
210 }
David Tolnayb99359b2021-03-25 02:05:20 -0400211 #[doc(hidden)]
David Tolnay5b163402020-12-10 19:26:02 -0800212 unsafe fn __null(new: *mut c_void) {
213 extern "C" {
214 attr! {
215 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
216 fn __null(new: *mut c_void);
217 }
218 }
David Tolnay0b4b73f2021-08-27 12:12:53 -0700219 unsafe { __null(new) }
David Tolnay5b163402020-12-10 19:26:02 -0800220 }
David Tolnayb99359b2021-03-25 02:05:20 -0400221 #[doc(hidden)]
David Tolnay5b163402020-12-10 19:26:02 -0800222 unsafe fn __new(value: Self, new: *mut c_void) {
223 extern "C" {
224 attr! {
225 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
226 fn __uninit(new: *mut c_void) -> *mut c_void;
227 }
228 }
David Tolnay0b4b73f2021-08-27 12:12:53 -0700229 unsafe { __uninit(new).cast::<$ty>().write(value) }
David Tolnay5b163402020-12-10 19:26:02 -0800230 }
David Tolnayb99359b2021-03-25 02:05:20 -0400231 #[doc(hidden)]
David Tolnay5b163402020-12-10 19:26:02 -0800232 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
233 extern "C" {
234 attr! {
235 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
236 fn __clone(this: *const c_void, new: *mut c_void);
237 }
238 }
David Tolnay0b4b73f2021-08-27 12:12:53 -0700239 unsafe { __clone(this, new) }
David Tolnay5b163402020-12-10 19:26:02 -0800240 }
David Tolnayb99359b2021-03-25 02:05:20 -0400241 #[doc(hidden)]
David Tolnay5b163402020-12-10 19:26:02 -0800242 unsafe fn __get(this: *const c_void) -> *const Self {
243 extern "C" {
244 attr! {
245 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
246 fn __get(this: *const c_void) -> *const c_void;
247 }
248 }
David Tolnay0b4b73f2021-08-27 12:12:53 -0700249 unsafe { __get(this) }.cast()
David Tolnay5b163402020-12-10 19:26:02 -0800250 }
David Tolnayb99359b2021-03-25 02:05:20 -0400251 #[doc(hidden)]
David Tolnay5b163402020-12-10 19:26:02 -0800252 unsafe fn __drop(this: *mut c_void) {
253 extern "C" {
254 attr! {
255 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
256 fn __drop(this: *mut c_void);
257 }
258 }
David Tolnay0b4b73f2021-08-27 12:12:53 -0700259 unsafe { __drop(this) }
David Tolnay5b163402020-12-10 19:26:02 -0800260 }
261 }
262 };
263}
264
265macro_rules! impl_shared_ptr_target_for_primitive {
266 ($ty:ident) => {
267 impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
268 };
269}
270
David Tolnaycd1430c2020-12-28 17:17:14 -0800271impl_shared_ptr_target_for_primitive!(bool);
David Tolnay5b163402020-12-10 19:26:02 -0800272impl_shared_ptr_target_for_primitive!(u8);
273impl_shared_ptr_target_for_primitive!(u16);
274impl_shared_ptr_target_for_primitive!(u32);
275impl_shared_ptr_target_for_primitive!(u64);
276impl_shared_ptr_target_for_primitive!(usize);
277impl_shared_ptr_target_for_primitive!(i8);
278impl_shared_ptr_target_for_primitive!(i16);
279impl_shared_ptr_target_for_primitive!(i32);
280impl_shared_ptr_target_for_primitive!(i64);
281impl_shared_ptr_target_for_primitive!(isize);
282impl_shared_ptr_target_for_primitive!(f32);
283impl_shared_ptr_target_for_primitive!(f64);
284
285impl_shared_ptr_target!("string", "CxxString", CxxString);