blob: b3a1b1ccadc0b4e992235520c84ea3923096eed2 [file] [log] [blame]
David Tolnayb3b24a12020-12-01 15:27:43 -08001use crate::kind::Trivial;
David Tolnaybac25822020-12-12 23:13:51 -08002use crate::string::CxxString;
David Tolnay85b6bc42020-12-28 17:47:51 -08003use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
David Tolnayb3b24a12020-12-01 15:27:43 -08004use crate::ExternType;
5use core::ffi::c_void;
6use core::fmt::{self, Debug, Display};
7use core::marker::PhantomData;
8use core::mem::MaybeUninit;
David Tolnay9df2aac2020-12-10 20:06:56 -08009use core::ops::Deref;
David Tolnayb3b24a12020-12-01 15:27:43 -080010
David Tolnay40f4b562020-12-28 15:04:54 -080011/// Binding to C++ `std::shared_ptr<T>`.
David Tolnayb3b24a12020-12-01 15:27:43 -080012#[repr(C)]
13pub struct SharedPtr<T>
14where
15 T: SharedPtrTarget,
16{
17 repr: [*mut c_void; 2],
18 ty: PhantomData<T>,
19}
20
21impl<T> SharedPtr<T>
22where
23 T: SharedPtrTarget,
24{
25 /// Makes a new SharedPtr wrapping a null pointer.
26 ///
27 /// Matches the behavior of default-constructing a std::shared\_ptr.
28 pub fn null() -> Self {
29 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
30 let new = shared_ptr.as_mut_ptr().cast();
31 unsafe {
32 T::__null(new);
33 shared_ptr.assume_init()
34 }
35 }
36
37 /// Allocates memory on the heap and makes a SharedPtr owner for it.
38 pub fn new(value: T) -> Self
39 where
40 T: ExternType<Kind = Trivial>,
41 {
42 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
43 let new = shared_ptr.as_mut_ptr().cast();
44 unsafe {
45 T::__new(value, new);
46 shared_ptr.assume_init()
47 }
48 }
49
Vitaly Shukelacbad4f32021-01-15 09:25:41 +030050 /// Checks whether the SharedPtr does not own an object.
David Tolnayb3b24a12020-12-01 15:27:43 -080051 ///
52 /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
53 pub fn is_null(&self) -> bool {
54 let this = self as *const Self as *const c_void;
55 let ptr = unsafe { T::__get(this) };
56 ptr.is_null()
57 }
58
59 /// Returns a reference to the object owned by this SharedPtr if any,
60 /// otherwise None.
61 pub fn as_ref(&self) -> Option<&T> {
62 let this = self as *const Self as *const c_void;
63 unsafe { T::__get(this).as_ref() }
64 }
David Tolnay85b6bc42020-12-28 17:47:51 -080065
66 /// Constructs new WeakPtr as a non-owning reference to the object managed
67 /// by `self`. If `self` manages no object, the WeakPtr manages no object
68 /// too.
69 ///
70 /// 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).
71 pub fn downgrade(self: &SharedPtr<T>) -> WeakPtr<T>
72 where
73 T: WeakPtrTarget,
74 {
75 let this = self as *const Self as *const c_void;
76 let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
77 let new = weak_ptr.as_mut_ptr().cast();
78 unsafe {
79 T::__downgrade(this, new);
80 weak_ptr.assume_init()
81 }
82 }
David Tolnayb3b24a12020-12-01 15:27:43 -080083}
84
85unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
86unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
87
88impl<T> Clone for SharedPtr<T>
89where
90 T: SharedPtrTarget,
91{
92 fn clone(&self) -> Self {
93 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
94 let new = shared_ptr.as_mut_ptr().cast();
95 let this = self as *const Self as *mut c_void;
96 unsafe {
97 T::__clone(this, new);
98 shared_ptr.assume_init()
99 }
100 }
101}
102
103impl<T> Drop for SharedPtr<T>
104where
105 T: SharedPtrTarget,
106{
107 fn drop(&mut self) {
108 let this = self as *mut Self as *mut c_void;
109 unsafe { T::__drop(this) }
110 }
111}
112
113impl<T> Deref for SharedPtr<T>
114where
115 T: SharedPtrTarget,
116{
117 type Target = T;
118
119 fn deref(&self) -> &Self::Target {
120 match self.as_ref() {
121 Some(target) => target,
122 None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
123 }
124 }
125}
126
David Tolnayb3b24a12020-12-01 15:27:43 -0800127impl<T> Debug for SharedPtr<T>
128where
129 T: Debug + SharedPtrTarget,
130{
131 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
132 match self.as_ref() {
133 None => formatter.write_str("nullptr"),
134 Some(value) => Debug::fmt(value, formatter),
135 }
136 }
137}
138
139impl<T> Display for SharedPtr<T>
140where
141 T: Display + SharedPtrTarget,
142{
143 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
144 match self.as_ref() {
145 None => formatter.write_str("nullptr"),
146 Some(value) => Display::fmt(value, formatter),
147 }
148 }
149}
150
151// Methods are private; not intended to be implemented outside of cxxbridge
152// codebase.
153pub unsafe trait SharedPtrTarget {
154 #[doc(hidden)]
155 const __NAME: &'static dyn Display;
156 #[doc(hidden)]
157 unsafe fn __null(new: *mut c_void);
158 #[doc(hidden)]
159 unsafe fn __new(value: Self, new: *mut c_void)
160 where
161 Self: Sized,
162 {
163 // Opoaque C types do not get this method because they can never exist
164 // by value on the Rust side of the bridge.
165 let _ = value;
166 let _ = new;
167 unreachable!()
168 }
169 #[doc(hidden)]
170 unsafe fn __clone(this: *const c_void, new: *mut c_void);
171 #[doc(hidden)]
172 unsafe fn __get(this: *const c_void) -> *const Self;
173 #[doc(hidden)]
174 unsafe fn __drop(this: *mut c_void);
175}
David Tolnay5b163402020-12-10 19:26:02 -0800176
177macro_rules! impl_shared_ptr_target {
178 ($segment:expr, $name:expr, $ty:ty) => {
179 unsafe impl SharedPtrTarget for $ty {
180 const __NAME: &'static dyn Display = &$name;
181 unsafe fn __null(new: *mut c_void) {
182 extern "C" {
183 attr! {
184 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
185 fn __null(new: *mut c_void);
186 }
187 }
188 __null(new);
189 }
190 unsafe fn __new(value: Self, new: *mut c_void) {
191 extern "C" {
192 attr! {
193 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
194 fn __uninit(new: *mut c_void) -> *mut c_void;
195 }
196 }
197 __uninit(new).cast::<$ty>().write(value);
198 }
199 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
200 extern "C" {
201 attr! {
202 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
203 fn __clone(this: *const c_void, new: *mut c_void);
204 }
205 }
206 __clone(this, new);
207 }
208 unsafe fn __get(this: *const c_void) -> *const Self {
209 extern "C" {
210 attr! {
211 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
212 fn __get(this: *const c_void) -> *const c_void;
213 }
214 }
215 __get(this).cast()
216 }
217 unsafe fn __drop(this: *mut c_void) {
218 extern "C" {
219 attr! {
220 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
221 fn __drop(this: *mut c_void);
222 }
223 }
224 __drop(this);
225 }
226 }
227 };
228}
229
230macro_rules! impl_shared_ptr_target_for_primitive {
231 ($ty:ident) => {
232 impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
233 };
234}
235
David Tolnaycd1430c2020-12-28 17:17:14 -0800236impl_shared_ptr_target_for_primitive!(bool);
David Tolnay5b163402020-12-10 19:26:02 -0800237impl_shared_ptr_target_for_primitive!(u8);
238impl_shared_ptr_target_for_primitive!(u16);
239impl_shared_ptr_target_for_primitive!(u32);
240impl_shared_ptr_target_for_primitive!(u64);
241impl_shared_ptr_target_for_primitive!(usize);
242impl_shared_ptr_target_for_primitive!(i8);
243impl_shared_ptr_target_for_primitive!(i16);
244impl_shared_ptr_target_for_primitive!(i32);
245impl_shared_ptr_target_for_primitive!(i64);
246impl_shared_ptr_target_for_primitive!(isize);
247impl_shared_ptr_target_for_primitive!(f32);
248impl_shared_ptr_target_for_primitive!(f64);
249
250impl_shared_ptr_target!("string", "CxxString", CxxString);