• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 14673999656

25 Apr 2025 09:38PM UTC coverage: 57.882% (+0.2%) from 57.71%
14673999656

push

github

fasterthanlime
No eprintln for you

6657 of 11501 relevant lines covered (57.88%)

72.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.77
/facet-core/src/impls_alloc/smartptr.rs
1
use core::alloc::Layout;
2

3
use crate::{
4
    ConstTypeId, Def, Facet, KnownSmartPointer, Opaque, PtrConst, PtrMut, PtrUninit, Shape,
5
    SmartPointerDef, SmartPointerFlags, SmartPointerVTable, TryBorrowInnerError, TryFromError,
6
    TryIntoInnerError, value_vtable,
7
};
8

9
unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::sync::Arc<T> {
10
    const SHAPE: &'static crate::Shape = &const {
11
        // Define the functions for transparent conversion between Arc<T> and T
12
        unsafe fn try_from<'a, 'src, 'dst, T: Facet<'a>>(
1✔
13
            src_ptr: PtrConst<'src>,
1✔
14
            src_shape: &'static Shape,
1✔
15
            dst: PtrUninit<'dst>,
1✔
16
        ) -> Result<PtrMut<'dst>, TryFromError> {
1✔
17
            if src_shape.id != T::SHAPE.id {
1✔
18
                return Err(TryFromError::UnsupportedSourceShape {
×
19
                    src_shape,
×
20
                    expected: &[T::SHAPE],
×
21
                });
×
22
            }
1✔
23
            let t = unsafe { src_ptr.read::<T>() };
1✔
24
            let arc = alloc::sync::Arc::new(t);
1✔
25
            Ok(unsafe { dst.put(arc) })
1✔
26
        }
1✔
27

28
        unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
×
29
            src_ptr: PtrConst<'src>,
×
30
            dst: PtrUninit<'dst>,
×
31
        ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
×
32
            let arc = unsafe { src_ptr.get::<alloc::sync::Arc<T>>() };
×
33
            match alloc::sync::Arc::try_unwrap(arc.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 arc = unsafe { src_ptr.get::<alloc::sync::Arc<T>>() };
×
43
            Ok(PtrConst::new(&**arc))
×
44
        }
×
45

46
        // Function to return inner type's shape
47
        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
2✔
48
            T::SHAPE
2✔
49
        }
2✔
50

51
        crate::Shape::builder()
52
            .id(ConstTypeId::of::<Self>())
53
            .layout(Layout::new::<Self>())
54
            .type_params(&[crate::TypeParam {
55
                name: "T",
56
                shape: || T::SHAPE,
2✔
57
            }])
58
            .def(Def::SmartPointer(
59
                SmartPointerDef::builder()
60
                    .pointee(T::SHAPE)
61
                    .flags(SmartPointerFlags::ATOMIC)
62
                    .known(KnownSmartPointer::Arc)
63
                    .weak(|| <alloc::sync::Weak<T> as Facet>::SHAPE)
×
64
                    .vtable(
65
                        &const {
66
                            SmartPointerVTable::builder()
67
                                .borrow_fn(|this| {
2✔
68
                                    let ptr = Self::as_ptr(unsafe { this.get() });
2✔
69
                                    PtrConst::new(ptr)
2✔
70
                                })
2✔
71
                                .new_into_fn(|this, ptr| {
3✔
72
                                    let t = unsafe { ptr.read::<T>() };
3✔
73
                                    let arc = alloc::sync::Arc::new(t);
3✔
74
                                    unsafe { this.put(arc) }
3✔
75
                                })
3✔
76
                                .downgrade_into_fn(|strong, weak| unsafe {
2✔
77
                                    weak.put(alloc::sync::Arc::downgrade(strong.get::<Self>()))
2✔
78
                                })
2✔
79
                                .build()
80
                        },
81
                    )
82
                    .build(),
83
            ))
84
            .vtable(
85
                &const {
86
                    let mut vtable =
87
                        value_vtable!(alloc::sync::Arc<T>, |f, _opts| write!(f, "Arc"));
×
88
                    vtable.try_from = Some(try_from::<T>);
89
                    vtable.try_into_inner = Some(try_into_inner::<T>);
90
                    vtable.try_borrow_inner = Some(try_borrow_inner::<T>);
91
                    vtable.drop_in_place =
92
                        Some(|ptr| unsafe { ptr.drop_in_place::<alloc::sync::Arc<T>>() });
4✔
93
                    vtable
94
                },
95
            )
