Skip to main content

nanvm_lib/mem/
block.rs

1use core::{alloc::Layout, marker::PhantomData};
2
3use super::{field_layout::FieldLayout, manager::Dealloc, object::Object};
4
5#[repr(transparent)]
6pub struct Block<T: Object, D: Dealloc> {
7    pub header: D::BlockHeader,
8    _0: PhantomData<T>,
9}
10
11impl<T: Object, D: Dealloc> Block<T, D> {
12    const BLOCK_HEADER_LAYOUT: FieldLayout<D::BlockHeader, T> =
13        FieldLayout::align_to(T::OBJECT_ALIGN);
14    #[inline(always)]
15    pub const fn block_layout(object_size: usize) -> Layout {
16        Self::BLOCK_HEADER_LAYOUT.layout(object_size)
17    }
18    pub unsafe fn delete(&mut self) {
19        let object = self.object_mut();
20        let object_size = object.object_size();
21        object.object_drop();
22        D::dealloc(self as *mut _ as *mut u8, Self::block_layout(object_size));
23    }
24    #[inline(always)]
25    pub fn object(&self) -> &T {
26        unsafe { &*Self::BLOCK_HEADER_LAYOUT.to_adjacent(&self.header) }
27    }
28    #[inline(always)]
29    pub fn object_mut(&mut self) -> &mut T {
30        unsafe { &mut *Self::BLOCK_HEADER_LAYOUT.into_adjacent_mut(&mut self.header) }
31    }
32}
33
34#[cfg(test)]
35mod test {
36    use core::{alloc::Layout, cell::Cell, marker::PhantomData};
37
38    use wasm_bindgen_test::wasm_bindgen_test;
39
40    use crate::mem::{
41        block::Block, fixed::Fixed, manager::Dealloc, object::Object,
42        ref_counter_update::RefCounterUpdate,
43    };
44
45    use super::super::block_header::BlockHeader;
46
47    #[derive(Debug)]
48    struct M();
49
50    impl Dealloc for M {
51        type BlockHeader = BH;
52        unsafe fn dealloc(_: *mut u8, _: Layout) {}
53    }
54
55    #[derive(Default)]
56    struct BH();
57
58    impl BlockHeader for BH {
59        unsafe fn ref_counter_update(&self, _: RefCounterUpdate) -> isize {
60            todo!()
61        }
62    }
63
64    #[test]
65    #[wasm_bindgen_test]
66    fn test_0() {
67        assert_eq!(Block::<Fixed<()>, M>::block_layout(0).size(), 0);
68        assert_eq!(Block::<Fixed<()>, M>::block_layout(0).align(), 1);
69        assert_eq!(Block::<Fixed<()>, M>::block_layout(2).size(), 2);
70        assert_eq!(Block::<Fixed<()>, M>::block_layout(2).align(), 1);
71        let mut b = Block::<Fixed<()>, M> {
72            header: BH::default(),
73            _0: Default::default(),
74        };
75        assert_eq!(b.object().object_size(), 0);
76        let x = b.object_mut();
77        assert_eq!(x.object_size(), 0);
78        unsafe { b.delete() };
79    }
80
81    #[test]
82    #[wasm_bindgen_test]
83    fn test() {
84        #[derive(Default)]
85        struct Xbh(Cell<isize>);
86
87        #[derive(Debug)]
88        struct D();
89
90        impl Dealloc for D {
91            type BlockHeader = Xbh;
92            unsafe fn dealloc(_: *mut u8, _: Layout) {}
93        }
94
95        impl BlockHeader for Xbh {
96            unsafe fn ref_counter_update(&self, i: RefCounterUpdate) -> isize {
97                let result = self.0.get();
98                self.0.set(result + i as isize);
99                result
100            }
101        }
102
103        let mut x = Block::<Fixed<()>, D> {
104            header: Xbh::default(),
105            _0: PhantomData,
106        };
107        let p = unsafe { x.header.block::<Fixed<()>, D>() };
108        assert_eq!(p as *mut _, (&mut x) as _);
109        unsafe {
110            assert_eq!(x.header.ref_counter_update(RefCounterUpdate::Read), 0);
111            assert_eq!(x.header.ref_counter_update(RefCounterUpdate::AddRef), 0);
112            assert_eq!(x.header.ref_counter_update(RefCounterUpdate::Read), 1);
113        }
114    }
115}