facet_core/impls_alloc/
boxed.rs1use crate::{
2 Def, Facet, KnownSmartPointer, PtrConst, PtrMut, PtrUninit, Shape, SmartPointerDef,
3 SmartPointerFlags, SmartPointerVTable, TryBorrowInnerError, TryFromError, TryIntoInnerError,
4 Type, UserType, ValueVTable, value_vtable,
5};
6
7unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::boxed::Box<T> {
8 const VTABLE: &'static ValueVTable = &const {
9 unsafe fn try_from<'a, 'shape, 'src, 'dst, T: Facet<'a>>(
11 src_ptr: PtrConst<'src>,
12 src_shape: &'shape Shape<'shape>,
13 dst: PtrUninit<'dst>,
14 ) -> Result<PtrMut<'dst>, TryFromError<'shape>> {
15 if src_shape.id != T::SHAPE.id {
16 return Err(TryFromError::UnsupportedSourceShape {
17 src_shape,
18 expected: &[T::SHAPE],
19 });
20 }
21 let t = unsafe { src_ptr.read::<T>() };
22 let boxed = alloc::boxed::Box::new(t);
23 Ok(unsafe { dst.put(boxed) })
24 }
25
26 unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
27 src_ptr: PtrMut<'src>,
28 dst: PtrUninit<'dst>,
29 ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
30 let boxed = unsafe { src_ptr.read::<alloc::boxed::Box<T>>() };
31 Ok(unsafe { dst.put(*boxed) })
32 }
33
34 unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
35 src_ptr: PtrConst<'src>,
36 ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
37 let boxed = unsafe { src_ptr.get::<alloc::boxed::Box<T>>() };
38 Ok(PtrConst::new(&**boxed))
39 }
40
41 let mut vtable = value_vtable!(alloc::boxed::Box<T>, |f, opts| {
42 write!(f, "{}", Self::SHAPE.type_identifier)?;
43 if let Some(opts) = opts.for_children() {
44 write!(f, "<")?;
45 (T::SHAPE.vtable.type_name())(f, opts)?;
46 write!(f, ">")?;
47 } else {
48 write!(f, "<…>")?;
49 }
50 Ok(())
51 });
52 {
53 let vtable = vtable.sized_mut().unwrap();
54 vtable.try_from = || Some(try_from::<T>);
55 vtable.try_into_inner = || Some(try_into_inner::<T>);
56 vtable.try_borrow_inner = || Some(try_borrow_inner::<T>);
57 }
58 vtable
59 };
60
61 const SHAPE: &'static crate::Shape<'static> = &const {
62 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape<'static> {
64 T::SHAPE
65 }
66
67 crate::Shape::builder_for_sized::<Self>()
68 .type_identifier("Box")
69 .type_params(&[crate::TypeParam {
70 name: "T",
71 shape: || T::SHAPE,
72 }])
73 .ty(Type::User(UserType::Opaque))
74 .def(Def::SmartPointer(
75 SmartPointerDef::builder()
76 .pointee(|| T::SHAPE)
77 .flags(SmartPointerFlags::EMPTY)
78 .known(KnownSmartPointer::Box)
79 .vtable(
80 &const {
81 SmartPointerVTable::builder()
82 .borrow_fn(|this| {
83 let ptr = unsafe {
84 &raw const **this.as_ptr::<alloc::boxed::Box<T>>()
85 };
86 PtrConst::new(ptr)
87 })
88 .new_into_fn(|this, ptr| {
89 let t = unsafe { ptr.read::<T>() };
90 let boxed = alloc::boxed::Box::new(t);
91 unsafe { this.put(boxed) }
92 })
93 .build()
94 },
95 )
96 .build(),
97 ))
98 .inner(inner_shape::<T>)
99 .build()
100 };
101}
102
103#[cfg(test)]
104mod tests {
105 use alloc::boxed::Box;
106 use alloc::string::String;
107
108 use super::*;
109
110 #[test]
111 fn test_box_type_params() {
112 let [type_param_1] = <Box<i32>>::SHAPE.type_params else {
113 panic!("Box<T> should only have 1 type param")
114 };
115 assert_eq!(type_param_1.shape(), i32::SHAPE);
116 }
117
118 #[test]
119 fn test_box_vtable_1_new_borrow_drop() -> eyre::Result<()> {
120 facet_testhelpers::setup();
121
122 let box_shape = <Box<String>>::SHAPE;
123 let box_def = box_shape
124 .def
125 .into_smart_pointer()
126 .expect("Box<T> should have a smart pointer definition");
127
128 let box_uninit_ptr = box_shape.allocate()?;
130
131 let new_into_fn = box_def
133 .vtable
134 .new_into_fn
135 .expect("Box<T> should have new_into_fn");
136
137 let mut value = String::from("example");
139 let box_ptr = unsafe { new_into_fn(box_uninit_ptr, PtrMut::new(&raw mut value)) };
140 core::mem::forget(value);
142
143 let borrow_fn = box_def
145 .vtable
146 .borrow_fn
147 .expect("Box<T> should have borrow_fn");
148
149 let borrowed_ptr = unsafe { borrow_fn(box_ptr.as_const()) };
151 assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
153
154 let drop_fn = (box_shape.vtable.sized().unwrap().drop_in_place)()
156 .expect("Box<T> should have drop_in_place");
157
158 unsafe { drop_fn(box_ptr) };
161
162 unsafe { box_shape.deallocate_mut(box_ptr)? };
165
166 Ok(())
167 }
168}