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 unsafe fn try_from<'a, 'shape, 'src, 'dst, T: Facet<'a>>(
13 src_ptr: PtrConst<'src>,
14 src_shape: &'shape Shape<'shape>,
15 dst: PtrUninit<'dst>,
16 ) -> Result<PtrMut<'dst>, TryFromError<'shape>> {
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<'static> = &const {
67 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape<'static> {
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<'static> = &const {
126 fn inner_shape() -> &'static Shape<'static> {
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<'static> = &const {
180 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape<'static> {
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<'static> = &const {
230 fn inner_shape() -> &'static Shape<'static> {
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() -> eyre::Result<()> {
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 let rc_uninit_ptr = rc_shape.allocate()?;
289
290 let new_into_fn = rc_def
292 .vtable
293 .new_into_fn
294 .expect("Rc<T> should have new_into_fn");
295
296 let mut value = String::from("example");
298 let rc_ptr = unsafe { new_into_fn(rc_uninit_ptr, PtrMut::new(&raw mut value)) };
299 core::mem::forget(value);
301
302 let borrow_fn = rc_def
304 .vtable
305 .borrow_fn
306 .expect("Rc<T> should have borrow_fn");
307
308 let borrowed_ptr = unsafe { borrow_fn(rc_ptr.as_const()) };
310 assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
312
313 let drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)()
315 .expect("Rc<T> should have drop_in_place");
316
317 unsafe { drop_fn(rc_ptr) };
320
321 unsafe { rc_shape.deallocate_mut(rc_ptr)? };
324
325 Ok(())
326 }
327
328 #[test]
329 fn test_rc_vtable_2_downgrade_upgrade_drop() -> eyre::Result<()> {
330 facet_testhelpers::setup();
331
332 let rc_shape = <Rc<String>>::SHAPE;
333 let rc_def = rc_shape
334 .def
335 .into_pointer()
336 .expect("Rc<T> should have a smart pointer definition");
337
338 let weak_shape = <RcWeak<String>>::SHAPE;
339 let weak_def = weak_shape
340 .def
341 .into_pointer()
342 .expect("RcWeak<T> should have a smart pointer definition");
343
344 let rc1_uninit_ptr = rc_shape.allocate()?;
346 let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
347 let mut value = String::from("example");
348 let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrMut::new(&raw mut value)) };
349 core::mem::forget(value); let weak1_uninit_ptr = weak_shape.allocate()?;
353 let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
354 let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
356
357 let rc2_uninit_ptr = rc_shape.allocate()?;
359 let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
360 let rc2_ptr = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) }
363 .expect("Upgrade should succeed while original Rc exists");
364
365 let borrow_fn = rc_def.vtable.borrow_fn.unwrap();
367 let borrowed_ptr = unsafe { borrow_fn(rc2_ptr.as_const()) };
369 assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
371
372 let rc_drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
374 let weak_drop_fn = (weak_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
375
376 unsafe {
377 rc_drop_fn(rc1_ptr);
379 rc_shape.deallocate_mut(rc1_ptr)?;
380 rc_drop_fn(rc2_ptr);
381 rc_shape.deallocate_mut(rc2_ptr)?;
382
383 weak_drop_fn(weak1_ptr);
385 weak_shape.deallocate_mut(weak1_ptr)?;
386 }
387
388 Ok(())
389 }
390
391 #[test]
392 fn test_rc_vtable_3_downgrade_drop_try_upgrade() -> eyre::Result<()> {
393 facet_testhelpers::setup();
394
395 let rc_shape = <Rc<String>>::SHAPE;
396 let rc_def = rc_shape
397 .def
398 .into_pointer()
399 .expect("Rc<T> should have a smart pointer definition");
400
401 let weak_shape = <RcWeak<String>>::SHAPE;
402 let weak_def = weak_shape
403 .def
404 .into_pointer()
405 .expect("RcWeak<T> should have a smart pointer definition");
406
407 let rc1_uninit_ptr = rc_shape.allocate()?;
409 let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
410 let mut value = String::from("example");
411 let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrMut::new(&raw mut value)) };
412 core::mem::forget(value);
413
414 let weak1_uninit_ptr = weak_shape.allocate()?;
416 let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
417 let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
419
420 let rc_drop_fn = (rc_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
422 unsafe {
423 rc_drop_fn(rc1_ptr);
424 rc_shape.deallocate_mut(rc1_ptr)?;
425 }
426
427 let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
429 let rc2_uninit_ptr = rc_shape.allocate()?;
430 let upgrade_result = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) };
432
433 assert!(
435 upgrade_result.is_none(),
436 "Upgrade should fail after the strong Rc is dropped"
437 );
438
439 let weak_drop_fn = (weak_shape.vtable.sized().unwrap().drop_in_place)().unwrap();
441 unsafe {
442 rc_shape.deallocate_uninit(rc2_uninit_ptr)?;
444
445 weak_drop_fn(weak1_ptr);
447 weak_shape.deallocate_mut(weak1_ptr)?;
448 }
449
450 Ok(())
451 }
452}