1use crate::fmt::display;
2use crate::kind::Trivial;
3use crate::string::CxxString;
4use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
5use crate::ExternType;
6use core::cmp::Ordering;
7use core::ffi::c_void;
8use core::fmt::{self, Debug, Display};
9use core::hash::{Hash, Hasher};
10use core::marker::PhantomData;
11use core::mem::MaybeUninit;
12use core::ops::Deref;
13
14#[repr(C)]
16pub struct SharedPtr<T>
17where
18 T: SharedPtrTarget,
19{
20 repr: [MaybeUninit<*mut c_void>; 2],
21 ty: PhantomData<T>,
22}
23
24impl<T> SharedPtr<T>
25where
26 T: SharedPtrTarget,
27{
28 pub fn null() -> Self {
32 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
33 let new = shared_ptr.as_mut_ptr().cast();
34 unsafe {
35 T::__null(new);
36 shared_ptr.assume_init()
37 }
38 }
39
40 pub fn new(value: T) -> Self
42 where
43 T: ExternType<Kind = Trivial>,
44 {
45 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
46 let new = shared_ptr.as_mut_ptr().cast();
47 unsafe {
48 T::__new(value, new);
49 shared_ptr.assume_init()
50 }
51 }
52
53 pub fn is_null(&self) -> bool {
57 let this = self as *const Self as *const c_void;
58 let ptr = unsafe { T::__get(this) };
59 ptr.is_null()
60 }
61
62 pub fn as_ref(&self) -> Option<&T> {
65 let this = self as *const Self as *const c_void;
66 unsafe { T::__get(this).as_ref() }
67 }
68
69 pub fn downgrade(self: &SharedPtr<T>) -> WeakPtr<T>
75 where
76 T: WeakPtrTarget,
77 {
78 let this = self as *const Self as *const c_void;
79 let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
80 let new = weak_ptr.as_mut_ptr().cast();
81 unsafe {
82 T::__downgrade(this, new);
83 weak_ptr.assume_init()
84 }
85 }
86}
87
88unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
89unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
90
91impl<T> Clone for SharedPtr<T>
92where
93 T: SharedPtrTarget,
94{
95 fn clone(&self) -> Self {
96 let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
97 let new = shared_ptr.as_mut_ptr().cast();
98 let this = self as *const Self as *mut c_void;
99 unsafe {
100 T::__clone(this, new);
101 shared_ptr.assume_init()
102 }
103 }
104}
105
106impl<T> Unpin for SharedPtr<T> where T: SharedPtrTarget {}
109
110impl<T> Drop for SharedPtr<T>
111where
112 T: SharedPtrTarget,
113{
114 fn drop(&mut self) {
115 let this = self as *mut Self as *mut c_void;
116 unsafe { T::__drop(this) }
117 }
118}
119
120impl<T> Deref for SharedPtr<T>
121where
122 T: SharedPtrTarget,
123{
124 type Target = T;
125
126 fn deref(&self) -> &Self::Target {
127 match self.as_ref() {
128 Some(target) => target,
129 None => panic!(
130 "called deref on a null SharedPtr<{}>",
131 display(T::__typename),
132 ),
133 }
134 }
135}
136
137impl<T> Debug for SharedPtr<T>
138where
139 T: Debug + SharedPtrTarget,
140{
141 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
142 match self.as_ref() {
143 None => formatter.write_str("nullptr"),
144 Some(value) => Debug::fmt(value, formatter),
145 }
146 }
147}
148
149impl<T> Display for SharedPtr<T>
150where
151 T: Display + SharedPtrTarget,
152{
153 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
154 match self.as_ref() {
155 None => formatter.write_str("nullptr"),
156 Some(value) => Display::fmt(value, formatter),
157 }
158 }
159}
160
161impl<T> PartialEq for SharedPtr<T>
162where
163 T: PartialEq + SharedPtrTarget,
164{
165 fn eq(&self, other: &Self) -> bool {
166 self.as_ref() == other.as_ref()
167 }
168}
169
170impl<T> Eq for SharedPtr<T> where T: Eq + SharedPtrTarget {}
171
172impl<T> PartialOrd for SharedPtr<T>
173where
174 T: PartialOrd + SharedPtrTarget,
175{
176 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
177 PartialOrd::partial_cmp(&self.as_ref(), &other.as_ref())
178 }
179}
180
181impl<T> Ord for SharedPtr<T>
182where
183 T: Ord + SharedPtrTarget,
184{
185 fn cmp(&self, other: &Self) -> Ordering {
186 Ord::cmp(&self.as_ref(), &other.as_ref())
187 }
188}
189
190impl<T> Hash for SharedPtr<T>
191where
192 T: Hash + SharedPtrTarget,
193{
194 fn hash<H>(&self, hasher: &mut H)
195 where
196 H: Hasher,
197 {
198 self.as_ref().hash(hasher);
199 }
200}
201
202pub unsafe trait SharedPtrTarget {
228 #[doc(hidden)]
229 fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
230 #[doc(hidden)]
231 unsafe fn __null(new: *mut c_void);
232 #[doc(hidden)]
233 unsafe fn __new(value: Self, new: *mut c_void)
234 where
235 Self: Sized,
236 {
237 let _ = value;
240 let _ = new;
241 unreachable!()
242 }
243 #[doc(hidden)]
244 unsafe fn __clone(this: *const c_void, new: *mut c_void);
245 #[doc(hidden)]
246 unsafe fn __get(this: *const c_void) -> *const Self;
247 #[doc(hidden)]
248 unsafe fn __drop(this: *mut c_void);
249}
250
251macro_rules! impl_shared_ptr_target {
252 ($segment:expr, $name:expr, $ty:ty) => {
253 unsafe impl SharedPtrTarget for $ty {
254 fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
255 f.write_str($name)
256 }
257 unsafe fn __null(new: *mut c_void) {
258 extern "C" {
259 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
260 fn __null(new: *mut c_void);
261 }
262 unsafe { __null(new) }
263 }
264 unsafe fn __new(value: Self, new: *mut c_void) {
265 extern "C" {
266 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
267 fn __uninit(new: *mut c_void) -> *mut c_void;
268 }
269 unsafe { __uninit(new).cast::<$ty>().write(value) }
270 }
271 unsafe fn __clone(this: *const c_void, new: *mut c_void) {
272 extern "C" {
273 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
274 fn __clone(this: *const c_void, new: *mut c_void);
275 }
276 unsafe { __clone(this, new) }
277 }
278 unsafe fn __get(this: *const c_void) -> *const Self {
279 extern "C" {
280 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
281 fn __get(this: *const c_void) -> *const c_void;
282 }
283 unsafe { __get(this) }.cast()
284 }
285 unsafe fn __drop(this: *mut c_void) {
286 extern "C" {
287 #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
288 fn __drop(this: *mut c_void);
289 }
290 unsafe { __drop(this) }
291 }
292 }
293 };
294}
295
296macro_rules! impl_shared_ptr_target_for_primitive {
297 ($ty:ident) => {
298 impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
299 };
300}
301
302impl_shared_ptr_target_for_primitive!(bool);
303impl_shared_ptr_target_for_primitive!(u8);
304impl_shared_ptr_target_for_primitive!(u16);
305impl_shared_ptr_target_for_primitive!(u32);
306impl_shared_ptr_target_for_primitive!(u64);
307impl_shared_ptr_target_for_primitive!(usize);
308impl_shared_ptr_target_for_primitive!(i8);
309impl_shared_ptr_target_for_primitive!(i16);
310impl_shared_ptr_target_for_primitive!(i32);
311impl_shared_ptr_target_for_primitive!(i64);
312impl_shared_ptr_target_for_primitive!(isize);
313impl_shared_ptr_target_for_primitive!(f32);
314impl_shared_ptr_target_for_primitive!(f64);
315
316impl_shared_ptr_target!("string", "CxxString", CxxString);