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