blob: 63ad7d31b367b1c8aa062a4dcdb804d559343d3b [file] [log] [blame]
David Tolnay5b163402020-12-10 19:26:02 -08001use crate::cxx_string::CxxString;
David Tolnayb3b24a12020-12-01 15:27:43 -08002use crate::kind::Trivial;
3use crate::ExternType;
4use core::ffi::c_void;
5use core::fmt::{self, Debug, Display};
6use core::marker::PhantomData;
7use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::pin::Pin;
10
11/// BInding to C++ `std::shared_ptr<T>`.
12#[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
50 /// Chacks whether the SharedPtr does not own an object.
51 ///
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 }
65
66 /// Returns a mutable pinned reference to the object owned by this SharedPtr
67 /// if any, otherwise None.
68 pub fn as_mut(&mut self) -> Option<Pin<&mut T>> {
69 let this = self as *mut Self as *mut c_void;
70 unsafe {
71 let mut_reference = (T::__get(this) as *mut T).as_mut()?;
72 Some(Pin::new_unchecked(mut_reference))
73 }
74 }
75
76 /// Returns a mutable pinned reference to the object owned by this
77 /// SharedPtr.
78 ///
79 /// # Panics
80 ///
81 /// Panics if the SharedPtr holds a null pointer.
82 pub fn pin_mut(&mut self) -> Pin<&mut T> {
83 match self.as_mut() {
84 Some(target) => target,
85 None => panic!("called pin_mut on a null SharedPtr<{}>", T::__NAME),
86 }
87 }
88}
89
90unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
91unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
92
93impl<T> Clone for SharedPtr<T>
94where
95 T: SharedPtrTarget,
96{
97 fn clone(&self) -> Self {
98 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
99 let new = shared_ptr.as_mut_ptr().cast();
100 let this = self as *const Self as *mut c_void;
101 unsafe {
102 T::__clone(this, new);
103 shared_ptr.assume_init()
104 }
105 }
106}
107
108impl<T> Drop for SharedPtr<T>
109where
110 T: SharedPtrTarget,
111{
112 fn drop(&mut self) {
113 let this = self as *mut Self as *mut c_void;
114 unsafe { T::__drop(this) }
115 }
116}
117
118impl<T> Deref for SharedPtr<T>
119where
120 T: SharedPtrTarget,
121{
122 type Target = T;
123
124 fn deref(&self) -> &Self::Target {
125 match self.as_ref() {
126 Some(target) => target,
127 None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
128 }
129 }
130}
131
132impl<T> DerefMut for SharedPtr<T>
133where
134 T: SharedPtrTarget + Unpin,
135{
136 fn deref_mut(&mut self) -> &mut Self::Target {
137 match self.as_mut() {
138 Some(target) => Pin::into_inner(target),
139 None => panic!("called deref_mut on a null SharedPtr<{}>", T::__NAME),
140 }
141 }
142}
143
144impl<T> Debug for SharedPtr<T>
145where
146 T: Debug + SharedPtrTarget,
147{
148 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
149 match self.as_ref() {
150 None => formatter.write_str("nullptr"),
151 Some(value) => Debug::fmt(value, formatter),
152 }
153 }
154}
155
156impl<T> Display for SharedPtr<T>
157where
158 T: Display + SharedPtrTarget,
159{
160 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
161 match self.as_ref() {
162 None => formatter.write_str("nullptr"),
163 Some(value) => Display::fmt(value, formatter),
164 }
165 }
166}
167
168// Methods are private; not intended to be implemented outside of cxxbridge
169// codebase.
170pub unsafe trait SharedPtrTarget {
171 #[doc(hidden)]
172 const __NAME: &'static dyn Display;
173 #[doc(hidden)]
174 unsafe fn __null(new: *mut c_void);
175 #[doc(hidden)]
176 unsafe fn __new(value: Self, new: *mut c_void)
177 where
178 Self: Sized,
179 {
180 // Opoaque C types do not get this method because they can never exist
181 // by value on the Rust side of the bridge.
182 let _ = value;
183 let _ = new;
184 unreachable!()
185 }
186 #[doc(hidden)]
187 unsafe fn __clone(this: *const c_void, new: *mut c_void);
188 #[doc(hidden)]
189 unsafe fn __get(this: *const c_void) -> *const Self;
190 #[doc(hidden)]
191 unsafe fn __drop(this: *mut c_void);
192}
David Tolnay5b163402020-12-10 19:26:02 -0800193
194macro_rules! impl_shared_ptr_target {
195 ($segment:expr, $name:expr, $ty:ty) => {
196 unsafe impl SharedPtrTarget for $ty {
197 const __NAME: &'static dyn Display = &$name;
198 unsafe fn __null(new: *mut c_void) {
199 extern "C" {
200 attr! {
201 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
202 fn __null(new: *mut c_void);
203 }
204 }
205 __null(new);
206 }
207 unsafe fn __new(value: Self, new: *mut c_void) {
208 extern "C" {
209 attr! {
210 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
211 fn __uninit(new: *mut c_void) -> *mut c_void;
212 }
213 }
214 __uninit(new).cast::<$ty>().write(value);
215 }
216 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
217 extern "C" {
218 attr! {
219 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
220 fn __clone(this: *const c_void, new: *mut c_void);
221 }
222 }
223 __clone(this, new);
224 }
225 unsafe fn __get(this: *const c_void) -> *const Self {
226 extern "C" {
227 attr! {
228 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
229 fn __get(this: *const c_void) -> *const c_void;
230 }
231 }
232 __get(this).cast()
233 }
234 unsafe fn __drop(this: *mut c_void) {
235 extern "C" {
236 attr! {
237 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
238 fn __drop(this: *mut c_void);
239 }
240 }
241 __drop(this);
242 }
243 }
244 };
245}
246
247macro_rules! impl_shared_ptr_target_for_primitive {
248 ($ty:ident) => {
249 impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
250 };
251}
252
253impl_shared_ptr_target_for_primitive!(u8);
254impl_shared_ptr_target_for_primitive!(u16);
255impl_shared_ptr_target_for_primitive!(u32);
256impl_shared_ptr_target_for_primitive!(u64);
257impl_shared_ptr_target_for_primitive!(usize);
258impl_shared_ptr_target_for_primitive!(i8);
259impl_shared_ptr_target_for_primitive!(i16);
260impl_shared_ptr_target_for_primitive!(i32);
261impl_shared_ptr_target_for_primitive!(i64);
262impl_shared_ptr_target_for_primitive!(isize);
263impl_shared_ptr_target_for_primitive!(f32);
264impl_shared_ptr_target_for_primitive!(f64);
265
266impl_shared_ptr_target!("string", "CxxString", CxxString);