96
            .inner(inner_shape::<T>)
97
            .build()
98
    };
99
}
100

101
unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::sync::Weak<T> {
102
    const SHAPE: &'static crate::Shape = &const {
103
        // Function to return inner type's shape
104
        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
×
105
            T::SHAPE
×
106
        }
×
107

108
        crate::Shape::builder()
109
            .id(ConstTypeId::of::<Self>())
110
            .layout(Layout::new::<Self>())
111
            .type_params(&[crate::TypeParam {
112
                name: "T",
113
                shape: || T::SHAPE,
1✔
114
            }])
115
            .def(Def::SmartPointer(
116
                SmartPointerDef::builder()
117
                    .pointee(T::SHAPE)
118
                    .flags(SmartPointerFlags::ATOMIC.union(SmartPointerFlags::WEAK))
119
                    .known(KnownSmartPointer::ArcWeak)
120
                    .strong(|| <alloc::sync::Arc<T> as Facet>::SHAPE)
×
121
                    .vtable(
122
                        &const {
123
                            SmartPointerVTable::builder()
124
                                .upgrade_into_fn(|weak, strong| unsafe {
2✔
125
                                    Some(strong.put(weak.get::<Self>().upgrade()?))
2✔
126
                                })
2✔
127
                                .build()
128
                        },
129
                    )
130
                    .build(),
131
            ))
132
            .vtable(
133
                &const {
134
                    let mut vtable =
135
                        value_vtable!(alloc::sync::Arc<T>, |f, _opts| write!(f, "Arc"));
×
136
                    vtable.drop_in_place =
137
                        Some(|ptr| unsafe { ptr.drop_in_place::<alloc::sync::Weak<T>>() });
2✔
138

139
                    vtable
140
                },
141
            )
142
            .inner(inner_shape::<T>)
143
            .build()
144
    };
145
}
146

147
unsafe impl<'a, T: 'a> Facet<'a> for Opaque<alloc::sync::Arc<T>> {
148
    const SHAPE: &'static crate::Shape = &const {
149
        crate::Shape::builder()
150
            .id(ConstTypeId::of::<Self>())
151
            .layout(Layout::new::<Self>())
152
            .def(Def::SmartPointer(
153
                SmartPointerDef::builder()
154
                    .flags(SmartPointerFlags::ATOMIC)
155
                    .known(KnownSmartPointer::Arc)
156
                    .vtable(
157
                        &const {
158
                            SmartPointerVTable::builder()
159
                                .borrow_fn(|this| {
×
160
                                    let ptr = alloc::sync::Arc::<T>::as_ptr(unsafe { this.get() });
×
161
                                    PtrConst::new(ptr)
×
162
                                })
×
163
                                .new_into_fn(|this, ptr| {
×
164
                                    let t = unsafe { ptr.read::<T>() };
×
165
                                    let arc = alloc::sync::Arc::new(t);
×
166
                                    unsafe { this.put(arc) }
×
167
                                })
×
168
                                .build()
169
                        },
170
                    )
171
                    .build(),
172
            ))
173
            .vtable(&const { value_vtable!(alloc::sync::Arc<T>, |f, _opts| write!(f, "Arc")) })
1✔
174
            .build()
175
    };
176
}
177

178
unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::rc::Rc<T> {
179
    const SHAPE: &'static crate::Shape = &const {
180
        // Define the functions for transparent conversion between Rc<T> and T
181
        unsafe fn try_from<'a, 'src, 'dst, T: Facet<'a>>(
×
182
            src_ptr: PtrConst<'src>,
×
183
            src_shape: &'static Shape,
×
184
            dst: PtrUninit<'dst>,
×
185
        ) -> Result<PtrMut<'dst>, TryFromError> {
×
186
            if src_shape.id != T::SHAPE.id {
×
187
                return Err(TryFromError::UnsupportedSourceShape {
×
188
                    src_shape,
×
189
                    expected: &[T::SHAPE],
×
190
                });
×
191
            }
×
192
            let t = unsafe { src_ptr.read::<T>() };
×
193
            let rc = alloc::rc::Rc::new(t);
×
194
            Ok(unsafe { dst.put(rc) })
×
195
        }
×
196

197
        unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
×
198
            src_ptr: PtrConst<'src>,
×
199
            dst: PtrUninit<'dst>,
