1use core::alloc::Layout;
2
3use crate::{
4 ConstTypeId, Def, Facet, KnownSmartPointer, Opaque, PtrConst, PtrMut, PtrUninit, Shape,
5 SmartPointerDef, SmartPointerFlags, SmartPointerVTable, TryBorrowInnerError, TryFromInnerError,
6 TryIntoInnerError, value_vtable, value_vtable_inner,
7};
8
9unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::sync::Arc<T> {
10 const SHAPE: &'static crate::Shape = &const {
11 unsafe fn try_from_inner<'a, 'src, 'dst, T: Facet<'a>>(
13 src_ptr: PtrConst<'src>,
14 src_shape: &'static Shape,
15 dst: PtrUninit<'dst>,
16 ) -> Result<PtrMut<'dst>, TryFromInnerError> {
17 if src_shape.id != T::SHAPE.id {
18 return Err(TryFromInnerError::UnsupportedSourceShape {
19 src_shape,
20 expected: &[T::SHAPE],
21 });
22 }
23 let t = unsafe { src_ptr.read::<T>() };
24 let arc = alloc::sync::Arc::new(t);
25 Ok(unsafe { dst.put(arc) })
26 }
27
28 unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
29 src_ptr: PtrConst<'src>,
30 dst: PtrUninit<'dst>,
31 ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
32 let arc = unsafe { src_ptr.get::<alloc::sync::Arc<T>>() };
33 match alloc::sync::Arc::try_unwrap(arc.clone()) {
34 Ok(t) => Ok(unsafe { dst.put(t) }),
35 Err(_) => Err(TryIntoInnerError::Unavailable),
36 }
37 }
38
39 unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
40 src_ptr: PtrConst<'src>,
41 ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
42 let arc = unsafe { src_ptr.get::<alloc::sync::Arc<T>>() };
43 Ok(PtrConst::new(&**arc))
44 }
45
46 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
48 T::SHAPE
49 }
50
51 crate::Shape::builder()
52 .id(ConstTypeId::of::<Self>())
53 .layout(Layout::new::<Self>())
54 .type_params(&[crate::TypeParam {
55 name: "T",
56 shape: || T::SHAPE,
57 }])
58 .def(Def::SmartPointer(
59 SmartPointerDef::builder()
60 .pointee(T::SHAPE)
61 .flags(SmartPointerFlags::ATOMIC)
62 .known(KnownSmartPointer::Arc)
63 .weak(|| <alloc::sync::Weak<T> as Facet>::SHAPE)
64 .vtable(
65 &const {
66 SmartPointerVTable::builder()
67 .borrow_fn(|this| {
68 let ptr = Self::as_ptr(unsafe { this.get() });
69 PtrConst::new(ptr)
70 })
71 .new_into_fn(|this, ptr| {
72 let t = unsafe { ptr.read::<T>() };
73 let arc = alloc::sync::Arc::new(t);
74 unsafe { this.put(arc) }
75 })
76 .downgrade_into_fn(|strong, weak| unsafe {
77 weak.put(alloc::sync::Arc::downgrade(strong.get::<Self>()))
78 })
79 .build()
80 },
81 )
82 .build(),
83 ))
84 .vtable(
85 &const {
86 let mut vtable =
87 value_vtable_inner!(alloc::sync::Arc<T>, |f, _opts| write!(f, "Arc"));
88 vtable.try_from_inner = Some(try_from_inner::<T>);
89 vtable.try_into_inner = Some(try_into_inner::<T>);
90 vtable.try_borrow_inner = Some(try_borrow_inner::<T>);
91 vtable
92 },
93 )
94 .inner(inner_shape::<T>)
95 .build()
96 };
97}
98
99unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::sync::Weak<T> {
100 const SHAPE: &'static crate::Shape = &const {
101 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
103 T::SHAPE
104 }
105
106 crate::Shape::builder()
107 .id(ConstTypeId::of::<Self>())
108 .layout(Layout::new::<Self>())
109 .type_params(&[crate::TypeParam {
110 name: "T",
111 shape: || T::SHAPE,
112 }])
113 .def(Def::SmartPointer(
114 SmartPointerDef::builder()
115 .pointee(T::SHAPE)
116 .flags(SmartPointerFlags::ATOMIC.union(SmartPointerFlags::WEAK))
117 .known(KnownSmartPointer::ArcWeak)
118 .strong(|| <alloc::sync::Arc<T> as Facet>::SHAPE)
119 .vtable(
120 &const {
121 SmartPointerVTable::builder()
122 .upgrade_into_fn(|weak, strong| unsafe {
123 Some(strong.put(weak.get::<Self>().upgrade()?))
124 })
125 .build()
126 },
127 )
128 .build(),
129 ))
130 .vtable(
131 &const { value_vtable_inner!(alloc::sync::Arc<T>, |f, _opts| write!(f, "Arc")) },
132 )
133 .inner(inner_shape::<T>)
134 .build()
135 };
136}
137
138unsafe impl<'a, T: 'a> Facet<'a> for Opaque<alloc::sync::Arc<T>> {
139 const SHAPE: &'static crate::Shape = &const {
140 crate::Shape::builder()
141 .id(ConstTypeId::of::<Self>())
142 .layout(Layout::new::<Self>())
143 .def(Def::SmartPointer(
144 SmartPointerDef::builder()
145 .flags(SmartPointerFlags::ATOMIC)
146 .known(KnownSmartPointer::Arc)
147 .vtable(
148 &const {
149 SmartPointerVTable::builder()
150 .borrow_fn(|this| {
151 let ptr = alloc::sync::Arc::<T>::as_ptr(unsafe { this.get() });
152 PtrConst::new(ptr)
153 })
154 .new_into_fn(|this, ptr| {
155 let t = unsafe { ptr.read::<T>() };
156 let arc = alloc::sync::Arc::new(t);
157 unsafe { this.put(arc) }
158 })
159 .build()
160 },
161 )
162 .build(),
163 ))
164 .vtable(
165 &const { value_vtable_inner!(alloc::sync::Arc<T>, |f, _opts| write!(f, "Arc")) },
166 )
167 .build()
168 };
169}
170
171unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::rc::Rc<T> {
172 const SHAPE: &'static crate::Shape = &const {
173 unsafe fn try_from_inner<'a, 'src, 'dst, T: Facet<'a>>(
175 src_ptr: PtrConst<'src>,
176 src_shape: &'static Shape,
177 dst: PtrUninit<'dst>,
178 ) -> Result<PtrMut<'dst>, TryFromInnerError> {
179 if src_shape.id != T::SHAPE.id {
180 return Err(TryFromInnerError::UnsupportedSourceShape {
181 src_shape,
182 expected: &[T::SHAPE],
183 });
184 }
185 let t = unsafe { src_ptr.read::<T>() };
186 let rc = alloc::rc::Rc::new(t);
187 Ok(unsafe { dst.put(rc) })
188 }
189
190 unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
191 src_ptr: PtrConst<'src>,
192 dst: PtrUninit<'dst>,
193 ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
194 let rc = unsafe { src_ptr.get::<alloc::rc::Rc<T>>() };
195 match alloc::rc::Rc::try_unwrap(rc.clone()) {
196 Ok(t) => Ok(unsafe { dst.put(t) }),
197 Err(_) => Err(TryIntoInnerError::Unavailable),
198 }
199 }
200
201 unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
202 src_ptr: PtrConst<'src>,
203 ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
204 let rc = unsafe { src_ptr.get::<alloc::rc::Rc<T>>() };
205 Ok(PtrConst::new(&**rc))
206 }
207
208 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
210 T::SHAPE
211 }
212
213 crate::Shape::builder()
214 .id(ConstTypeId::of::<Self>())
215 .layout(Layout::new::<Self>())
216 .type_params(&[crate::TypeParam {
217 name: "T",
218 shape: || T::SHAPE,
219 }])
220 .def(Def::SmartPointer(
221 SmartPointerDef::builder()
222 .pointee(T::SHAPE)
223 .flags(SmartPointerFlags::EMPTY)
224 .known(KnownSmartPointer::Rc)
225 .weak(|| <alloc::rc::Weak<T> as Facet>::SHAPE)
226 .vtable(
227 &const {
228 SmartPointerVTable::builder()
229 .borrow_fn(|this| {
230 let ptr = Self::as_ptr(unsafe { this.get() });
231 PtrConst::new(ptr)
232 })
233 .new_into_fn(|this, ptr| {
234 let t = unsafe { ptr.read::<T>() };
235 let rc = alloc::rc::Rc::new(t);
236 unsafe { this.put(rc) }
237 })
238 .downgrade_into_fn(|strong, weak| unsafe {
239 weak.put(alloc::rc::Rc::downgrade(strong.get::<Self>()))
240 })
241 .build()
242 },
243 )
244 .build(),
245 ))
246 .vtable(
247 &const {
248 let mut vtable =
249 value_vtable_inner!(alloc::rc::Rc<T>, |f, _opts| write!(f, "Rc"));
250 vtable.try_from_inner = Some(try_from_inner::<T>);
251 vtable.try_into_inner = Some(try_into_inner::<T>);
252 vtable.try_borrow_inner = Some(try_borrow_inner::<T>);
253 vtable
254 },
255 )
256 .inner(inner_shape::<T>)
257 .build()
258 };
259}
260
261unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::rc::Weak<T> {
262 const SHAPE: &'static crate::Shape = &const {
263 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
265 T::SHAPE
266 }
267
268 crate::Shape::builder()
269 .id(ConstTypeId::of::<Self>())
270 .layout(Layout::new::<Self>())
271 .type_params(&[crate::TypeParam {
272 name: "T",
273 shape: || T::SHAPE,
274 }])
275 .def(Def::SmartPointer(
276 SmartPointerDef::builder()
277 .pointee(T::SHAPE)
278 .flags(SmartPointerFlags::WEAK)
279 .known(KnownSmartPointer::RcWeak)
280 .strong(|| <alloc::rc::Rc<T> as Facet>::SHAPE)
281 .vtable(
282 &const {
283 SmartPointerVTable::builder()
284 .upgrade_into_fn(|weak, strong| unsafe {
285 Some(strong.put(weak.get::<Self>().upgrade()?))
286 })
287 .build()
288 },
289 )
290 .build(),
291 ))
292 .vtable(&const { value_vtable_inner!(alloc::rc::Rc<T>, |f, _opts| write!(f, "Rc")) })
293 .inner(inner_shape::<T>)
294 .build()
295 };
296}
297
298unsafe impl<'a, T: 'a> Facet<'a> for Opaque<alloc::rc::Rc<T>> {
299 const SHAPE: &'static crate::Shape = &const {
300 crate::Shape::builder()
301 .id(ConstTypeId::of::<Self>())
302 .layout(Layout::new::<Self>())
303 .def(Def::SmartPointer(
304 SmartPointerDef::builder()
305 .known(KnownSmartPointer::Rc)
306 .vtable(
307 &const {
308 SmartPointerVTable::builder()
309 .borrow_fn(|this| {
310 let ptr = alloc::rc::Rc::<T>::as_ptr(unsafe { this.get() });
311 PtrConst::new(ptr)
312 })
313 .new_into_fn(|this, ptr| {
314 let t = unsafe { ptr.read::<T>() };
315 let rc = alloc::rc::Rc::new(t);
316 unsafe { this.put(rc) }
317 })
318 .build()
319 },
320 )
321 .build(),
322 ))
323 .vtable(value_vtable!(alloc::rc::Rc<T>, |f, _opts| write!(f, "Rc")))
324 .build()
325 };
326}
327
328#[cfg(test)]
329mod tests {
330 use alloc::rc::{Rc, Weak as RcWeak};
331 use alloc::string::String;
332 use alloc::sync::{Arc, Weak as ArcWeak};
333 use core::mem::MaybeUninit;
334
335 use super::*;
336
337 use crate::PtrUninit;
338
339 #[test]
340 fn test_arc_type_params() {
341 let [type_param_1] = <Arc<i32>>::SHAPE.type_params else {
342 panic!("Arc<T> should only have 1 type param")
343 };
344 assert_eq!(type_param_1.shape(), i32::SHAPE);
345 }
346
347 #[test]
348 fn test_arc_vtable() {
349 facet_testhelpers::setup();
350
351 let arc_shape = <Arc<String>>::SHAPE;
352 let arc_def = arc_shape
353 .def
354 .into_smart_pointer()
355 .expect("Arc<T> should have a smart pointer definition");
356
357 let weak_shape = <ArcWeak<String>>::SHAPE;
358 let weak_def = weak_shape
359 .def
360 .into_smart_pointer()
361 .expect("ArcWeak<T> should have a smart pointer definition");
362
363 let mut arc_storage = MaybeUninit::<Arc<String>>::zeroed();
365 let arc_ptr = unsafe {
366 let arc_uninit_ptr = PtrUninit::from_maybe_uninit(&mut arc_storage);
367
368 let value = String::from("example");
369 let value_ptr = PtrConst::new(&raw const value);
370
371 let returned_ptr = arc_def
376 .vtable
377 .new_into_fn
378 .expect("Arc<T> should have new_into_fn vtable function")(
379 arc_uninit_ptr,
380 value_ptr,
381 );
382
383 core::mem::forget(value);
385
386 assert_eq!(
389 returned_ptr.as_ptr(),
390 arc_uninit_ptr.as_byte_ptr() as *const Arc<String>
391 );
392
393 returned_ptr
394 };
395
396 unsafe {
397 let borrowed = arc_def
399 .vtable
400 .borrow_fn
401 .expect("Arc<T> should have borrow_fn vtable function")(
402 arc_ptr.as_const()
403 );
404 assert_eq!(borrowed.get::<String>(), "example");
405 }
406
407 let mut new_arc_storage = MaybeUninit::<ArcWeak<String>>::zeroed();
409 let weak_ptr = unsafe {
410 let weak_uninit_ptr = PtrUninit::from_maybe_uninit(&mut new_arc_storage);
411
412 let returned_ptr = arc_def
413 .vtable
414 .downgrade_into_fn
415 .expect("Arc<T> should have downgrade_into_fn vtable function")(
416 arc_ptr,
417 weak_uninit_ptr,
418 );
419
420 assert_eq!(
423 returned_ptr.as_ptr(),
424 weak_uninit_ptr.as_byte_ptr() as *const ArcWeak<String>
425 );
426
427 returned_ptr
428 };
429
430 {
431 let mut new_arc_storage = MaybeUninit::<Arc<String>>::zeroed();
432 let new_arc_ptr = unsafe {
433 let new_arc_uninit_ptr = PtrUninit::from_maybe_uninit(&mut new_arc_storage);
434
435 let returned_ptr = weak_def
437 .vtable
438 .upgrade_into_fn
439 .expect("ArcWeak<T> should have upgrade_into_fn vtable function")(
440 weak_ptr,
441 new_arc_uninit_ptr,
442 )
443 .expect("Upgrade should be successful");
444
445 assert_eq!(
448 returned_ptr.as_ptr(),
449 new_arc_uninit_ptr.as_byte_ptr() as *const Arc<String>
450 );
451
452 returned_ptr
453 };
454
455 unsafe {
456 let borrowed = arc_def
458 .vtable
459 .borrow_fn
460 .expect("Arc<T> should have borrow_fn vtable function")(
461 new_arc_ptr.as_const()
462 );
463 assert_eq!(borrowed.get::<String>(), "example");
464 }
465
466 unsafe {
467 arc_shape
469 .vtable
470 .drop_in_place
471 .expect("Arc<T> should have drop_in_place vtable function")(
472 new_arc_ptr
473 );
474 }
475 }
476
477 unsafe {
478 arc_shape
480 .vtable
481 .drop_in_place
482 .expect("Arc<T> should have drop_in_place vtable function")(arc_ptr);
483 }
484
485 unsafe {
486 let mut new_arc_storage = MaybeUninit::<Arc<String>>::zeroed();
487 let new_arc_uninit_ptr = PtrUninit::from_maybe_uninit(&mut new_arc_storage);
488
489 if weak_def
491 .vtable
492 .upgrade_into_fn
493 .expect("ArcWeak<T> should have upgrade_into_fn vtable function")(
494 weak_ptr,
495 new_arc_uninit_ptr,
496 )
497 .is_some()
498 {
499 panic!("Upgrade should be unsuccessful")
500 }
501 };
502
503 unsafe {
504 weak_shape
506 .vtable
507 .drop_in_place
508 .expect("ArcWeak<T> should have drop_in_place vtable function")(
509 weak_ptr
510 );
511 }
512 }
513
514 #[test]
515 fn test_rc_type_params() {
516 let [type_param_1] = <Rc<i32>>::SHAPE.type_params else {
517 panic!("Rc<T> should only have 1 type param")
518 };
519 assert_eq!(type_param_1.shape(), i32::SHAPE);
520 }
521
522 #[test]
523 fn test_rc_vtable() {
524 facet_testhelpers::setup();
525
526 let rc_shape = <Rc<String>>::SHAPE;
527 let rc_def = rc_shape
528 .def
529 .into_smart_pointer()
530 .expect("Rc<T> should have a smart pointer definition");
531
532 let weak_shape = <RcWeak<String>>::SHAPE;
533 let weak_def = weak_shape
534 .def
535 .into_smart_pointer()
536 .expect("RcWeak<T> should have a smart pointer definition");
537
538 let mut rc_storage = MaybeUninit::<Rc<String>>::zeroed();
540 let rc_ptr = unsafe {
541 let rc_uninit_ptr = PtrUninit::from_maybe_uninit(&mut rc_storage);
542
543 let value = String::from("example");
544 let value_ptr = PtrConst::new(&raw const value);
545
546 let returned_ptr = rc_def
551 .vtable
552 .new_into_fn
553 .expect("Rc<T> should have new_into_fn vtable function")(
554 rc_uninit_ptr, value_ptr
555 );
556
557 core::mem::forget(value);
559
560 assert_eq!(
563 returned_ptr.as_ptr(),
564 rc_uninit_ptr.as_byte_ptr() as *const Rc<String>
565 );
566
567 returned_ptr
568 };
569
570 unsafe {
571 let borrowed = rc_def
573 .vtable
574 .borrow_fn
575 .expect("Rc<T> should have borrow_fn vtable function")(
576 rc_ptr.as_const()
577 );
578 assert_eq!(borrowed.get::<String>(), "example");
579 }
580
581 let mut new_rc_storage = MaybeUninit::<RcWeak<String>>::zeroed();
583 let weak_ptr = unsafe {
584 let weak_uninit_ptr = PtrUninit::from_maybe_uninit(&mut new_rc_storage);
585
586 let returned_ptr = rc_def
587 .vtable
588 .downgrade_into_fn
589 .expect("Rc<T> should have downgrade_into_fn vtable function")(
590 rc_ptr,
591 weak_uninit_ptr,
592 );
593
594 assert_eq!(
597 returned_ptr.as_ptr(),
598 weak_uninit_ptr.as_byte_ptr() as *const RcWeak<String>
599 );
600
601 returned_ptr
602 };
603
604 {
605 let mut new_rc_storage = MaybeUninit::<Rc<String>>::zeroed();
606 let new_rc_ptr = unsafe {
607 let new_rc_uninit_ptr = PtrUninit::from_maybe_uninit(&mut new_rc_storage);
608
609 let returned_ptr = weak_def
611 .vtable
612 .upgrade_into_fn
613 .expect("RcWeak<T> should have upgrade_into_fn vtable function")(
614 weak_ptr,
615 new_rc_uninit_ptr,
616 )
617 .expect("Upgrade should be successful");
618
619 assert_eq!(
622 returned_ptr.as_ptr(),
623 new_rc_uninit_ptr.as_byte_ptr() as *const Rc<String>
624 );
625
626 returned_ptr
627 };
628
629 unsafe {
630 let borrowed = rc_def
632 .vtable
633 .borrow_fn
634 .expect("Rc<T> should have borrow_fn vtable function")(
635 new_rc_ptr.as_const()
636 );
637 assert_eq!(borrowed.get::<String>(), "example");
638 }
639
640 unsafe {
641 rc_shape
643 .vtable
644 .drop_in_place
645 .expect("Rc<T> should have drop_in_place vtable function")(
646 new_rc_ptr
647 );
648 }
649 }
650
651 unsafe {
652 rc_shape
654 .vtable
655 .drop_in_place
656 .expect("Rc<T> should have drop_in_place vtable function")(rc_ptr);
657 }
658
659 unsafe {
660 let mut new_rc_storage = MaybeUninit::<Rc<String>>::zeroed();
661 let new_rc_uninit_ptr = PtrUninit::from_maybe_uninit(&mut new_rc_storage);
662
663 if weak_def
665 .vtable
666 .upgrade_into_fn
667 .expect("RcWeak<T> should have upgrade_into_fn vtable function")(
668 weak_ptr,
669 new_rc_uninit_ptr,
670 )
671 .is_some()
672 {
673 panic!("Upgrade should be unsuccessful")
674 }
675 };
676
677 unsafe {
678 weak_shape
680 .vtable
681 .drop_in_place
682 .expect("RcWeak<T> should have drop_in_place vtable function")(weak_ptr);
683 }
684 }
685}