facet_core/impls_alloc/
rc.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::rc::Rc<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 rc = alloc::rc::Rc::new(t);
23 Ok(unsafe { dst.put(rc) })
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 rc = unsafe { src_ptr.get::<alloc::rc::Rc<T>>() };
31 match alloc::rc::Rc::try_unwrap(rc.clone()) {
32 Ok(t) => Ok(unsafe { dst.put(t) }),
33 Err(_) => Err(TryIntoInnerError::Unavailable),
34 }
35 }
36
37 unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
38 src_ptr: PtrConst<'src>,
39 ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
40 let rc = unsafe { src_ptr.get::<alloc::rc::Rc<T>>() };
41 Ok(PtrConst::new(&**rc))
42 }
43
44 let mut vtable = value_vtable!(alloc::rc::Rc<T>, |f, opts| {
45 write!(f, "{}", Self::SHAPE.type_identifier)?;
46 if let Some(opts) = opts.for_children() {
47 write!(f, "<")?;
48 T::SHAPE.vtable.type_name()(f, opts)?;
49 write!(f, ">")?;
50 } else {
51 write!(f, "<…>")?;
52 }
53 Ok(())
54 });
55 {
56 let vtable = vtable.sized_mut().unwrap();
57 vtable.try_from = || Some(try_from::<T>);
58 vtable.try_into_inner = || Some(try_into_inner::<T>);
59 vtable.try_borrow_inner = || Some(try_borrow_inner::<T>);
60 }
61 vtable
62 };
63
64 const SHAPE: &'static crate::Shape<'static> = &const {
65 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape<'static> {
67 T::SHAPE
68 }
69
70 crate::Shape::builder_for_sized::<Self>()
71 .type_identifier("Rc")
72 .type_params(&[crate::TypeParam {
73 name: "T",
74 shape: || T::SHAPE,
75 }])
76 .ty(Type::User(UserType::Opaque))
77 .def(Def::SmartPointer(
78 SmartPointerDef::builder()
79 .pointee(|| T::SHAPE)
80 .flags(SmartPointerFlags::EMPTY)
81 .known(KnownSmartPointer::Rc)
82 .weak(|| <alloc::rc::Weak<T> as Facet>::SHAPE)
83 .vtable(
84 &const {
85 SmartPointerVTable::builder()
86 .borrow_fn(|this| {
87 let ptr = Self::as_ptr(unsafe { this.get() });
88 PtrConst::new(ptr)
89 })
90 .new_into_fn(|this, ptr| {
91 let t = unsafe { ptr.read::<T>() };
92 let rc = alloc::rc::Rc::new(t);
93 unsafe { this.put(rc) }
94 })
95 .downgrade_into_fn(|strong, weak| unsafe {
96 weak.put(alloc::rc::Rc::downgrade(strong.get::<Self>()))
97 })
98 .build()
99 },
100 )
101 .build(),
102 ))
103 .inner(inner_shape::<T>)
104 .build()
105 };
106}
107
108unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::rc::Weak<T> {
109 const VTABLE: &'static ValueVTable = &const {
110 value_vtable!(alloc::rc::Weak<T>, |f, opts| {
111 write!(f, "{}", Self::SHAPE.type_identifier)?;
112 if let Some(opts) = opts.for_children() {
113 write!(f, "<")?;
114 T::SHAPE.vtable.type_name()(f, opts)?;
115 write!(f, ">")?;
116 } else {
117 write!(f, "<…>")?;
118 }
119 Ok(())
120 })
121 };
122
123 const SHAPE: &'static crate::Shape<'static> = &const {
124 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape<'static> {
126 T::SHAPE
127 }
128
129 crate::Shape::builder_for_sized::<Self>()
130 .type_identifier("Weak")
131 .type_params(&[crate::TypeParam {
132 name: "T",
133 shape: || T::SHAPE,
134 }])
135 .ty(Type::User(UserType::Opaque))
136 .def(Def::SmartPointer(
137 SmartPointerDef::builder()
138 .pointee(|| T::SHAPE)
139 .flags(SmartPointerFlags::WEAK)
140 .known(KnownSmartPointer::RcWeak)
141 .strong(|| <alloc::rc::Rc<T> as Facet>::SHAPE)
142 .vtable(
143 &const {
144 SmartPointerVTable::builder()
145 .upgrade_into_fn(|weak, strong| unsafe {
146 Some(strong.put(weak.get::<Self>().upgrade()?))
147 })
148 .build()
149 },
150 )
151 .build(),
152 ))
153 .inner(inner_shape::<T>)
154 .build()
155 };
156}
157
158#[cfg(test)]
159mod tests {
160 use alloc::rc::{Rc, Weak as RcWeak};
161 use alloc::string::String;
162
163 use super::*;
164
165 #[test]
166 fn test_rc_type_params() {
167 let [type_param_1] = <Rc<i32>>::SHAPE.type_params else {
168 panic!("Rc<T> should only have 1 type param")
169 };
170 assert_eq!(type_param_1.shape(), i32::SHAPE);
171 }
172
173 #[test]
174 fn test_rc_vtable_1_new_borrow_drop() -> eyre::Result<()> {
175 facet_testhelpers::setup();
176
177 let rc_shape = <Rc<String>>::SHAPE;
178 let rc_def = rc_shape
179 .def
180 .into_smart_pointer()
181 .expect("Rc<T> should have a smart pointer definition");
182
183 let rc_uninit_ptr = rc_shape.allocate()?;
185
186 let new_into_fn = rc_def
188 .vtable
189 .new_into_fn
190 .expect("Rc<T> should have new_into_fn");
191
192 let mut value = String::from("example");
194 let rc_ptr = unsafe { new_into_fn(rc_uninit_ptr, PtrMut::new(&raw mut value)) };
195 core::mem::forget(value);
197
198 let borrow_fn = rc_def
200 .vtable
201 .borrow_fn
202 .expect("Rc<T> should have borrow_fn");
203
204 let borrowed_ptr = unsafe { borrow_fn(rc_ptr.as_const()) };
206 assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
208
209 let drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)()
211 .expect("Rc<T> should have drop_in_place");
212
213 unsafe { drop_fn(rc_ptr) };
216
217 unsafe { rc_shape.deallocate_mut(rc_ptr)? };
220
221 Ok(())
222 }
223
224 #[test]
225 fn test_rc_vtable_2_downgrade_upgrade_drop() -> eyre::Result<()> {
226 facet_testhelpers::setup();
227
228 let rc_shape = <Rc<String>>::SHAPE;
229 let rc_def = rc_shape
230 .def
231 .into_smart_pointer()
232 .expect("Rc<T> should have a smart pointer definition");
233
234 let weak_shape = <RcWeak<String>>::SHAPE;
235 let weak_def = weak_shape
236 .def
237 .into_smart_pointer()
238 .expect("RcWeak<T> should have a smart pointer definition");
239
240 let rc1_uninit_ptr = rc_shape.allocate()?;
242 let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
243 let mut value = String::from("example");
244 let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrMut::new(&raw mut value)) };
245 core::mem::forget(value); let weak1_uninit_ptr = weak_shape.allocate()?;
249 let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
250 let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
252
253 let rc2_uninit_ptr = rc_shape.allocate()?;
255 let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
256 let rc2_ptr = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) }
259 .expect("Upgrade should succeed while original Rc exists");
260
261 let borrow_fn = rc_def.vtable.borrow_fn.unwrap();
263 let borrowed_ptr = unsafe { borrow_fn(rc2_ptr.as_const()) };
265 assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
267
268 let rc_drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
270 let weak_drop_fn = (weak_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
271
272 unsafe {
273 rc_drop_fn(rc1_ptr);
275 rc_shape.deallocate_mut(rc1_ptr)?;
276 rc_drop_fn(rc2_ptr);
277 rc_shape.deallocate_mut(rc2_ptr)?;
278
279 weak_drop_fn(weak1_ptr);
281 weak_shape.deallocate_mut(weak1_ptr)?;
282 }
283
284 Ok(())
285 }
286
287 #[test]
288 fn test_rc_vtable_3_downgrade_drop_try_upgrade() -> eyre::Result<()> {
289 facet_testhelpers::setup();
290
291 let rc_shape = <Rc<String>>::SHAPE;
292 let rc_def = rc_shape
293 .def
294 .into_smart_pointer()
295 .expect("Rc<T> should have a smart pointer definition");
296
297 let weak_shape = <RcWeak<String>>::SHAPE;
298 let weak_def = weak_shape
299 .def
300 .into_smart_pointer()
301 .expect("RcWeak<T> should have a smart pointer definition");
302
303 let rc1_uninit_ptr = rc_shape.allocate()?;
305 let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
306 let mut value = String::from("example");
307 let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrMut::new(&raw mut value)) };
308 core::mem::forget(value);
309
310 let weak1_uninit_ptr = weak_shape.allocate()?;
312 let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
313 let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
315
316 let rc_drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
318 unsafe {
319 rc_drop_fn(rc1_ptr);
320 rc_shape.deallocate_mut(rc1_ptr)?;
321 }
322
323 let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
325 let rc2_uninit_ptr = rc_shape.allocate()?;
326 let upgrade_result = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) };
328
329 assert!(
331 upgrade_result.is_none(),
332 "Upgrade should fail after the strong Rc is dropped"
333 );
334
335 let weak_drop_fn = (weak_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
337 unsafe {
338 rc_shape.deallocate_uninit(rc2_uninit_ptr)?;
340
341 weak_drop_fn(weak1_ptr);
343 weak_shape.deallocate_mut(weak1_ptr)?;
344 }
345
346 Ok(())
347 }
348}