Skip to main content

memlink_msdk/
ref.rs

1//! Persistent state references for memlink modules, allowing data to persist across calls.
2//!
3//! Provides ArenaRef for storing offsets to values in an arena, enabling
4//! data to survive arena resets across module invocations.
5
6use std::marker::PhantomData;
7use std::ptr;
8
9use crate::arena::Arena;
10
11pub struct ArenaRef<T> {
12    offset: usize,
13    _phantom: PhantomData<T>,
14}
15
16unsafe impl<T: Send> Send for ArenaRef<T> {}
17unsafe impl<T: Sync> Sync for ArenaRef<T> {}
18
19impl<T> ArenaRef<T> {
20    pub fn new(arena: &Arena, value: T) -> Option<Self> {
21        let slot = arena.alloc_with(value)?;
22        let offset = unsafe {
23            (slot as *const T as *const u8)
24                .offset_from(arena.base_ptr() as *const u8) as usize
25        };
26
27        Some(ArenaRef {
28            offset,
29            _phantom: PhantomData,
30        })
31    }
32
33    pub unsafe fn from_offset(offset: usize) -> Self {
34        ArenaRef {
35            offset,
36            _phantom: PhantomData,
37        }
38    }
39
40    pub fn offset(&self) -> usize {
41        self.offset
42    }
43
44    pub unsafe fn get<'a>(&self, arena: &'a Arena) -> &'a T {
45        &*(arena.base_ptr().add(self.offset) as *const T)
46    }
47
48    #[allow(clippy::mut_from_ref)]
49    pub unsafe fn get_mut<'a>(&self, arena: &'a Arena) -> &'a mut T {
50        &mut *(arena.base_ptr().add(self.offset) as *mut T)
51    }
52
53    pub unsafe fn write(&self, arena: &Arena, value: T) {
54        ptr::write(self.get_mut(arena), value);
55    }
56
57    pub unsafe fn read(&self, arena: &Arena) -> T
58    where
59        T: Copy,
60    {
61        ptr::read(self.get(arena))
62    }
63}
64
65impl<T> Clone for ArenaRef<T> {
66    fn clone(&self) -> Self {
67        *self
68    }
69}
70
71impl<T> Copy for ArenaRef<T> {}