×
200
        ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
×
201
            let rc = unsafe { src_ptr.get::<alloc::rc::Rc<T>>() };
×
202
            match alloc::rc::Rc::try_unwrap(rc.clone()) {
×
203
                Ok(t) => Ok(unsafe { dst.put(t) }),
×
204
                Err(_) => Err(TryIntoInnerError::Unavailable),
×
205
            }
206
        }
×
207

208
        unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
×
209
            src_ptr: PtrConst<'src>,
×
210
        ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
×
211
            let rc = unsafe { src_ptr.get::<alloc::rc::Rc<T>>() };
×
212
            Ok(PtrConst::new(&**rc))
×
213
        }
×
214

215
        // Function to return inner type's shape
216
        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
×
217
            T::SHAPE
×
218
        }
×
219

220
        crate::Shape::builder()
221
            .id(ConstTypeId::of::<Self>())
222
            .layout(Layout::new::<Self>())
223
            .type_params(&[crate::TypeParam {
224
                name: "T",
225
                shape: || T::SHAPE,
1✔
226
            }])
227
            .def(Def::SmartPointer(
228
                SmartPointerDef::builder()
229
                    .pointee(T::SHAPE)
230
                    .flags(SmartPointerFlags::EMPTY)
231
                    .known(KnownSmartPointer::Rc)
232
                    .weak(|| <alloc::rc::Weak<T> as Facet>::SHAPE)
×
233
                    .vtable(
234
                        &const {
235
                            SmartPointerVTable::builder()
236
                                .borrow_fn(|this| {
2✔
237
                                    let ptr = Self::as_ptr(unsafe { this.get() });
2✔
238
                                    PtrConst::new(ptr)
2✔
239
                                })
2✔
240
                                .new_into_fn(|this, ptr| {
3✔
241
                                    let t = unsafe { ptr.read::<T>() };
3✔
242
                                    let rc = alloc::rc::Rc::new(t);
3✔
243
                                    unsafe { this.put(rc) }
3✔
244
                                })
3✔
245
                                .downgrade_into_fn(|strong, weak| unsafe {
2✔
246
                                    weak.put(alloc::rc::Rc::downgrade(strong.get::<Self>()))
2✔
247
                                })
2✔
248
                                .build()
249
                        },
250
                    )
251
                    .build(),
252
            ))
253
            .vtable(
254
                &const {
255
                    let mut vtable = value_vtable!(alloc::rc::Rc<T>, |f, _opts| write!(f, "Rc"));
×
256
                    vtable.try_from = Some(try_from::<T>);
257
                    vtable.try_into_inner = Some(try_into_inner::<T>);
258
                    vtable.try_borrow_inner = Some(try_borrow_inner::<T>);
259
                    vtable.drop_in_place =
260
                        Some(|ptr| unsafe { ptr.drop_in_place::<alloc::rc::Rc<T>>() });
4✔
261
                    vtable
262
                },
263
            )
264
            .inner(inner_shape::<T>)
265
            .build()
266
    };
267
}
268

269
unsafe impl<'a, T: Facet<'a>> Facet<'a> for alloc::rc::Weak<T> {
270
    const SHAPE: &'static crate::Shape = &const {
271
        // Function to return inner type's shape
272
        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
×
273
            T::SHAPE
×
274
        }
×
275

276
        crate::Shape::builder()
277
            .id(ConstTypeId::of::<Self>())
278
            .layout(Layout::new::<Self>())
279
            .type_params(&[crate::TypeParam {
280
                name: "T",
281
                shape: || T::SHAPE,
×
282
            }])
283
            .def(Def::SmartPointer(
284
                SmartPointerDef::builder()
285
                    .pointee(T::SHAPE)
286
                    .flags(SmartPointerFlags::WEAK)
287
                    .known(KnownSmartPointer::RcWeak)
288
                    .strong(|| <alloc::rc::Rc<T> as Facet>::SHAPE)
×
289
                    .vtable(
290
                        &const {
291
                            SmartPointerVTable::builder()
292
                                .upgrade_into_fn(|weak, strong| unsafe {
2✔
293
                                    Some(strong.put(weak.get::<Self>().upgrade()?))
2✔
294
                                })
2✔
295
                                .build()
296
                        },
297
                    )
298
                    .build(),
299
            ))
