1use crate::memory::header;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ArenaError {
12 OutOfSpace,
14 InvalidOffset,
16}
17
18#[inline]
22pub(crate) fn alloc(data: &mut [u8], header: &mut [u8], bytes: &[u8]) -> Result<u32, ArenaError> {
23 alloc_at(data, header, crate::memory::OFF_ARENA_CURSOR, bytes)
24}
25
26#[inline]
31pub(crate) fn alloc_event(
32 data: &mut [u8],
33 header: &mut [u8],
34 bytes: &[u8],
35) -> Result<u32, ArenaError> {
36 alloc_at(data, header, crate::memory::OFF_EVENT_ARENA_CURSOR, bytes)
37}
38
39#[inline]
41pub(crate) fn alloc_at(
42 data: &mut [u8],
43 header: &mut [u8],
44 cursor_off: usize,
45 bytes: &[u8],
46) -> Result<u32, ArenaError> {
47 let cursor = header::get_u32(header, cursor_off) as usize;
48 let len = bytes.len();
49 let needed = 4 + len;
50 if cursor + needed > data.len() {
51 return Err(ArenaError::OutOfSpace);
52 }
53 data[cursor..cursor + 4].copy_from_slice(&(len as u32).to_le_bytes());
54 data[cursor + 4..cursor + needed].copy_from_slice(bytes);
55 header::set_u32(header, cursor_off, (cursor + needed) as u32);
56 Ok(cursor as u32)
57}
58
59#[inline]
61pub(crate) fn alloc_str(
62 data: &mut [u8],
63 header: &mut [u8],
64 s: &str,
65) -> Result<u32, ArenaError> {
66 alloc(data, header, s.as_bytes())
67}
68
69#[inline]
71pub(crate) fn get(data: &[u8], offset: u32) -> Result<&[u8], ArenaError> {
72 let off = offset as usize;
73 if off + 4 > data.len() {
74 return Err(ArenaError::InvalidOffset);
75 }
76 let len = u32::from_le_bytes(data[off..off + 4].try_into().unwrap()) as usize;
77 if off + 4 + len > data.len() {
78 return Err(ArenaError::InvalidOffset);
79 }
80 Ok(&data[off + 4..off + 4 + len])
81}
82
83#[inline]
85pub(crate) fn get_str(data: &[u8], offset: u32) -> Result<&str, ArenaError> {
86 let bytes = get(data, offset)?;
87 core::str::from_utf8(bytes).map_err(|_| ArenaError::InvalidOffset)
88}
89
90#[cfg(test)]
91mod tests {
92 use alloc::vec;
93 use super::*;
94 use crate::memory::{header, MemoryLayout};
95
96 #[test]
97 fn alloc_and_get_round_trip() {
98 let layout = MemoryLayout::default();
99 let mut buf = vec![0u8; layout.total_bytes()];
100 crate::init_memory(&mut buf, &layout);
101 let (head, rest) = buf.split_at_mut(crate::memory::HEADER_SIZE);
102 let (_, rest) = rest.split_at_mut(layout.ring_bytes() + layout.event_ring_bytes());
103 let (arena_data, _event_arena) = rest.split_at_mut(layout.arena_bytes);
104 let off = alloc_str(arena_data, head, "Hello").unwrap();
105 assert_eq!(get(arena_data, off).unwrap(), b"Hello");
106 assert_eq!(get_str(arena_data, off).unwrap(), "Hello");
107 assert_eq!(header::get_u32(head, crate::memory::OFF_ARENA_CURSOR), 4 + 5);
108 }
109
110 #[test]
111 fn multiple_allocs_are_contiguous() {
112 let layout = MemoryLayout::default();
113 let mut buf = vec![0u8; layout.total_bytes()];
114 crate::init_memory(&mut buf, &layout);
115 let (head, rest) = buf.split_at_mut(crate::memory::HEADER_SIZE);
116 let (_, rest) = rest.split_at_mut(layout.ring_bytes() + layout.event_ring_bytes());
117 let (arena_data, _event_arena) = rest.split_at_mut(layout.arena_bytes);
118 let o1 = alloc_str(arena_data, head, "ab").unwrap();
119 let o2 = alloc_str(arena_data, head, "cdef").unwrap();
120 assert!(o2 > o1);
121 assert_eq!(get(arena_data, o1).unwrap(), b"ab");
122 assert_eq!(get(arena_data, o2).unwrap(), b"cdef");
123 }
124
125 #[test]
126 fn out_of_space_is_reported() {
127 let layout = MemoryLayout::default();
128 let mut buf = vec![0u8; layout.total_bytes()];
129 crate::init_memory(&mut buf, &layout);
130 let (head, rest) = buf.split_at_mut(crate::memory::HEADER_SIZE);
131 let (_, rest) = rest.split_at_mut(layout.ring_bytes() + layout.event_ring_bytes());
132 let (arena_data, _event_arena) = rest.split_at_mut(layout.arena_bytes);
133 assert_eq!(
134 alloc(arena_data, head, &[0u8; 1024 * 1024]).unwrap_err(),
135 ArenaError::OutOfSpace
136 );
137 }
138}