1use crate::buffers::RUMBuffer;
21use crate::mem::constants::KB;
22use crate::mem::{as_slice, as_slice_mut, cast_to_nonnull, direct_alloc, AsPtr, AsSlice, SizedType};
23use crate::rumtk_layout;
24use std::alloc::AllocError;
25use std::ops::Index;
26use std::ops::{Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive};
27use std::ptr::NonNull;
28
29pub const DEFAULT_ARENA_MEMORY_ALLOCATION: usize = 4 * KB;
30
31pub type ArenaResult<T> = Result<T, AllocError>;
32pub type ArenaBaseAddress = *const u8;
33
34#[derive(Debug)]
70pub struct Arena {
71 memory: RUMBuffer,
72 remaining: usize,
73 capacity: usize,
74}
75
76impl Arena {
77 pub fn new() -> Self {
81 Self::with_capacity(DEFAULT_ARENA_MEMORY_ALLOCATION)
82 }
83
84 #[inline]
89 pub fn with_capacity(capacity: usize) -> Self {
90 Self {
91 memory: RUMBuffer::from_parts(unsafe { direct_alloc(rumtk_layout!(capacity)) }, capacity, true),
92 remaining: capacity,
93 capacity,
94 }
95 }
96
97 #[inline]
98 pub const fn null() -> Self {
99 Self {
100 memory: RUMBuffer::new(),
101 remaining: 0,
102 capacity: 0,
103 }
104 }
105
106 #[inline]
107 pub fn from_parts(ptr: *mut u8, capacity: usize, dealloc: bool) -> Self {
108 Self {
109 memory: RUMBuffer::from_parts(ptr, capacity, dealloc),
110 remaining: capacity,
111 capacity,
112 }
113 }
114
115 #[inline]
116 pub fn split_to(&mut self, len: usize) -> Self {
117 match self.memory.split_to(len) {
118 Some(new_buffer) => {
119 self.remaining -= len;
120 self.capacity -= len;
121
122 Self {
123 memory: new_buffer,
124 remaining: len,
125 capacity: len,
126 }
127 },
128 None => {
129 Self {
130 memory: RUMBuffer::new(),
131 remaining: 0,
132 capacity: 0,
133 }
134 }
135 }
136 }
137
138 #[inline]
139 pub fn freeze(&mut self) -> Self {
140 Self {
141 memory: self.memory.freeze(),
142 remaining: self.remaining,
143 capacity: self.capacity,
144 }
145 }
146
147 #[inline(always)]
148 pub fn remaining(&self) -> usize {
149 self.remaining
150 }
151
152 #[inline(always)]
153 pub fn capacity(&self) -> usize {
154 self.capacity
155 }
156
157 #[inline(always)]
162 pub fn can_allocate(&self, size: usize) -> bool {
163 let remaining = self.remaining();
164 remaining >= size
165 }
166
167 #[inline(always)]
176 pub fn commit(&mut self, size: usize) -> ArenaResult<*mut [u8]> {
177 if self.can_allocate(size) {
178 let lower_bound = self.capacity - self.remaining;
179 let upper_bound = lower_bound + size;
180 let slice = &mut self.memory[lower_bound..upper_bound];
181 self.remaining -= size;
182 Ok(slice)
183 } else {
184 eprintln!("Cannot allocate {} bytes due to lack of space!", size);
185 Err(AllocError)
186 }
187 }
188
189 pub fn write_bytes(&mut self, src: *const u8, data_length: usize) -> ArenaResult<*mut [u8]> {
193 let dst = self.commit(data_length)?;
194 unsafe {
195 std::ptr::copy_nonoverlapping(
196 src,
197 dst.as_mut_ptr(),
198 data_length,
199 );
200 }
201 Ok(dst)
202 }
203
204 pub fn write<T>(&mut self, data: T) -> ArenaResult<NonNull<T>> {
221 let data_length = size_of::<T>();
222 let src = std::ptr::addr_of!(data).cast::<u8>();
223
224 let mem = cast_to_nonnull(self.write_bytes(src, data_length)?);
225 Ok(mem.cast())
226 }
227
228 #[inline(always)]
237 pub fn uncommit(&mut self, length: usize) {
238 let new_lower_bound = self.remaining() - (length % self.len());
239 self.remaining = new_lower_bound;
240 }
241
242 #[inline(always)]
246 pub fn reset(&mut self) {
247 self.remaining = self.capacity;
248 }
249
250 #[inline(always)]
251 pub fn address(&self) -> ArenaBaseAddress {
252 self.as_ptr()
253 }
254
255 #[inline(always)]
256 pub fn is_empty(&self) -> bool {
257 self.remaining() == 0
258 }
259
260 #[inline(always)]
261 pub fn len(&self) -> usize {
262 self.capacity()
263 }
264}
265
266impl AsSlice for Arena {
267 #[inline(always)]
268 fn as_slice(&self) -> &'static [u8] { as_slice(self.as_ptr(), self.size()) }
269 #[inline(always)]
270 fn as_slice_mut(&mut self) -> &'static mut [u8] { as_slice_mut(self.as_mut_ptr(), self.size()) }
271
272 #[inline(always)]
273 fn contains(&self, x: &u8) -> bool {
274 self.as_slice().contains(x)
275 }
276}
277
278impl AsPtr for Arena {
279 #[inline(always)]
280 fn as_ptr(&self) -> *const u8 {
281 self.memory.as_ptr()
282 }
283 #[inline(always)]
284 fn as_mut_ptr(&mut self) -> *mut u8 {
285 self.memory.as_mut_ptr()
286 }
287}
288
289impl SizedType for Arena {
290 #[inline(always)]
291 fn size(&self) -> usize {
292 self.capacity
293 }
294}
295
296impl Default for Arena {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302unsafe impl Send for Arena {}
303unsafe impl Sync for Arena {}
304
305impl Index<usize> for Arena {
306 type Output = u8;
307 #[inline]
308 fn index(&self, i: usize) -> & Self::Output {
309 &self.as_slice()[i]
310 }
311}
312
313impl Index<Range<usize>> for Arena {
314 type Output = [u8];
315 #[inline]
316 fn index(&self, i: Range<usize>) -> & Self::Output {
317 &self.as_slice()[i.start..i.end]
318 }
319}
320
321impl Index<RangeTo<usize>> for Arena {
322 type Output = [u8];
323 #[inline]
324 fn index(&self, i: RangeTo<usize>) -> & Self::Output {
325 &self.as_slice()[..i.end]
326 }
327}
328
329impl Index<RangeFrom<usize>> for Arena {
330 type Output = [u8];
331 #[inline]
332 fn index(&self, i: RangeFrom<usize>) -> & Self::Output {
333 &self.as_slice()[i.start..]
334 }
335}
336
337impl Index<RangeToInclusive<usize>> for Arena {
338 type Output = [u8];
339 #[inline]
340 fn index(&self, i: RangeToInclusive<usize>) -> & Self::Output {
341 &self.as_slice()[..=i.end]
342 }
343}
344
345impl Index<RangeFull> for Arena {
346 type Output = [u8];
347 #[inline]
348 fn index(&self, i: RangeFull) -> & Self::Output {
349 self.as_slice()
350 }
351}
352
353#[macro_export]
354macro_rules! rumtk_arena_new {
355 ( ) => {{
356 use $crate::arena::Arena;
357 Arena::new()
358 }};
359 ( $capacity:expr ) => {{
360 use $crate::arena::Arena;
361
362 Arena::with_capacity($capacity)
363 }};
364 ( $ptr:expr, $capacity:expr, $dealloc:expr ) => {{
365 use $crate::arena::Arena;
366
367 Arena::from_parts($ptr, $capacity, $dealloc)
368 }};
369}