300
            .vtable(
301
                &const {
302
                    let mut vtable =
303
                        value_vtable!(alloc::rc::Weak<T>, |f, _opts| write!(f, "Weak")); // Note: Weak<T> for type name
×
304
                    vtable.drop_in_place =
305
                        Some(|ptr| unsafe { ptr.drop_in_place::<alloc::rc::Weak<T>>() });
2✔
306
                    vtable
307
                },
308
            )
309
            .inner(inner_shape::<T>)
310
            .build()
311
    };
312
}
313

314
unsafe impl<'a, T: 'a> Facet<'a> for Opaque<alloc::rc::Rc<T>> {
315
    const SHAPE: &'static crate::Shape = &const {
316
        crate::Shape::builder()
317
            .id(ConstTypeId::of::<Self>())
318
            .layout(Layout::new::<Self>())
319
            .def(Def::SmartPointer(
320
                SmartPointerDef::builder()
321
                    .known(KnownSmartPointer::Rc)
322
                    .vtable(
323
                        &const {
324
                            SmartPointerVTable::builder()
325
                                .borrow_fn(|this| {
×
326
                                    let ptr = alloc::rc::Rc::<T>::as_ptr(unsafe { this.get() });
×
327
                                    PtrConst::new(ptr)
×
328
                                })
×
329
                                .new_into_fn(|this, ptr| {
×
330
                                    let t = unsafe { ptr.read::<T>() };
×
331
                                    let rc = alloc::rc::Rc::new(t);
×
332
                                    unsafe { this.put(rc) }
×
333
                                })
×
334
                                .build()
335
                        },
336
                    )
337
                    .build(),
338
            ))
339
            .vtable(&const { value_vtable!(alloc::rc::Rc<T>, |f, _opts| write!(f, "Rc")) })
×
340
            .build()
341
    };
342
}
343

