facet_core/impls_alloc/
rc.rs

1use alloc::rc::{Rc, Weak};
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 Rc<T> {
10    const VTABLE: &'static ValueVTable = &const {
11        // Define the functions for transparent conversion between Rc<T> and T
12        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 rc = Rc::new(t);
25            Ok(unsafe { dst.put(rc) })
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 rc = unsafe { src_ptr.get::<Rc<T>>() };
33            match Rc::try_unwrap(rc.clone()) {
34                Ok(t) => Ok(unsafe { dst.put(t) }),
35                Err(_) => Err(TryIntoInnerError::Unavailable),
36            }
37        }
38
39        unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
40            src_ptr: PtrConst<'src>,
41        ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
42            let rc = unsafe { src_ptr.get::<Rc<T>>() };
43            Ok(PtrConst::new(&**rc))
44        }
45
46        let mut vtable = value_vtable!(alloc::rc::Rc<T>, |f, opts| {
47            write!(f, "{}", Self::SHAPE.type_identifier)?;
48            if let Some(opts) = opts.for_children() {
49                write!(f, "<")?;
50                T::SHAPE.vtable.type_name()(f, opts)?;
51                write!(f, ">")?;
52            } else {
53                write!(f, "<…>")?;
54            }
55            Ok(())
56        });
57        {
58            let vtable = vtable.sized_mut().unwrap();
59            vtable.try_from = || Some(try_from::<T>);
60            vtable.try_into_inner = || Some(try_into_inner::<T>);
61            vtable.try_borrow_inner = || Some(try_borrow_inner::<T>);
62        }
63        vtable
64    };
65
66    const SHAPE: &'static crate::Shape = &const {
67        // Function to return inner type's shape
68        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
69            T::SHAPE
70        }
71
72        crate::Shape::builder_for_sized::<Self>()
73            .type_identifier("Rc")
74            .type_params(&[crate::TypeParam {
75                name: "T",
76                shape: || T::SHAPE,
77            }])
78            .ty(Type::User(UserType::Opaque))
79            .def(Def::Pointer(
80                PointerDef::builder()
81                    .pointee(|| T::SHAPE)
82                    .flags(PointerFlags::EMPTY)
83                    .known(KnownPointer::Rc)
84                    .weak(|| <Weak<T> as Facet>::SHAPE)
85                    .vtable(
86                        &const {
87                            PointerVTable::builder()
88                                .borrow_fn(|this| {
89                                    let ptr = Self::as_ptr(unsafe { this.get() });
90                                    PtrConst::new(ptr).into()
91                                })
92                                .new_into_fn(|this, ptr| {
93                                    let t = unsafe { ptr.read::<T>() };
94                                    let rc = Rc::new(t);
95                                    unsafe { this.put(rc) }
96                                })
97                                .downgrade_into_fn(|strong, weak| unsafe {
98                                    weak.put(Rc::downgrade(strong.get::<Self>()))
99                                })
100                                .build()
101                        },
102                    )
103                    .build(),
104            ))
105            .inner(inner_shape::<T>)
106            .build()
107    };
108}
109
110unsafe impl<'a> Facet<'a> for Rc<str> {
111    const VTABLE: &'static ValueVTable = &const {
112        value_vtable!(alloc::rc::Rc<str>, |f, opts| {
113            write!(f, "{}", Self::SHAPE.type_identifier)?;
114            if let Some(opts) = opts.for_children() {
115                write!(f, "<")?;
116                (str::SHAPE.vtable.type_name())(f, opts)?;
117                write!(f, ">")?;
118            } else {
119                write!(f, "<…>")?;
120            }
121            Ok(())
122        })
123    };
124
125    const SHAPE: &'static crate::Shape = &const {
126        // Function to return inner type's shape
127        fn inner_shape() -> &'static Shape {
128            str::SHAPE
129        }
130
131        crate::Shape::builder_for_sized::<Self>()
132            .type_identifier("Rc")
133            .type_params(&[crate::TypeParam {
134                name: "T",
135                shape: || str::SHAPE,
136            }])
137            .ty(Type::User(UserType::Opaque))
138            .def(Def::Pointer(
139                PointerDef::builder()
140                    .pointee(|| str::SHAPE)
141                    .flags(PointerFlags::EMPTY)
142                    .known(KnownPointer::Rc)
143                    .weak(|| <Weak<str> as Facet>::SHAPE)
144                    .vtable(
145                        &const {
146                            PointerVTable::builder()
147                                .borrow_fn(|this| unsafe {
148                                    let concrete = this.get::<Rc<str>>();
149                                    let s: &str = concrete;
150                                    PtrConstWide::new(&raw const *s).into()
151                                })
152                                .new_into_fn(|_this, _ptr| todo!())
153                                .downgrade_into_fn(|_strong, _weak| todo!())
154                                .build()
155                        },
156                    )
157                    .build(),
158            ))
159            .inner(inner_shape)
160            .build()
161    };
162}
163
164unsafe impl<'a, T: Facet<'a>> Facet<'a> for Weak<T> {
165    const VTABLE: &'static ValueVTable = &const {
166        value_vtable!(alloc::rc::Weak<T>, |f, opts| {
167            write!(f, "{}", Self::SHAPE.type_identifier)?;
168            if let Some(opts) = opts.for_children() {
169                write!(f, "<")?;
170                T::SHAPE.vtable.type_name()(f, opts)?;
171                write!(f, ">")?;
172            } else {
173                write!(f, "<…>")?;
174            }
175            Ok(())
176        })
177    };
178
179    const SHAPE: &'static crate::Shape = &const {
180        // Function to return inner type's shape
181        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
182            T::SHAPE
183        }
184
185        crate::Shape::builder_for_sized::<Self>()
186            .type_identifier("Weak")
187            .type_params(&[crate::TypeParam {
188                name: "T",
189                shape: || T::SHAPE,
190            }])
191            .ty(Type::User(UserType::Opaque))
192            .def(Def::Pointer(
193                PointerDef::builder()
194                    .pointee(|| T::SHAPE)
195                    .flags(PointerFlags::WEAK)
196                    .known(KnownPointer::RcWeak)
197                    .strong(|| <Rc<T> as Facet>::SHAPE)
198                    .vtable(
199                        &const {
200                            PointerVTable::builder()
201                                .upgrade_into_fn(|weak, strong| unsafe {
202                                    Some(strong.put(weak.get::<Self>().upgrade()?))
203                                })
204                                .build()
205                        },
206                    )
207                    .build(),
208            ))
209            .inner(inner_shape::<T>)
210            .build()
211    };
212}
213
214unsafe impl<'a> Facet<'a> for Weak<str> {
215    const VTABLE: &'static ValueVTable = &const {
216        value_vtable!(alloc::rc::Weak<str>, |f, opts| {
217            write!(f, "{}", Self::SHAPE.type_identifier)?;
218            if let Some(opts) = opts.for_children() {
219                write!(f, "<")?;
220                (str::SHAPE.vtable.type_name())(f, opts)?;
221                write!(f, ">")?;
222            } else {
223                write!(f, "<…>")?;
224            }
225            Ok(())
226        })
227    };
228
229    const SHAPE: &'static crate::Shape = &const {
230        // Function to return inner type's shape
231        fn inner_shape() -> &'static Shape {
232            str::SHAPE
233        }
234
235        crate::Shape::builder_for_sized::<Self>()
236            .type_identifier("Weak")
237            .type_params(&[crate::TypeParam {
238                name: "T",
239                shape: || str::SHAPE,
240            }])
241            .ty(Type::User(UserType::Opaque))
242            .def(Def::Pointer(
243                PointerDef::builder()
244                    .pointee(|| str::SHAPE)
245                    .flags(PointerFlags::WEAK)
246                    .known(KnownPointer::RcWeak)
247                    .strong(|| <Rc<str> as Facet>::SHAPE)
248                    .vtable(
249                        &const {
250                            PointerVTable::builder()
251                                .upgrade_into_fn(|_weak, _strong| todo!())
252                                .build()
253                        },
254                    )
255                    .build(),
256            ))
257            .inner(inner_shape)
258            .build()
259    };
260}
261
262#[cfg(test)]
263mod tests {
264    use alloc::rc::{Rc, Weak as RcWeak};
265    use alloc::string::String;
266
267    use super::*;
268
269    #[test]
270    fn test_rc_type_params() {
271        let [type_param_1] = <Rc<i32>>::SHAPE.type_params else {
272            panic!("Rc<T> should only have 1 type param")
273        };
274        assert_eq!(type_param_1.shape(), i32::SHAPE);
275    }
276
277    #[test]
278    fn test_rc_vtable_1_new_borrow_drop() {
279        facet_testhelpers::setup();
280
281        let rc_shape = <Rc<String>>::SHAPE;
282        let rc_def = rc_shape
283            .def
284            .into_pointer()
285            .expect("Rc<T> should have a smart pointer definition");
286
287        // Allocate memory for the Rc
288        let rc_uninit_ptr = rc_shape.allocate().unwrap();
289
290        // Get the function pointer for creating a new Rc from a value
291        let new_into_fn = rc_def
292            .vtable
293            .new_into_fn
294            .expect("Rc<T> should have new_into_fn");
295
296        // Create the value and initialize the Rc
297        let mut value = String::from("example");
298        let rc_ptr = unsafe { new_into_fn(rc_uninit_ptr, PtrMut::new(&raw mut value)) };
299        // The value now belongs to the Rc, prevent its drop
300        core::mem::forget(value);
301
302        // Get the function pointer for borrowing the inner value
303        let borrow_fn = rc_def
304            .vtable
305            .borrow_fn
306            .expect("Rc<T> should have borrow_fn");
307
308        // Borrow the inner value and check it
309        let borrowed_ptr = unsafe { borrow_fn(rc_ptr.as_const()) };
310        // SAFETY: borrowed_ptr points to a valid String within the Rc
311        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
312
313        // Get the function pointer for dropping the Rc
314        let drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)()
315            .expect("Rc<T> should have drop_in_place");
316
317        // Drop the Rc in place
318        // SAFETY: rc_ptr points to a valid Rc<String>
319        unsafe { drop_fn(rc_ptr) };
320
321        // Deallocate the memory
322        // SAFETY: rc_ptr was allocated by rc_shape and is now dropped (but memory is still valid)
323        unsafe { rc_shape.deallocate_mut(rc_ptr).unwrap() };
324    }
325
326    #[test]
327    fn test_rc_vtable_2_downgrade_upgrade_drop() {
328        facet_testhelpers::setup();
329
330        let rc_shape = <Rc<String>>::SHAPE;
331        let rc_def = rc_shape
332            .def
333            .into_pointer()
334            .expect("Rc<T> should have a smart pointer definition");
335
336        let weak_shape = <RcWeak<String>>::SHAPE;
337        let weak_def = weak_shape
338            .def
339            .into_pointer()
340            .expect("RcWeak<T> should have a smart pointer definition");
341
342        // 1. Create the first Rc (rc1)
343        let rc1_uninit_ptr = rc_shape.allocate().unwrap();
344        let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
345        let mut value = String::from("example");
346        let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrMut::new(&raw mut value)) };
347        core::mem::forget(value); // Value now owned by rc1
348
349        // 2. Downgrade rc1 to create a weak pointer (weak1)
350        let weak1_uninit_ptr = weak_shape.allocate().unwrap();
351        let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
352        // SAFETY: rc1_ptr points to a valid Rc, weak1_uninit_ptr is allocated for a Weak
353        let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
354
355        // 3. Upgrade weak1 to create a second Rc (rc2)
356        let rc2_uninit_ptr = rc_shape.allocate().unwrap();
357        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
358        // SAFETY: weak1_ptr points to a valid Weak, rc2_uninit_ptr is allocated for an Rc.
359        // Upgrade should succeed as rc1 still exists.
360        let rc2_ptr = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) }
361            .expect("Upgrade should succeed while original Rc exists");
362
363        // Check the content of the upgraded Rc
364        let borrow_fn = rc_def.vtable.borrow_fn.unwrap();
365        // SAFETY: rc2_ptr points to a valid Rc<String>
366        let borrowed_ptr = unsafe { borrow_fn(rc2_ptr.as_const()) };
367        // SAFETY: borrowed_ptr points to a valid String
368        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
369
370        // 4. Drop everything and free memory
371        let rc_drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
372        let weak_drop_fn = (weak_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
373
374        unsafe {
375            // Drop Rcs
376            rc_drop_fn(rc1_ptr);
377            rc_shape.deallocate_mut(rc1_ptr).unwrap();
378            rc_drop_fn(rc2_ptr);
379            rc_shape.deallocate_mut(rc2_ptr).unwrap();
380
381            // Drop Weak
382            weak_drop_fn(weak1_ptr);
383            weak_shape.deallocate_mut(weak1_ptr).unwrap();
384        }
385    }
386
387    #[test]
388    fn test_rc_vtable_3_downgrade_drop_try_upgrade() {
389        facet_testhelpers::setup();
390
391        let rc_shape = <Rc<String>>::SHAPE;
392        let rc_def = rc_shape
393            .def
394            .into_pointer()
395            .expect("Rc<T> should have a smart pointer definition");
396
397        let weak_shape = <RcWeak<String>>::SHAPE;
398        let weak_def = weak_shape
399            .def
400            .into_pointer()
401            .expect("RcWeak<T> should have a smart pointer definition");
402
403        // 1. Create the strong Rc (rc1)
404        let rc1_uninit_ptr = rc_shape.allocate().unwrap();
405        let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
406        let mut value = String::from("example");
407        let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrMut::new(&raw mut value)) };
408        core::mem::forget(value);
409
410        // 2. Downgrade rc1 to create a weak pointer (weak1)
411        let weak1_uninit_ptr = weak_shape.allocate().unwrap();
412        let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
413        // SAFETY: rc1_ptr is valid, weak1_uninit_ptr is allocated for Weak
414        let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
415
416        // 3. Drop and free the strong pointer (rc1)
417        let rc_drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
418        unsafe {
419            rc_drop_fn(rc1_ptr);
420            rc_shape.deallocate_mut(rc1_ptr).unwrap();
421        }
422
423        // 4. Attempt to upgrade the weak pointer (weak1)
424        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
425        let rc2_uninit_ptr = rc_shape.allocate().unwrap();
426        // SAFETY: weak1_ptr is valid (though points to dropped data), rc2_uninit_ptr is allocated for Rc
427        let upgrade_result = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) };
428
429        // Assert that the upgrade failed
430        assert!(
431            upgrade_result.is_none(),
432            "Upgrade should fail after the strong Rc is dropped"
433        );
434
435        // 5. Clean up: Deallocate the memory intended for the failed upgrade and drop/deallocate the weak pointer
436        let weak_drop_fn = (weak_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
437        unsafe {
438            // Deallocate the *uninitialized* memory allocated for the failed upgrade attempt
439            rc_shape.deallocate_uninit(rc2_uninit_ptr).unwrap();
440
441            // Drop and deallocate the weak pointer
442            weak_drop_fn(weak1_ptr);
443            weak_shape.deallocate_mut(weak1_ptr).unwrap();
444        }
445    }
446}