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