344
#[cfg(test)]
345
mod tests {
346
    use alloc::rc::{Rc, Weak as RcWeak};
347
    use alloc::string::String;
348
    use alloc::sync::{Arc, Weak as ArcWeak};
349

350
    use super::*;
351

352
    #[test]
353
    fn test_arc_type_params() {
1✔
354
        let [type_param_1] = <Arc<i32>>::SHAPE.type_params else {
1✔
355
            panic!("Arc<T> should only have 1 type param")
×
356
        };
357
        assert_eq!(type_param_1.shape(), i32::SHAPE);
1✔
358
    }
1✔
359

360
    #[test]
361
    fn test_arc_vtable_1_new_borrow_drop() -> eyre::Result<()> {
1✔
362
        facet_testhelpers::setup();
1✔
363

1✔
364
        let arc_shape = <Arc<String>>::SHAPE;
1✔
365
        let arc_def = arc_shape
1✔
366
            .def
1✔
367
            .into_smart_pointer()
1✔
368
            .expect("Arc<T> should have a smart pointer definition");
1✔
369

370
        // Allocate memory for the Arc
371
        let arc_uninit_ptr = arc_shape.allocate()?;
1✔
372

373
        // Get the function pointer for creating a new Arc from a value
374
        let new_into_fn = arc_def
1✔
375
            .vtable
1✔
376
            .new_into_fn
1✔
377
            .expect("Arc<T> should have new_into_fn");
1✔
378

1✔
379
        // Create the value and initialize the Arc
1✔
380
        let value = String::from("example");
1✔
381
        let arc_ptr = unsafe { new_into_fn(arc_uninit_ptr, PtrConst::new(&raw const value)) };
1✔
382
        // The value now belongs to the Arc, prevent its drop
1✔
383
        core::mem::forget(value);
1✔
384

1✔
385
        // Get the function pointer for borrowing the inner value
1✔
386
        let borrow_fn = arc_def
1✔
387
            .vtable
1✔
388
            .borrow_fn
1✔
389
            .expect("Arc<T> should have borrow_fn");
1✔
390

1✔
391
        // Borrow the inner value and check it
1✔
392
        let borrowed_ptr = unsafe { borrow_fn(arc_ptr.as_const()) };
1✔
393
        // SAFETY: borrowed_ptr points to a valid String within the Arc
1✔
394
        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
1✔
395

396
        // Get the function pointer for dropping the Arc
397
        let drop_fn = arc_shape
1✔
398
            .vtable
1✔
399
            .drop_in_place
1✔
400
            .expect("Arc<T> should have drop_in_place");
1✔
401

1✔
402
        // Drop the Arc in place
1✔
403
        // SAFETY: arc_ptr points to a valid Arc<String>
1✔
404
        unsafe { drop_fn(arc_ptr) };
1✔
405

1✔
406
        // Deallocate the memory
1✔
407
        // SAFETY: arc_ptr was allocated by arc_shape and is now dropped (but memory is still valid)
1✔
408
        unsafe { arc_shape.deallocate_mut(arc_ptr)? };
1✔
409

410
        Ok(())
1✔
411
    }
1✔
412

413
    #[test]
414
    fn test_arc_vtable_2_downgrade_upgrade_drop() -> eyre::Result<()> {
1✔
415
        facet_testhelpers::setup();
1✔
416

1✔
417
        let arc_shape = <Arc<String>>::SHAPE;
1✔
418
        let arc_def = arc_shape
1✔
419
            .def
1✔
420
            .into_smart_pointer()
1✔
421
            .expect("Arc<T> should have a smart pointer definition");
1✔
422

1✔
423
        let weak_shape = <ArcWeak<String>>::SHAPE;
1✔
424
        let weak_def = weak_shape
1✔
425
            .def
1✔
426
            .into_smart_pointer()
1✔
427
            .expect("ArcWeak<T> should have a smart pointer definition");
1✔
428

429
        // 1. Create the first Arc (arc1)
430
        let arc1_uninit_ptr = arc_shape.allocate()?;
1✔
431
        let new_into_fn = arc_def.vtable.new_into_fn.unwrap();
1✔
432
        let value = String::from("example");
1✔
433
        let arc1_ptr = unsafe { new_into_fn(arc1_uninit_ptr, PtrConst::new(&raw const value)) };
1✔
434
        core::mem::forget(value); // Value now owned by arc1
1✔
435

436
        // 2. Downgrade arc1 to create a weak pointer (weak1)
437
        let weak1_uninit_ptr = weak_shape.allocate()?;
1✔
438
        let downgrade_into_fn = arc_def.vtable.downgrade_into_fn.unwrap();
1✔
439
        // SAFETY: arc1_ptr points to a valid Arc, weak1_uninit_ptr is allocated for a Weak
1✔
440
        let weak1_ptr = unsafe { downgrade_into_fn(arc1_ptr, weak1_uninit_ptr) };
1✔
441

442
        // 3. Upgrade weak1 to create a second Arc (arc2)
443
        let arc2_uninit_ptr = arc_shape.allocate()?;
1✔
444
        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
1✔
445
        // SAFETY: weak1_ptr points to a valid Weak, arc2_uninit_ptr is allocated for an Arc.
1✔
446
        // Upgrade should succeed as arc1 still exists.
1✔
447
        let arc2_ptr = unsafe { upgrade_into_fn(weak1_ptr, arc2_uninit_ptr) }
1✔
448
            .expect("Upgrade should succeed while original Arc exists");
1✔
449

1✔
450
        // Check the content of the upgraded Arc
1✔
451
        let borrow_fn = arc_def.vtable.borrow_fn.unwrap();
1✔
452
        // SAFETY: arc2_ptr points to a valid Arc<String>
1✔
453
        let borrowed_ptr = unsafe { borrow_fn(arc2_ptr.as_const()) };
1✔
454
        // SAFETY: borrowed_ptr points to a valid String
1✔
455
        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
1✔
456

457
        // 4. Drop everything and free memory
458
        let arc_drop_fn = arc_shape.vtable.drop_in_place.unwrap();
1✔
459
        let weak_drop_fn = weak_shape.vtable.drop_in_place.unwrap();
1✔
460

1✔
461
        unsafe {
1✔
462
            // Drop Arcs
1✔
463
            arc_drop_fn(arc1_ptr);
1✔
464
            arc_shape.deallocate_mut(arc1_ptr)?;
1✔
465
            arc_drop_fn(arc2_ptr);
1✔
466
            arc_shape.deallocate_mut(arc2_ptr)?;
1✔
467

468
            // Drop Weak
469
            weak_drop_fn(weak1_ptr);
1✔
470
            weak_shape.deallocate_mut(weak1_ptr)?;
1✔
471
        }
472

473
        Ok(())
1✔
474
    }
1✔
475

476
    #[test]
477
    fn test_arc_vtable_3_downgrade_drop_try_upgrade() -> eyre::Result<()> {
1✔
478
        facet_testhelpers::setup();
1✔
479

1✔
480
        let arc_shape = <Arc<String>>::SHAPE;
1✔
481
        let arc_def = arc_shape
1✔
482
            .def
1✔
483
            .into_smart_pointer()
1✔
484
            .expect("Arc<T> should have a smart pointer definition");
1✔
485

1✔
486
        let weak_shape = <ArcWeak<String>>::SHAPE;
1✔
487
        let weak_def = weak_shape
1✔
488
            .def
1✔
489
            .into_smart_pointer()
1✔
490
            .expect("ArcWeak<T> should have a smart pointer definition");
1✔
491

492
        // 1. Create the strong Arc (arc1)
493
        let arc1_uninit_ptr = arc_shape.allocate()?;
1✔
494
        let new_into_fn = arc_def.vtable.new_into_fn.unwrap();
1✔
495
        let value = String::from("example");
1✔
496
        let arc1_ptr = unsafe { new_into_fn(arc1_uninit_ptr, PtrConst::new(&raw const value)) };
1✔
497
        core::mem::forget(value);
1✔
498

499
        // 2. Downgrade arc1 to create a weak pointer (weak1)
500
        let weak1_uninit_ptr = weak_shape.allocate()?;
1✔
501
        let downgrade_into_fn = arc_def.vtable.downgrade_into_fn.unwrap();
1✔
502
        // SAFETY: arc1_ptr is valid, weak1_uninit_ptr is allocated for Weak
1✔
503
        let weak1_ptr = unsafe { downgrade_into_fn(arc1_ptr, weak1_uninit_ptr) };
1✔
504

1✔
505
        // 3. Drop and free the strong pointer (arc1)
1✔
506
        let arc_drop_fn = arc_shape.vtable.drop_in_place.unwrap();
1✔
507
        unsafe {
1✔
508
            arc_drop_fn(arc1_ptr);
1✔
509
            arc_shape.deallocate_mut(arc1_ptr)?;
1✔
510
        }
511

512
        // 4. Attempt to upgrade the weak pointer (weak1)
513
        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
1✔
514
        let arc2_uninit_ptr = arc_shape.allocate()?;
1✔
515
        // SAFETY: weak1_ptr is valid (though points to dropped data), arc2_uninit_ptr is allocated for Arc
516
        let upgrade_result = unsafe { upgrade_into_fn(weak1_ptr, arc2_uninit_ptr) };
1✔
517

1✔
518
        // Assert that the upgrade failed
1✔
519
        assert!(
1✔
520
            upgrade_result.is_none(),
1✔
521
            "Upgrade should fail after the strong Arc is dropped"
×
522
        );
523

524
        // 5. Clean up: Deallocate the memory intended for the failed upgrade and drop/deallocate the weak pointer
525
        let weak_drop_fn = weak_shape.vtable.drop_in_place.unwrap();
1✔
526
        unsafe {
1✔
527
            // Deallocate the *uninitialized* memory allocated for the failed upgrade attempt
1✔
528
            arc_shape.deallocate_uninit(arc2_uninit_ptr)?;
1✔
529

530
            // Drop and deallocate the weak pointer
531
            weak_drop_fn(weak1_ptr);
1✔
532
            weak_shape.deallocate_mut(weak1_ptr)?;
1✔
533
        }
534

535
        Ok(())
1✔
536
    }
1✔
537

538
    #[test]
539
    fn test_rc_type_params() {
1✔
540
        let [type_param_1] = <Rc<i32>>::SHAPE.type_params else {
1✔
541
            panic!("Rc<T> should only have 1 type param")
×
542
        };
543
        assert_eq!(type_param_1.shape(), i32::SHAPE);
1✔
544
    }
1✔
545

546
    #[test]
547
    fn test_rc_vtable_1_new_borrow_drop() -> eyre::Result<()> {
1✔
548
        facet_testhelpers::setup();
1✔
549

1✔
550
        let rc_shape = <Rc<String>>::SHAPE;
1✔
551
        let rc_def = rc_shape
1✔
552
            .def
1✔
553
            .into_smart_pointer()
1✔
554
            .expect("Rc<T> should have a smart pointer definition");
1✔
555

556
        // Allocate memory for the Rc
557
        let rc_uninit_ptr = rc_shape.allocate()?;
1✔
558

559
        // Get the function pointer for creating a new Rc from a value
560
        let new_into_fn = rc_def
1✔
561
            .vtable
1✔
562
            .new_into_fn
1✔
563
            .expect("Rc<T> should have new_into_fn");
1✔
564

1✔
565
        // Create the value and initialize the Rc
1✔
566
        let value = String::from("example");
1✔
567
        let rc_ptr = unsafe { new_into_fn(rc_uninit_ptr, PtrConst::new(&raw const value)) };
1✔
568
        // The value now belongs to the Rc, prevent its drop
1✔
569
        core::mem::forget(value);
1✔
570

1✔
571
        // Get the function pointer for borrowing the inner value
1✔
572
        let borrow_fn = rc_def
1✔
573
            .vtable
1✔
574
            .borrow_fn
1✔
575
            .expect("Rc<T> should have borrow_fn");
1✔
576

1✔
577
        // Borrow the inner value and check it
1✔
578
        let borrowed_ptr = unsafe { borrow_fn(rc_ptr.as_const()) };
1✔
579
        // SAFETY: borrowed_ptr points to a valid String within the Rc
1✔
580
        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
1✔
581

582
        // Get the function pointer for dropping the Rc
583
        let drop_fn = rc_shape
1✔
584
            .vtable
1✔
585
            .drop_in_place
1✔
586
            .expect("Rc<T> should have drop_in_place");
1✔
587

1✔
588
        // Drop the Rc in place
1✔
589
        // SAFETY: rc_ptr points to a valid Rc<String>
1✔
590
        unsafe { drop_fn(rc_ptr) };
1✔
591

1✔
592
        // Deallocate the memory
1✔
593
        // SAFETY: rc_ptr was allocated by rc_shape and is now dropped (but memory is still valid)
1✔
594
        unsafe { rc_shape.deallocate_mut(rc_ptr)? };
1✔
595

596
        Ok(())
1✔
597
    }
1✔
598

599
    #[test]
600
    fn test_rc_vtable_2_downgrade_upgrade_drop() -> eyre::Result<()> {
1✔
601
        facet_testhelpers::setup();
1✔
602

1✔
603
        let rc_shape = <Rc<String>>::SHAPE;
1✔
604
        let rc_def = rc_shape
1✔
605
            .def
1✔
606
            .into_smart_pointer()
1✔
607
            .expect("Rc<T> should have a smart pointer definition");
1✔
608

1✔
609
        let weak_shape = <RcWeak<String>>::SHAPE;
1✔
610
        let weak_def = weak_shape
1✔
611
            .def
1✔
612
            .into_smart_pointer()
1✔
613
            .expect("RcWeak<T> should have a smart pointer definition");
1✔
614

615
        // 1. Create the first Rc (rc1)
616
        let rc1_uninit_ptr = rc_shape.allocate()?;
1✔
617
        let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
1✔
618
        let value = String::from("example");
1✔
619
        let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrConst::new(&raw const value)) };
