nanvm_lib/mem/
ref_.rs

1use core::{mem::forget, ops::Deref};
2
3use super::{
4    block::Block, manager::Dealloc, mut_ref::MutRef, object::Object, optional_block::OptionalBlock,
5    optional_ref::OptionalRef, ref_counter_update::RefCounterUpdate,
6};
7
8/// A reference to an object allocated by a memory manager.
9pub type Ref<T, D> = OptionalRef<*const Block<T, D>>;
10
11impl<T: Object, D: Dealloc> Ref<T, D> {
12    pub fn try_to_mut_ref(self) -> Result<MutRef<T, D>, Self> {
13        unsafe {
14            if let Some(ptr) = self.internal().ref_counter_update(RefCounterUpdate::Read) {
15                forget(self);
16                Ok(MutRef::new(ptr as _))
17            } else {
18                Err(self)
19            }
20        }
21    }
22}
23
24impl<T: Object, D: Dealloc> Deref for Ref<T, D> {
25    type Target = T;
26    #[inline(always)]
27    fn deref(&self) -> &T {
28        unsafe { (*self.internal()).object() }
29    }
30}
31
32#[cfg(test)]
33mod test {
34    use core::{alloc::Layout, mem::forget, sync::atomic::AtomicIsize};
35
36    use wasm_bindgen_test::wasm_bindgen_test;
37
38    use crate::mem::{
39        block::Block, block_header::BlockHeader, fixed::Fixed, manager::Dealloc,
40        ref_counter_update::RefCounterUpdate,
41    };
42
43    use super::Ref;
44
45    #[derive(Default)]
46    struct BH();
47
48    #[derive(Debug)]
49    struct M();
50
51    impl Dealloc for M {
52        type BlockHeader = BH;
53        unsafe fn dealloc(_: *mut u8, _: core::alloc::Layout) {
54            panic!()
55        }
56    }
57
58    impl BlockHeader for BH {
59        unsafe fn ref_counter_update(&self, _: RefCounterUpdate) -> isize {
60            panic!()
61        }
62    }
63
64    #[test]
65    #[wasm_bindgen_test]
66    fn test() {
67        let mut buffer: [(); 0] = [];
68        let x = buffer.as_mut_ptr() as *mut Block<Fixed<()>, M>;
69        let y = unsafe { Ref::from_internal(x) };
70        forget(y);
71    }
72
73    #[derive(Debug)]
74    struct M1();
75
76    impl Dealloc for M1 {
77        type BlockHeader = AtomicIsize;
78        unsafe fn dealloc(_: *mut u8, _: Layout) {}
79    }
80
81    #[test]
82    #[wasm_bindgen_test]
83    fn test_1() {
84        let mut buffer: [isize; 1] = [0];
85        let x = buffer.as_mut_ptr() as *mut Block<Fixed<()>, M1>;
86        let p = unsafe { &mut (*x).header };
87        assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 0);
88        {
89            let y = unsafe { Ref::from_internal(x) };
90            assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 0);
91            {
92                let _z = y.clone();
93                assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 1);
94            }
95            assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, 0);
96        }
97        assert_eq!(unsafe { p.ref_counter_update(RefCounterUpdate::Read) }, -1);
98    }
99}