Skip to main content

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