1✔
620
        core::mem::forget(value); // Value now owned by rc1
1✔
621

622
        // 2. Downgrade rc1 to create a weak pointer (weak1)
623
        let weak1_uninit_ptr = weak_shape.allocate()?;
1✔
624
        let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
1✔
625
        // SAFETY: rc1_ptr points to a valid Rc, weak1_uninit_ptr is allocated for a Weak
1✔
626
        let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
1✔
627

628
        // 3. Upgrade weak1 to create a second Rc (rc2)
629
        let rc2_uninit_ptr = rc_shape.allocate()?;
1✔
630
        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
1✔
631
        // SAFETY: weak1_ptr points to a valid Weak, rc2_uninit_ptr is allocated for an Rc.
1✔
632
        // Upgrade should succeed as rc1 still exists.
1✔
633
        let rc2_ptr = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) }
1✔
634
            .expect("Upgrade should succeed while original Rc exists");
1✔
635

1✔
636
        // Check the content of the upgraded Rc
1✔
637
        let borrow_fn = rc_def.vtable.borrow_fn.unwrap();
1✔
638
        // SAFETY: rc2_ptr points to a valid Rc<String>
1✔
639
        let borrowed_ptr = unsafe { borrow_fn(rc2_ptr.as_const()) };
1✔
640
        // SAFETY: borrowed_ptr points to a valid String
