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