facet_core/impls_alloc/
boxed.rs1use alloc::boxed::Box;
2
3use crate::{
4 Def, Facet, KnownPointer, PointerDef, PointerFlags, PointerVTable, PtrConst, PtrConstWide,
5 PtrMut, PtrUninit, Shape, TryBorrowInnerError, TryFromError, TryIntoInnerError, Type, UserType,
6 ValueVTable, value_vtable,
7};
8
9unsafe impl<'a, T: Facet<'a>> Facet<'a> for Box<T> {
10 const VTABLE: &'static ValueVTable = &const {
11 unsafe fn try_from<'a, 'src, 'dst, T: Facet<'a>>(
13 src_ptr: PtrConst<'src>,
14 src_shape: &'static Shape,
15 dst: PtrUninit<'dst>,
16 ) -> Result<PtrMut<'dst>, TryFromError> {
17 if src_shape.id != T::SHAPE.id {
18 return Err(TryFromError::UnsupportedSourceShape {
19 src_shape,
20 expected: &[T::SHAPE],
21 });
22 }
23 let t = unsafe { src_ptr.read::<T>() };
24 let boxed = Box::new(t);
25 Ok(unsafe { dst.put(boxed) })
26 }
27
28 unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
29 src_ptr: PtrMut<'src>,
30 dst: PtrUninit<'dst>,
31 ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
32 let boxed = unsafe { src_ptr.read::<Box<T>>() };
33 Ok(unsafe { dst.put(*boxed) })
34 }
35
36 unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
37 src_ptr: PtrConst<'src>,
38 ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
39 let boxed = unsafe { src_ptr.get::<Box<T>>() };
40 Ok(PtrConst::new(&**boxed))
41 }
42
43 let mut vtable = value_vtable!(alloc::boxed::Box<T>, |f, opts| {
44 write!(f, "{}", Self::SHAPE.type_identifier)?;
45 if let Some(opts) = opts.for_children() {
46 write!(f, "<")?;
47 (T::SHAPE.vtable.type_name())(f, opts)?;
48 write!(f, ">")?;
49 } else {
50 write!(f, "<…>")?;
51 }
52 Ok(())
53 });
54 {
55 let vtable = vtable.sized_mut().unwrap();
56 vtable.try_from = || Some(try_from::<T>);
57 vtable.try_into_inner = || Some(try_into_inner::<T>);
58 vtable.try_borrow_inner = || Some(try_borrow_inner::<T>);
59 }
60 vtable
61 };
62
63 const SHAPE: &'static crate::Shape = &const {
64 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
66 T::SHAPE
67 }
68
69 crate::Shape::builder_for_sized::<Self>()
70 .type_identifier("Box")
71 .type_params(&[crate::TypeParam {
72 name: "T",
73 shape: || T::SHAPE,
74 }])
75 .ty(Type::User(UserType::Opaque))
76 .def(Def::Pointer(
77 PointerDef::builder()
78 .pointee(|| T::SHAPE)
79 .flags(PointerFlags::EMPTY)
80 .known(KnownPointer::Box)
81 .vtable(
82 &const {
83 PointerVTable::builder()
84 .borrow_fn(|this| unsafe {
85 let concrete = this.get::<Box<T>>();
86 let t: &T = concrete.as_ref();
87 PtrConst::new(t as *const T).into()
88 })
89 .new_into_fn(|this, ptr| {
90 let t = unsafe { ptr.read::<T>() };
91 let boxed = Box::new(t);
92 unsafe { this.put(boxed) }
93 })
94 .build()
95 },
96 )
97 .build(),
98 ))
99 .inner(inner_shape::<T>)
100 .build()
101 };
102}
103
104unsafe impl<'a> Facet<'a> for Box<str> {
105 const VTABLE: &'static ValueVTable = &const {
106 value_vtable!(alloc::boxed::Box<str>, |f, opts| {
107 write!(f, "{}", Self::SHAPE.type_identifier)?;
108 if let Some(opts) = opts.for_children() {
109 write!(f, "<")?;
110 (str::SHAPE.vtable.type_name())(f, opts)?;
111 write!(f, ">")?;
112 } else {
113 write!(f, "<…>")?;
114 }
115 Ok(())
116 })
117 };
118
119 const SHAPE: &'static crate::Shape = &const {
120 fn inner_shape() -> &'static Shape {
121 str::SHAPE
122 }
123
124 crate::Shape::builder_for_sized::<Self>()
125 .type_identifier("Box")
126 .type_params(&[crate::TypeParam {
127 name: "T",
128 shape: || str::SHAPE,
129 }])
130 .ty(Type::User(UserType::Opaque))
131 .def(Def::Pointer(
132 PointerDef::builder()
133 .pointee(|| str::SHAPE)
134 .flags(PointerFlags::EMPTY)
135 .known(KnownPointer::Box)
136 .vtable(
137 &const {
138 PointerVTable::builder()
139 .borrow_fn(|this| unsafe {
140 let concrete = this.get::<Box<str>>();
141 let s: &str = concrete;
142 PtrConstWide::new(&raw const *s).into()
143 })
144 .new_into_fn(|_this, _ptr| todo!())
145 .build()
146 },
147 )
148 .build(),
149 ))
150 .inner(inner_shape)
151 .build()
152 };
153}
154
155#[cfg(test)]
156mod tests {
157 use alloc::boxed::Box;
158 use alloc::string::String;
159
160 use super::*;
161
162 #[test]
163 fn test_box_type_params() {
164 let [type_param_1] = <Box<i32>>::SHAPE.type_params else {
165 panic!("Box<T> should only have 1 type param")
166 };
167 assert_eq!(type_param_1.shape(), i32::SHAPE);
168 }
169
170 #[test]
171 fn test_box_vtable_1_new_borrow_drop() {
172 facet_testhelpers::setup();
173
174 let box_shape = <Box<String>>::SHAPE;
175 let box_def = box_shape
176 .def
177 .into_pointer()
178 .expect("Box<T> should have a smart pointer definition");
179
180 let box_uninit_ptr = box_shape.allocate().unwrap();
182
183 let new_into_fn = box_def
185 .vtable
186 .new_into_fn
187 .expect("Box<T> should have new_into_fn");
188
189 let mut value = String::from("example");
191 let box_ptr = unsafe { new_into_fn(box_uninit_ptr, PtrMut::new(&raw mut value)) };
192 core::mem::forget(value);
194
195 let borrow_fn = box_def
197 .vtable
198 .borrow_fn
199 .expect("Box<T> should have borrow_fn");
200
201 let borrowed_ptr = unsafe { borrow_fn(box_ptr.as_const()) };
203 assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
205
206 let drop_fn = (box_shape.vtable.sized().unwrap().drop_in_place)()
208 .expect("Box<T> should have drop_in_place");
209
210 unsafe { drop_fn(box_ptr) };
213
214 unsafe { box_shape.deallocate_mut(box_ptr).unwrap() };
217 }
218}