1✔
641
        assert_eq!(unsafe { borrowed_ptr.get::<String>() }, "example");
1✔
642

643
        // 4. Drop everything and free memory
644
        let rc_drop_fn = rc_shape.vtable.drop_in_place.unwrap();
1✔
645
        let weak_drop_fn = weak_shape.vtable.drop_in_place.unwrap();
1✔
646

1✔
647
        unsafe {
1✔
648
            // Drop Rcs
1✔
649
            rc_drop_fn(rc1_ptr);
1✔
650
            rc_shape.deallocate_mut(rc1_ptr)?;
1✔
651
            rc_drop_fn(rc2_ptr);
1✔
652
            rc_shape.deallocate_mut(rc2_ptr)?;
1✔
653

654
            // Drop Weak
655
            weak_drop_fn(weak1_ptr);
1✔
656
            weak_shape.deallocate_mut(weak1_ptr)?;
1✔
657
        }
658

659
        Ok(())
1✔
660
    }
1✔
661

662
    #[test]
663
    fn test_rc_vtable_3_downgrade_drop_try_upgrade() -> eyre::Result<()> {
1✔
664
        facet_testhelpers::setup();
1✔
665

1✔
666
        let rc_shape = <Rc<String>>::SHAPE;
1✔
667
        let rc_def = rc_shape
1✔
668
            .def
1✔
669
            .into_smart_pointer()
1✔
670
            .expect("Rc<T> should have a smart pointer definition");
1✔
671

1✔
672
        let weak_shape = <RcWeak<String>>::SHAPE;
1✔
673
        let weak_def = weak_shape
1✔
674
            .def
1✔
675
            .into_smart_pointer()
1✔
676
            .expect("RcWeak<T> should have a smart pointer definition");
1✔
677

678
        // 1. Create the strong Rc (rc1)
679
        let rc1_uninit_ptr = rc_shape.allocate()?;
1✔
680
        let new_into_fn = rc_def.vtable.new_into_fn.unwrap();
1✔
681
        let value = String::from("example");
1✔
682
        let rc1_ptr = unsafe { new_into_fn(rc1_uninit_ptr, PtrConst::new(&raw const value)) };
1✔
683
        core::mem::forget(value);
1✔
684

685
        // 2. Downgrade rc1 to create a weak pointer (weak1)
686
        let weak1_uninit_ptr = weak_shape.allocate()?;
1✔
687
        let downgrade_into_fn = rc_def.vtable.downgrade_into_fn.unwrap();
1✔
688
        // SAFETY: rc1_ptr is valid, weak1_uninit_ptr is allocated for Weak
1✔
689
        let weak1_ptr = unsafe { downgrade_into_fn(rc1_ptr, weak1_uninit_ptr) };
1✔
690

1✔
691
        // 3. Drop and free the strong pointer (rc1)
1✔
692
        let rc_drop_fn = rc_shape.vtable.drop_in_place.unwrap();
1✔
693
        unsafe {
1✔
694
            rc_drop_fn(rc1_ptr);
1✔
695
            rc_shape.deallocate_mut(rc1_ptr)?;
1✔
696
        }
697

698
        // 4. Attempt to upgrade the weak pointer (weak1)
699
        let upgrade_into_fn = weak_def.vtable.upgrade_into_fn.unwrap();
1✔
700
        let rc2_uninit_ptr = rc_shape.allocate()?;
1✔
701
        // SAFETY: weak1_ptr is valid (though points to dropped data), rc2_uninit_ptr is allocated for Rc
702
        let upgrade_result = unsafe { upgrade_into_fn(weak1_ptr, rc2_uninit_ptr) };
1✔
703

1✔
704
        // Assert that the upgrade failed
1✔
705
        assert!(
1✔
706
            upgrade_result.is_none(),
1✔
707
            "Upgrade should fail after the strong Rc is dropped"
×
708
        );
709

710
        // 5. Clean up: Deallocate the memory intended for the failed upgrade and drop/deallocate the weak pointer
711
        let weak_drop_fn = weak_shape.vtable.drop_in_place.unwrap();
1✔
712
        unsafe {
1✔
713
            // Deallocate the *uninitialized* memory allocated for the failed upgrade attempt
1✔
714
            rc_shape.deallocate_uninit(rc2_uninit_ptr)?;
1✔
715

716
            // Drop and deallocate the weak pointer
717
            weak_drop_fn(weak1_ptr);
1✔
718
            weak_shape.deallocate_mut(weak1_ptr)?;
1✔
719
        }
720

721
        Ok(())
1✔
722
    }
1✔
723
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc