twizzler/alloc/
invbox.rs

1use twizzler_rt_abi::object::ObjectHandle;
2
3use super::{Allocator, OwnedGlobalPtr};
4use crate::{
5    marker::Invariant,
6    ptr::{GlobalPtr, InvPtr, Ref},
7};
8
9pub struct InvBox<T: Invariant, Alloc: Allocator> {
10    raw: InvPtr<T>,
11    alloc: Alloc,
12}
13
14impl<T: Invariant, Alloc: Allocator> InvBox<T, Alloc> {
15    pub unsafe fn from_invptr(raw: InvPtr<T>, alloc: Alloc) -> Self {
16        Self { raw, alloc }
17    }
18
19    pub fn new_in(tx: impl AsRef<ObjectHandle>, val: T, alloc: Alloc) -> crate::Result<Self> {
20        let p = alloc.alloc_with(|r| Ok(r.write(val)))?;
21        let ogp = unsafe { OwnedGlobalPtr::from_global(p.cast(), alloc) };
22        Self::from_in(tx, ogp)
23    }
24
25    pub fn from_in(
26        tx: impl AsRef<ObjectHandle>,
27        ogp: OwnedGlobalPtr<T, Alloc>,
28    ) -> crate::Result<Self> {
29        let raw = InvPtr::new(tx, ogp.global())?;
30        Ok(Self {
31            raw,
32            alloc: ogp.allocator().clone(),
33        })
34    }
35
36    pub fn resolve(&self) -> Ref<'_, T> {
37        unsafe { self.raw.resolve() }
38    }
39
40    pub fn global(&self) -> GlobalPtr<T> {
41        self.raw.global()
42    }
43
44    pub fn as_ptr(&self) -> &InvPtr<T> {
45        &self.raw
46    }
47
48    pub fn alloc(&self) -> &Alloc {
49        &self.alloc
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use twizzler_derive::BaseType;
56
57    use super::InvBox;
58    use crate::{
59        alloc::arena::{ArenaAllocator, ArenaObject},
60        object::{ObjectBuilder, TypedObject},
61    };
62
63    #[derive(BaseType)]
64    struct Foo {
65        x: InvBox<u32, ArenaAllocator>,
66    }
67
68    #[test]
69    fn box_simple() {
70        let arena = ArenaObject::new(ObjectBuilder::default()).unwrap();
71        let alloc = arena.allocator();
72        let mut tx = arena.into_tx().unwrap();
73        let foo = tx
74            .alloc(Foo {
75                x: InvBox::new_in(&tx, 3, alloc).unwrap(),
76            })
77            .unwrap();
78
79        let base = foo.resolve();
80        assert_eq!(*base.x.resolve(), 3);
81    }
82
83    #[test]
84    fn box_alloc_builder() {
85        let alloc = ArenaObject::new(ObjectBuilder::default()).unwrap();
86        let foo = alloc
87            .alloc_inplace(|tx| {
88                let foo = Foo {
89                    x: InvBox::new_in(&tx, 3, alloc.allocator()).unwrap(),
90                };
91                Ok(tx.write(foo))
92            })
93            .unwrap();
94        let foo = foo.resolve();
95        assert_eq!(*foo.x.resolve(), 3);
96    }
97
98    #[test]
99    fn box_simple_builder() {
100        let builder = ObjectBuilder::<Foo>::default();
101        let alloc = ArenaObject::new(ObjectBuilder::default()).unwrap();
102        let obj = builder
103            .build_inplace(|tx| {
104                let x = InvBox::new_in(&tx, 3, alloc.allocator()).unwrap();
105                tx.write(Foo { x })
106            })
107            .unwrap();
108        let base = obj.base();
109        assert_eq!(*base.x.resolve(), 3);
110        // Do this multiple times to check that the cache works as well.
111        assert_eq!(*base.x.resolve(), 3);
112        assert_eq!(*base.x.resolve(), 3);
113        assert_eq!(*base.x.resolve(), 3);
114    }
115}