facet_core/impls/alloc/
arc.rs

1use core::alloc::Layout;
2use core::ptr::NonNull;
3
4use alloc::boxed::Box;
5use alloc::sync::{Arc, Weak};
6use alloc::vec::Vec;
7
8use crate::{
9    Def, Facet, KnownPointer, OxPtrConst, OxPtrMut, PointerDef, PointerFlags, PointerVTable,
10    PtrConst, PtrMut, PtrUninit, Shape, ShapeBuilder, SliceBuilderVTable, Type, TypeNameOpts,
11    TypeOpsIndirect, UserType, VTableIndirect,
12};
13
14// Helper functions to create type_name formatters
15fn type_name_arc<'a, T: Facet<'a>>(
16    _shape: &'static crate::Shape,
17    f: &mut core::fmt::Formatter<'_>,
18    opts: TypeNameOpts,
19) -> core::fmt::Result {
20    write!(f, "Arc")?;
21    if let Some(opts) = opts.for_children() {
22        write!(f, "<")?;
23        T::SHAPE.write_type_name(f, opts)?;
24        write!(f, ">")?;
25    } else {
26        write!(f, "<…>")?;
27    }
28    Ok(())
29}
30
31fn type_name_weak<'a, T: Facet<'a>>(
32    _shape: &'static crate::Shape,
33    f: &mut core::fmt::Formatter<'_>,
34    opts: TypeNameOpts,
35) -> core::fmt::Result {
36    write!(f, "Weak")?;
37    if let Some(opts) = opts.for_children() {
38        write!(f, "<")?;
39        T::SHAPE.write_type_name(f, opts)?;
40        write!(f, ">")?;
41    } else {
42        write!(f, "<…>")?;
43    }
44    Ok(())
45}
46
47// Pointer VTable functions for Arc<T>
48unsafe fn arc_borrow<'a, T: Facet<'a>>(this: PtrConst) -> PtrConst {
49    unsafe {
50        let arc_ptr = this.as_ptr::<Arc<T>>();
51        let ptr = &**arc_ptr;
52        PtrConst::new(NonNull::from(ptr).as_ptr())
53    }
54}
55
56unsafe fn arc_new_into<'a, 'src, T: Facet<'a>>(this: PtrUninit, ptr: PtrMut) -> PtrMut {
57    unsafe {
58        let t = ptr.read::<T>();
59        let arc = Arc::new(t);
60        this.put(arc)
61    }
62}
63
64unsafe fn arc_downgrade_into<'a, 'src, T: Facet<'a>>(strong: PtrMut, weak: PtrUninit) -> PtrMut {
65    unsafe { weak.put(Arc::downgrade(strong.as_const().get::<Arc<T>>())) }
66}
67
68// Arc<str> specific functions
69unsafe fn arc_str_borrow(this: PtrConst) -> PtrConst {
70    unsafe {
71        let concrete = this.get::<Arc<str>>();
72        let s: &str = concrete;
73        PtrConst::new(NonNull::from(s).as_ptr())
74    }
75}
76
77unsafe fn arc_str_downgrade_into(strong: PtrMut, weak: PtrUninit) -> PtrMut {
78    unsafe { weak.put(Arc::downgrade(strong.as_const().get::<Arc<str>>())) }
79}
80
81// Arc<[U]> specific functions
82unsafe fn arc_slice_borrow<'a, U: Facet<'a>>(this: PtrConst) -> PtrConst {
83    unsafe {
84        let concrete = this.get::<Arc<[U]>>();
85        let s: &[U] = concrete;
86        PtrConst::new(NonNull::from(s).as_ptr())
87    }
88}
89
90unsafe fn arc_slice_downgrade_into<'a, 'src, U: Facet<'a>>(
91    strong: PtrMut,
92    weak: PtrUninit,
93) -> PtrMut {
94    unsafe { weak.put(Arc::downgrade(strong.as_const().get::<Arc<[U]>>())) }
95}
96
97// Slice builder functions
98fn slice_builder_new<'a, U: Facet<'a>>() -> PtrMut {
99    let v = Box::new(Vec::<U>::new());
100    let raw = Box::into_raw(v);
101    PtrMut::new(raw as *mut u8)
102}
103
104unsafe fn slice_builder_push<'a, U: Facet<'a>>(builder: PtrMut, item: PtrMut) {
105    unsafe {
106        let vec = builder.as_mut::<Vec<U>>();
107        let value = item.read::<U>();
108        vec.push(value);
109    }
110}
111
112unsafe fn slice_builder_convert<'a, U: Facet<'a>>(builder: PtrMut) -> PtrConst {
113    unsafe {
114        let vec_box = Box::from_raw(builder.as_ptr::<Vec<U>>() as *mut Vec<U>);
115        let arc: Arc<[U]> = (*vec_box).into();
116
117        // Allocate memory for the Arc (which is a fat pointer, 16 bytes on 64-bit)
118        let layout = Layout::new::<Arc<[U]>>();
119        let ptr = alloc::alloc::alloc(layout) as *mut Arc<[U]>;
120        if ptr.is_null() {
121            alloc::alloc::handle_alloc_error(layout);
122        }
123
124        // Write the Arc into the allocation
125        ptr.write(arc);
126
127        PtrConst::new(ptr as *const u8)
128    }
129}
130
131unsafe fn slice_builder_free<'a, U: Facet<'a>>(builder: PtrMut) {
132    unsafe {
133        let _ = Box::from_raw(builder.as_ptr::<Vec<U>>() as *mut Vec<U>);
134    }
135}
136
137// Debug functions for Weak
138unsafe fn weak_debug(
139    _this: OxPtrConst,
140    f: &mut core::fmt::Formatter<'_>,
141) -> Option<core::fmt::Result> {
142    Some(write!(f, "(Weak)"))
143}
144
145// Drop functions for Weak
146unsafe fn weak_drop<T: ?Sized>(ox: OxPtrMut) {
147    unsafe {
148        core::ptr::drop_in_place(ox.ptr().as_ptr::<Weak<T>>() as *mut Weak<T>);
149    }
150}
151
152// Clone functions for Weak
153unsafe fn weak_clone<T: Clone>(src: OxPtrConst, dst: OxPtrMut) {
154    unsafe {
155        let value = src.get::<Weak<T>>().clone();
156        (dst.ptr().as_ptr::<Weak<T>>() as *mut Weak<T>).write(value);
157    }
158}
159
160// Default functions for Weak
161unsafe fn weak_default<T>(target: OxPtrMut) {
162    unsafe {
163        (target.ptr().as_ptr::<Weak<T>>() as *mut Weak<T>).write(Weak::<T>::new());
164    }
165}
166
167// Upgrade functions for Weak
168unsafe fn weak_upgrade_into<'a, 'src, T: Facet<'a>>(
169    weak: PtrMut,
170    strong: PtrUninit,
171) -> Option<PtrMut> {
172    unsafe { Some(strong.put(weak.as_const().get::<Weak<T>>().upgrade()?)) }
173}
174
175// Type operations for Arc<T>
176unsafe fn arc_drop<T>(ox: OxPtrMut) {
177    unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<Arc<T>>() as *mut Arc<T>) };
178}
179
180unsafe impl<'a, T: Facet<'a>> Facet<'a> for Arc<T> {
181    const SHAPE: &'static crate::Shape = &const {
182        ShapeBuilder::for_sized::<Self>("Arc")
183            .type_name(type_name_arc::<T>)
184            .vtable_indirect(&VTableIndirect::EMPTY)
185            .type_ops_indirect(
186                &const {
187                    TypeOpsIndirect {
188                        drop_in_place: arc_drop::<T>,
189                        default_in_place: None,
190                        clone_into: None,
191                        is_truthy: None,
192                    }
193                },
194            )
195            .ty(Type::User(UserType::Opaque))
196            .def(Def::Pointer(PointerDef {
197                vtable: &const {
198                    PointerVTable {
199                        borrow_fn: Some(arc_borrow::<T>),
200                        new_into_fn: Some(arc_new_into::<T>),
201                        downgrade_into_fn: Some(arc_downgrade_into::<T>),
202                        ..PointerVTable::new()
203                    }
204                },
205                pointee: Some(T::SHAPE),
206                weak: Some(|| <Weak<T> as Facet>::SHAPE),
207                strong: None,
208                flags: PointerFlags::ATOMIC,
209                known: Some(KnownPointer::Arc),
210            }))
211            .type_params(&[crate::TypeParam {
212                name: "T",
213                shape: T::SHAPE,
214            }])
215            .inner(T::SHAPE)
216            // Arc<T> propagates T's variance
217            .variance(Shape::computed_variance)
218            .build()
219    };
220}
221
222// Type operations for Arc<str>
223unsafe fn arc_str_drop(ox: OxPtrMut) {
224    unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<Arc<str>>() as *mut Arc<str>) };
225}
226
227// Type operations for Weak<str>
228unsafe fn weak_str_drop(ox: OxPtrMut) {
229    unsafe {
230        core::ptr::drop_in_place(ox.ptr().as_ptr::<Weak<str>>() as *mut Weak<str>);
231    }
232}
233
234// Module-level static for Arc<str> type ops
235static ARC_STR_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
236    drop_in_place: arc_str_drop,
237    default_in_place: None,
238    clone_into: None,
239    is_truthy: None,
240};
241
242unsafe impl<'a> Facet<'a> for Arc<str> {
243    const SHAPE: &'static crate::Shape = &const {
244        fn type_name_arc_str(
245            _shape: &'static crate::Shape,
246            f: &mut core::fmt::Formatter<'_>,
247            opts: TypeNameOpts,
248        ) -> core::fmt::Result {
249            write!(f, "Arc")?;
250            if let Some(opts) = opts.for_children() {
251                write!(f, "<")?;
252                str::SHAPE.write_type_name(f, opts)?;
253                write!(f, ">")?;
254            } else {
255                write!(f, "<…>")?;
256            }
257            Ok(())
258        }
259
260        ShapeBuilder::for_sized::<Self>("Arc")
261            .type_name(type_name_arc_str)
262            .vtable_indirect(&const { VTableIndirect::EMPTY })
263            .type_ops_indirect(&ARC_STR_TYPE_OPS)
264            .ty(Type::User(UserType::Opaque))
265            .def(Def::Pointer(PointerDef {
266                vtable: &const {
267                    PointerVTable {
268                        borrow_fn: Some(arc_str_borrow),
269                        downgrade_into_fn: Some(arc_str_downgrade_into),
270                        ..PointerVTable::new()
271                    }
272                },
273                pointee: Some(str::SHAPE),
274                weak: Some(|| <Weak<str> as Facet>::SHAPE),
275                strong: None,
276                flags: PointerFlags::ATOMIC,
277                known: Some(KnownPointer::Arc),
278            }))
279            .type_params(&[crate::TypeParam {
280                name: "T",
281                shape: str::SHAPE,
282            }])
283            .build()
284    };
285}
286
287// Type operations for Arc<[U]>
288unsafe fn arc_slice_drop<U>(ox: OxPtrMut) {
289    unsafe { core::ptr::drop_in_place(ox.ptr().as_ptr::<Arc<[U]>>() as *mut Arc<[U]>) };
290}
291
292// Type operations for Weak<[U]>
293unsafe fn weak_slice_drop<U>(ox: OxPtrMut) {
294    unsafe {
295        core::ptr::drop_in_place(ox.ptr().as_ptr::<Weak<[U]>>() as *mut Weak<[U]>);
296    }
297}
298
299unsafe impl<'a, U: Facet<'a>> Facet<'a> for Arc<[U]> {
300    const SHAPE: &'static crate::Shape = &const {
301        fn type_name_arc_slice<'a, U: Facet<'a>>(
302            _shape: &'static crate::Shape,
303            f: &mut core::fmt::Formatter<'_>,
304            opts: TypeNameOpts,
305        ) -> core::fmt::Result {
306            write!(f, "Arc")?;
307            if let Some(opts) = opts.for_children() {
308                write!(f, "<")?;
309                <[U]>::SHAPE.write_type_name(f, opts)?;
310                write!(f, ">")?;
311            } else {
312                write!(f, "<…>")?;
313            }
314            Ok(())
315        }
316
317        ShapeBuilder::for_sized::<Self>("Arc")
318            .type_name(type_name_arc_slice::<U>)
319            .vtable_indirect(&VTableIndirect::EMPTY)
320            .type_ops_indirect(
321                &const {
322                    TypeOpsIndirect {
323                        drop_in_place: arc_slice_drop::<U>,
324                        default_in_place: None,
325                        clone_into: None,
326                        is_truthy: None,
327                    }
328                },
329            )
330            .ty(Type::User(UserType::Opaque))
331            .def(Def::Pointer(PointerDef {
332                vtable: &const {
333                    PointerVTable {
334                        borrow_fn: Some(arc_slice_borrow::<U>),
335                        downgrade_into_fn: Some(arc_slice_downgrade_into::<U>),
336                        slice_builder_vtable: Some(
337                            &const {
338                                SliceBuilderVTable::new(
339                                    slice_builder_new::<U>,
340                                    slice_builder_push::<U>,
341                                    slice_builder_convert::<U>,
342                                    slice_builder_free::<U>,
343                                )
344                            },
345                        ),
346                        ..PointerVTable::new()
347                    }
348                },
349                pointee: Some(<[U]>::SHAPE),
350                weak: Some(|| <Weak<[U]> as Facet>::SHAPE),
351                strong: None,
352                flags: PointerFlags::ATOMIC,
353                known: Some(KnownPointer::Arc),
354            }))
355            .type_params(&[crate::TypeParam {
356                name: "T",
357                shape: <[U]>::SHAPE,
358            }])
359            .build()
360    };
361}
362
363unsafe impl<'a, T: Facet<'a>> Facet<'a> for Weak<T> {
364    const SHAPE: &'static crate::Shape = &const {
365        const VTABLE: VTableIndirect = VTableIndirect {
366            display: None,
367            debug: Some(weak_debug),
368            hash: None,
369            invariants: None,
370            parse: None,
371            parse_bytes: None,
372            try_from: None,
373            try_into_inner: None,
374            try_borrow_inner: None,
375            partial_eq: None,
376            partial_cmp: None,
377            cmp: None,
378        };
379
380        ShapeBuilder::for_sized::<Self>("Weak")
381            .type_name(type_name_weak::<T>)
382            .vtable_indirect(&VTABLE)
383            .type_ops_indirect(
384                &const {
385                    TypeOpsIndirect {
386                        drop_in_place: weak_drop::<T>,
387                        default_in_place: Some(weak_default::<T>),
388                        clone_into: Some(weak_clone::<Weak<T>>),
389                        is_truthy: None,
390                    }
391                },
392            )
393            .ty(Type::User(UserType::Opaque))
394            .def(Def::Pointer(PointerDef {
395                vtable: &const {
396                    PointerVTable {
397                        upgrade_into_fn: Some(weak_upgrade_into::<T>),
398                        ..PointerVTable::new()
399                    }
400                },
401                pointee: Some(T::SHAPE),
402                weak: None,
403                strong: Some(<Arc<T> as Facet>::SHAPE),
404                flags: PointerFlags::ATOMIC.union(PointerFlags::WEAK),
405                known: Some(KnownPointer::ArcWeak),
406            }))
407            .type_params(&[crate::TypeParam {
408                name: "T",
409                shape: T::SHAPE,
410            }])
411            .inner(T::SHAPE)
412            // Weak<T> propagates T's variance
413            .variance(Shape::computed_variance)
414            .build()
415    };
416}
417
418// Module-level statics for Weak<str>
419static WEAK_STR_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
420    drop_in_place: weak_str_drop,
421    default_in_place: None,
422    clone_into: Some(weak_clone::<Weak<str>>),
423    is_truthy: None,
424};
425
426static WEAK_VTABLE: VTableIndirect = VTableIndirect {
427    display: None,
428    debug: Some(weak_debug),
429    hash: None,
430    invariants: None,
431    parse: None,
432    parse_bytes: None,
433    try_from: None,
434    try_into_inner: None,
435    try_borrow_inner: None,
436    partial_eq: None,
437    partial_cmp: None,
438    cmp: None,
439};
440
441unsafe impl<'a> Facet<'a> for Weak<str> {
442    const SHAPE: &'static crate::Shape = &const {
443        fn type_name_weak_str(
444            _shape: &'static crate::Shape,
445            f: &mut core::fmt::Formatter<'_>,
446            opts: TypeNameOpts,
447        ) -> core::fmt::Result {
448            write!(f, "Weak")?;
449            if let Some(opts) = opts.for_children() {
450                write!(f, "<")?;
451                str::SHAPE.write_type_name(f, opts)?;
452                write!(f, ">")?;
453            } else {
454                write!(f, "<…>")?;
455            }
456            Ok(())
457        }
458
459        ShapeBuilder::for_sized::<Self>("Weak")
460            .type_name(type_name_weak_str)
461            .vtable_indirect(&WEAK_VTABLE)
462            .type_ops_indirect(&WEAK_STR_TYPE_OPS)
463            .ty(Type::User(UserType::Opaque))
464            .def(Def::Pointer(PointerDef {
465                vtable: &const {
466                    PointerVTable {
467                        upgrade_into_fn: Some(|weak, strong| unsafe {
468                            let upgraded = weak.as_const().get::<Weak<str>>().upgrade()?;
469                            Some(strong.put(upgraded))
470                        }),
471                        ..PointerVTable::new()
472                    }
473                },
474                pointee: Some(str::SHAPE),
475                weak: None,
476                strong: Some(<Arc<str> as Facet>::SHAPE),
477                flags: PointerFlags::ATOMIC.union(PointerFlags::WEAK),
478                known: Some(KnownPointer::ArcWeak),
479            }))
480            .type_params(&[crate::TypeParam {
481                name: "T",
482                shape: str::SHAPE,
483            }])
484            .build()
485    };
486}
487
488unsafe impl<'a, U: Facet<'a>> Facet<'a> for Weak<[U]> {
489    const SHAPE: &'static crate::Shape = &const {
490        fn type_name_weak_slice<'a, U: Facet<'a>>(
491            _shape: &'static crate::Shape,
492            f: &mut core::fmt::Formatter<'_>,
493            opts: TypeNameOpts,
494        ) -> core::fmt::Result {
495            write!(f, "Weak")?;
496            if let Some(opts) = opts.for_children() {
497                write!(f, "<")?;
498                <[U]>::SHAPE.write_type_name(f, opts)?;
499                write!(f, ">")?;
500            } else {
501                write!(f, "<…>")?;
502            }
503            Ok(())
504        }
505
506        const VTABLE: VTableIndirect = VTableIndirect {
507            display: None,
508            debug: Some(weak_debug),
509            hash: None,
510            invariants: None,
511            parse: None,
512            parse_bytes: None,
513            try_from: None,
514            try_into_inner: None,
515            try_borrow_inner: None,
516            partial_eq: None,
517            partial_cmp: None,
518            cmp: None,
519        };
520
521        ShapeBuilder::for_sized::<Self>("Weak")
522            .type_name(type_name_weak_slice::<U>)
523            .vtable_indirect(&VTABLE)
524            .type_ops_indirect(
525                &const {
526                    TypeOpsIndirect {
527                        drop_in_place: weak_slice_drop::<U>,
528                        default_in_place: None,
529                        clone_into: Some(weak_clone::<Weak<[U]>>),
530                        is_truthy: None,
531                    }
532                },
533            )
534            .ty(Type::User(UserType::Opaque))
535            .def(Def::Pointer(PointerDef {
536                vtable: &const {
537                    PointerVTable {
538                        upgrade_into_fn: Some(|weak, strong| unsafe {
539                            let upgraded = weak.as_const().get::<Weak<[U]>>().upgrade()?;
540                            Some(strong.put(upgraded))
541                        }),
542                        ..PointerVTable::new()
543                    }
544                },
545                pointee: Some(<[U]>::SHAPE),
546                weak: None,
547                strong: Some(<Arc<[U]> as Facet>::SHAPE),
548                flags: PointerFlags::ATOMIC.union(PointerFlags::WEAK),
549                known: Some(KnownPointer::ArcWeak),
550            }))
551            .type_params(&[crate::TypeParam {
552                name: "T",
553                shape: <[U]>::SHAPE,
554            }])
555            .build()
556    };
557}
558
559#[cfg(test)]
560mod tests {
561    use core::mem::ManuallyDrop;
562
563    use alloc::string::String;
564    use alloc::sync::{Arc, Weak as ArcWeak};
565
566    use super::*;
567
568    #[test]
569    fn test_arc_type_params() {
570        let [type_param_1] = <Arc<i32>>::SHAPE.type_params else {
571            panic!("Arc<T> should only have 1 type param")
572        };
573        assert_eq!(type_param_1.shape(), i32::SHAPE);
574    }
575
576    #[test]
577    fn test_arc_vtable_1_new_borrow_drop() {
578        facet_testhelpers::setup();
579
580        let arc_shape = <Arc<String>>::SHAPE;
581        let arc_def = arc_shape
582            .def
583            .into_pointer()
584            .expect("Arc<T> should have a smart pointer definition");
585
586        // Allocate memory for the Arc
587        let arc_uninit_ptr = arc_shape.allocate().unwrap();
588
589        // Get the function pointer for creating a new Arc from a value
590        let new_into_fn = arc_def
591            .vtable
592            .new_into_fn
593            .expect("Arc<T> should have new_into_fn");
594
595        // Create the value and initialize the Arc
596        let mut value = ManuallyDrop::new(String::from("example"));
597        let arc_ptr = unsafe {
598            new_into_fn(
599                arc_uninit_ptr,
600                PtrMut::new(NonNull::from(&mut value).as_ptr()),
601            )
602        };
603        // The value now belongs to the Arc, prevent its drop
604
605        // Get the function pointer for borrowing the inner value
606        let borrow_fn = arc_def
607            .vtable
608            .borrow_fn
609            .expect("Arc<T> should have borrow_fn");
610
611        // Borrow the inner value and check it
612        let borrowed_ptr = unsafe { borrow_fn(arc_ptr.as_const()) };
613        // SAFETY: borrowed_ptr points to a valid String within the Arc
614        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
615
616        // Drop the Arc in place
617        // SAFETY: arc_ptr points to a valid Arc<String>
618        unsafe {
619            arc_shape
620                .call_drop_in_place(arc_ptr)
621                .expect("Arc<T> should have drop_in_place");
622        }
623
624        // Deallocate the memory
625        // SAFETY: arc_ptr was allocated by arc_shape and is now dropped (but memory is still valid)
626        unsafe { arc_shape.deallocate_mut(arc_ptr).unwrap() };
627    }
628
629    #[test]
630    fn test_arc_vtable_2_downgrade_upgrade_drop() {
631        facet_testhelpers::setup();
632
633        let arc_shape = <Arc<String>>::SHAPE;
634        let arc_def = arc_shape
635            .def
636            .into_pointer()
637            .expect("Arc<T> should have a smart pointer definition");
638
639        let weak_shape = <ArcWeak<String>>::SHAPE;
640        let weak_def = weak_shape
641            .def
642            .into_pointer()
643            .expect("ArcWeak<T> should have a smart pointer definition");
644
645        // 1. Create the first Arc (arc1)
646        let arc1_uninit_ptr = arc_shape.allocate().unwrap();
647        let new_into_fn = arc_def.vtable.new_into_fn.unwrap();
648        let mut value = ManuallyDrop::new(String::from("example"));
649        let arc1_ptr = unsafe {
650            new_into_fn(
651                arc1_uninit_ptr,
652                PtrMut::new(NonNull::from(&mut value).as_ptr()),
653            )
654        };
655
656        // 2. Downgrade arc1 to create a weak pointer (weak1)
657        let weak1_uninit_ptr = weak_shape.allocate().unwrap();
658        let downgrade_into_fn = arc_def.vtable.downgrade_into_fn.unwrap();
659        // SAFETY: arc1_ptr points to a valid Arc, weak1_uninit_ptr is allocated for a Weak
660        let weak1_ptr = unsafe { downgrade_into_fn(arc1_ptr, weak1_uninit_ptr) };
661
662        // 3. Upgrade weak1 to create a second Arc (arc2)
663        let arc2_uninit_ptr = arc_shape.allocate().unwrap();
664        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
665        // SAFETY: weak1_ptr points to a valid Weak, arc2_uninit_ptr is allocated for an Arc.
666        // Upgrade should succeed as arc1 still exists.
667        let arc2_ptr = unsafe { upgrade_into_fn(weak1_ptr, arc2_uninit_ptr) }
668            .expect("Upgrade should succeed while original Arc exists");
669
670        // Check the content of the upgraded Arc
671        let borrow_fn = arc_def.vtable.borrow_fn.unwrap();
672        // SAFETY: arc2_ptr points to a valid Arc<String>
673        let borrowed_ptr = unsafe { borrow_fn(arc2_ptr.as_const()) };
674        // SAFETY: borrowed_ptr points to a valid String
675        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
676
677        // 4. Drop everything and free memory
678        unsafe {
679            // Drop Arcs
680            arc_shape.call_drop_in_place(arc1_ptr).unwrap();
681            arc_shape.deallocate_mut(arc1_ptr).unwrap();
682            arc_shape.call_drop_in_place(arc2_ptr).unwrap();
683            arc_shape.deallocate_mut(arc2_ptr).unwrap();
684
685            // Drop Weak
686            weak_shape.call_drop_in_place(weak1_ptr).unwrap();
687            weak_shape.deallocate_mut(weak1_ptr).unwrap();
688        }
689    }
690
691    #[test]
692    fn test_arc_vtable_3_downgrade_drop_try_upgrade() {
693        facet_testhelpers::setup();
694
695        let arc_shape = <Arc<String>>::SHAPE;
696        let arc_def = arc_shape
697            .def
698            .into_pointer()
699            .expect("Arc<T> should have a smart pointer definition");
700
701        let weak_shape = <ArcWeak<String>>::SHAPE;
702        let weak_def = weak_shape
703            .def
704            .into_pointer()
705            .expect("ArcWeak<T> should have a smart pointer definition");
706
707        // 1. Create the strong Arc (arc1)
708        let arc1_uninit_ptr = arc_shape.allocate().unwrap();
709        let new_into_fn = arc_def.vtable.new_into_fn.unwrap();
710        let mut value = ManuallyDrop::new(String::from("example"));
711        let arc1_ptr = unsafe {
712            new_into_fn(
713                arc1_uninit_ptr,
714                PtrMut::new(NonNull::from(&mut value).as_ptr()),
715            )
716        };
717
718        // 2. Downgrade arc1 to create a weak pointer (weak1)
719        let weak1_uninit_ptr = weak_shape.allocate().unwrap();
720        let downgrade_into_fn = arc_def.vtable.downgrade_into_fn.unwrap();
721        // SAFETY: arc1_ptr is valid, weak1_uninit_ptr is allocated for Weak
722        let weak1_ptr = unsafe { downgrade_into_fn(arc1_ptr, weak1_uninit_ptr) };
723
724        // 3. Drop and free the strong pointer (arc1)
725        unsafe {
726            arc_shape.call_drop_in_place(arc1_ptr).unwrap();
727            arc_shape.deallocate_mut(arc1_ptr).unwrap();
728        }
729
730        // 4. Attempt to upgrade the weak pointer (weak1)
731        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
732        let arc2_uninit_ptr = arc_shape.allocate().unwrap();
733        // SAFETY: weak1_ptr is valid (though points to dropped data), arc2_uninit_ptr is allocated for Arc
734        let upgrade_result = unsafe { upgrade_into_fn(weak1_ptr, arc2_uninit_ptr) };
735
736        // Assert that the upgrade failed
737        assert!(
738            upgrade_result.is_none(),
739            "Upgrade should fail after the strong Arc is dropped"
740        );
741
742        // 5. Clean up: Deallocate the memory intended for the failed upgrade and drop/deallocate the weak pointer
743        unsafe {
744            // Deallocate the *uninitialized* memory allocated for the failed upgrade attempt
745            arc_shape.deallocate_uninit(arc2_uninit_ptr).unwrap();
746
747            // Drop and deallocate the weak pointer
748            weak_shape.call_drop_in_place(weak1_ptr).unwrap();
749            weak_shape.deallocate_mut(weak1_ptr).unwrap();
750        }
751    }
752
753    #[test]
754    fn test_arc_vtable_6_slice_builder() {
755        facet_testhelpers::setup();
756
757        // Get the shapes we'll be working with
758        let arc_slice_shape = <Arc<[i32]>>::SHAPE;
759        let arc_slice_def = arc_slice_shape
760            .def
761            .into_pointer()
762            .expect("Arc<[i32]> should have a smart pointer definition");
763
764        // Get the slice builder vtable
765        let slice_builder_vtable = arc_slice_def
766            .vtable
767            .slice_builder_vtable
768            .expect("Arc<[i32]> should have slice_builder_vtable");
769
770        // 1. Create a new builder
771        let builder_ptr = (slice_builder_vtable.new_fn)();
772
773        // 2. Push some items to the builder
774        let push_fn = slice_builder_vtable.push_fn;
775        let values = [1i32, 2, 3, 4, 5];
776        for &value in &values {
777            let mut value_copy = value;
778            let value_ptr = PtrMut::new(NonNull::from(&mut value_copy).as_ptr());
779            unsafe { push_fn(builder_ptr, value_ptr) };
780        }
781
782        // 3. Convert the builder to Arc<[i32]>
783        let convert_fn = slice_builder_vtable.convert_fn;
784        let arc_slice_ptr = unsafe { convert_fn(builder_ptr) };
785
786        // 4. Verify the contents by borrowing
787        let borrow_fn = arc_slice_def
788            .vtable
789            .borrow_fn
790            .expect("Arc<[i32]> should have borrow_fn");
791        let borrowed_ptr = unsafe { borrow_fn(arc_slice_ptr) };
792
793        // Convert the wide pointer to a slice reference
794        let slice = unsafe { borrowed_ptr.get::<[i32]>() };
795        assert_eq!(slice, &[1, 2, 3, 4, 5]);
796
797        // 5. Clean up - the Arc<[i32]> was boxed by convert_fn, we need to deallocate the Box
798        unsafe {
799            let _ = Box::from_raw(arc_slice_ptr.as_ptr::<Arc<[i32]>>() as *mut Arc<[i32]>);
800        }
801    }
802
803    #[test]
804    fn test_arc_vtable_7_slice_builder_free() {
805        facet_testhelpers::setup();
806
807        // Get the shapes we'll be working with
808        let arc_slice_shape = <Arc<[String]>>::SHAPE;
809        let arc_slice_def = arc_slice_shape
810            .def
811            .into_pointer()
812            .expect("Arc<[String]> should have a smart pointer definition");
813
814        // Get the slice builder vtable
815        let slice_builder_vtable = arc_slice_def
816            .vtable
817            .slice_builder_vtable
818            .expect("Arc<[String]> should have slice_builder_vtable");
819
820        // 1. Create a new builder
821        let builder_ptr = (slice_builder_vtable.new_fn)();
822
823        // 2. Push some items to the builder
824        let push_fn = slice_builder_vtable.push_fn;
825        let strings = ["hello", "world", "test"];
826        for &s in &strings {
827            let mut value = ManuallyDrop::new(String::from(s));
828            let value_ptr = PtrMut::new(NonNull::from(&mut value).as_ptr());
829            unsafe { push_fn(builder_ptr, value_ptr) };
830        }
831
832        // 3. Instead of converting, test the free function
833        // This simulates abandoning the builder without creating the Arc
834        let free_fn = slice_builder_vtable.free_fn;
835        unsafe { free_fn(builder_ptr) };
836
837        // If we get here without panicking, the free worked correctly
838    }
839}