blob: 58930352fae9ca7a0799e6ddb05bf646c216730c [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{
18 repr: [*mut c_void; 2],
19 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
155// Methods are private; not intended to be implemented outside of cxxbridge
156// codebase.
157pub unsafe trait SharedPtrTarget {
158 #[doc(hidden)]
David Tolnayac5af502021-03-25 00:29:06 -0400159 fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
David Tolnayb3b24a12020-12-01 15:27:43 -0800160 #[doc(hidden)]
161 unsafe fn __null(new: *mut c_void);
162 #[doc(hidden)]
163 unsafe fn __new(value: Self, new: *mut c_void)
164 where
165 Self: Sized,
166 {
167 // Opoaque C types do not get this method because they can never exist
168 // by value on the Rust side of the bridge.
169 let _ = value;
170 let _ = new;
171 unreachable!()
172 }
173 #[doc(hidden)]
174 unsafe fn __clone(this: *const c_void, new: *mut c_void);
175 #[doc(hidden)]
176 unsafe fn __get(this: *const c_void) -> *const Self;
177 #[doc(hidden)]
178 unsafe fn __drop(this: *mut c_void);
179}
David Tolnay5b163402020-12-10 19:26:02 -0800180
181macro_rules! impl_shared_ptr_target {
182 ($segment:expr, $name:expr, $ty:ty) => {
183 unsafe impl SharedPtrTarget for $ty {
David Tolnayac5af502021-03-25 00:29:06 -0400184 fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
185 f.write_str($name)
186 }
David Tolnay5b163402020-12-10 19:26:02 -0800187 unsafe fn __null(new: *mut c_void) {
188 extern "C" {
189 attr! {
190 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
191 fn __null(new: *mut c_void);
192 }
193 }
194 __null(new);
195 }
196 unsafe fn __new(value: Self, new: *mut c_void) {
197 extern "C" {
198 attr! {
199 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
200 fn __uninit(new: *mut c_void) -> *mut c_void;
201 }
202 }
203 __uninit(new).cast::<$ty>().write(value);
204 }
205 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
206 extern "C" {
207 attr! {
208 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
209 fn __clone(this: *const c_void, new: *mut c_void);
210 }
211 }
212 __clone(this, new);
213 }
214 unsafe fn __get(this: *const c_void) -> *const Self {
215 extern "C" {
216 attr! {
217 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
218 fn __get(this: *const c_void) -> *const c_void;
219 }
220 }
221 __get(this).cast()
222 }
223 unsafe fn __drop(this: *mut c_void) {
224 extern "C" {
225 attr! {
226 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
227 fn __drop(this: *mut c_void);
228 }
229 }
230 __drop(this);
231 }
232 }
233 };
234}
235
236macro_rules! impl_shared_ptr_target_for_primitive {
237 ($ty:ident) => {
238 impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
239 };
240}
241
David Tolnaycd1430c2020-12-28 17:17:14 -0800242impl_shared_ptr_target_for_primitive!(bool);
David Tolnay5b163402020-12-10 19:26:02 -0800243impl_shared_ptr_target_for_primitive!(u8);
244impl_shared_ptr_target_for_primitive!(u16);
245impl_shared_ptr_target_for_primitive!(u32);
246impl_shared_ptr_target_for_primitive!(u64);
247impl_shared_ptr_target_for_primitive!(usize);
248impl_shared_ptr_target_for_primitive!(i8);
249impl_shared_ptr_target_for_primitive!(i16);
250impl_shared_ptr_target_for_primitive!(i32);
251impl_shared_ptr_target_for_primitive!(i64);
252impl_shared_ptr_target_for_primitive!(isize);
253impl_shared_ptr_target_for_primitive!(f32);
254impl_shared_ptr_target_for_primitive!(f64);
255
256impl_shared_ptr_target!("string", "CxxString", CxxString);