1use core::alloc::Layout;
4use core::fmt;
5use core::ptr::NonNull;
6
7use crate::alloc::AllocError;
8use crate::alloc::Allocator;
9use crate::alloc::Global;
10use crate::boxed::Box;
11use crate::vec::Vec;
12
13pub struct LocalArena<A: Allocator = Global>(blink_alloc::BlinkAlloc<A>);
18
19pub struct SharedArena<A: Allocator = Global>(blink_alloc::SyncBlinkAlloc<A>);
26
27pub struct ScopedArena<'shared, A: Allocator = Global>(blink_alloc::LocalBlinkAlloc<'shared, A>);
37
38impl LocalArena<Global> {
39 #[inline]
44 #[must_use]
45 pub const fn new() -> Self {
46 Self::new_in(Global)
47 }
48
49 #[inline]
55 #[must_use]
56 pub const fn with_chunk_size(chunk_size: usize) -> Self {
57 Self::with_chunk_size_in(chunk_size, Global)
58 }
59}
60
61impl<A: Allocator> LocalArena<A> {
62 #[inline]
64 #[must_use]
65 pub const fn new_in(arena: A) -> Self {
66 Self(blink_alloc::BlinkAlloc::new_in(arena))
67 }
68
69 #[inline]
71 #[must_use]
72 pub const fn with_chunk_size_in(chunk_size: usize, arena: A) -> Self {
73 Self(blink_alloc::BlinkAlloc::with_chunk_size_in(chunk_size, arena))
74 }
75
76 #[inline]
78 pub fn reset(&mut self) {
79 self.0.reset();
80 }
81}
82
83impl Default for LocalArena {
84 #[inline]
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90impl SharedArena<Global> {
91 #[inline]
96 #[must_use]
97 pub const fn new() -> Self {
98 Self::new_in(Global)
99 }
100
101 #[inline]
107 #[must_use]
108 pub const fn with_chunk_size(chunk_size: usize) -> Self {
109 Self::with_chunk_size_in(chunk_size, Global)
110 }
111}
112
113impl<A: Allocator> SharedArena<A> {
114 #[inline]
117 #[must_use]
118 pub const fn new_in(arena: A) -> Self {
119 Self(blink_alloc::SyncBlinkAlloc::new_in(arena))
120 }
121
122 #[inline]
124 #[must_use]
125 pub const fn with_chunk_size_in(chunk_size: usize, arena: A) -> Self {
126 Self(blink_alloc::SyncBlinkAlloc::with_chunk_size_in(chunk_size, arena))
127 }
128
129 #[inline]
134 pub fn scoped(&self) -> ScopedArena<'_, A> {
135 ScopedArena(self.0.local())
136 }
137
138 #[inline]
140 pub fn reset(&mut self) {
141 self.0.reset();
142 }
143}
144
145impl Default for SharedArena {
146 #[inline]
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152impl<A: Allocator> ScopedArena<'_, A> {
153 #[inline]
155 pub fn reset(&mut self) {
156 self.0.reset();
157 }
158}
159
160macro_rules! forward_allocator {
161 () => {
162 #[inline]
163 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
164 Allocator::allocate(&self.0, layout)
165 }
166
167 #[inline]
168 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
169 Allocator::allocate_zeroed(&self.0, layout)
170 }
171
172 #[inline]
173 unsafe fn deallocate(&self, pointer: NonNull<u8>, layout: Layout) {
174 unsafe { Allocator::deallocate(&self.0, pointer, layout) }
176 }
177
178 #[inline]
179 unsafe fn grow(
180 &self,
181 pointer: NonNull<u8>,
182 old_layout: Layout,
183 new_layout: Layout,
184 ) -> Result<NonNull<[u8]>, AllocError> {
185 unsafe { Allocator::grow(&self.0, pointer, old_layout, new_layout) }
187 }
188
189 #[inline]
190 unsafe fn grow_zeroed(
191 &self,
192 pointer: NonNull<u8>,
193 old_layout: Layout,
194 new_layout: Layout,
195 ) -> Result<NonNull<[u8]>, AllocError> {
196 unsafe { Allocator::grow_zeroed(&self.0, pointer, old_layout, new_layout) }
198 }
199
200 #[inline]
201 unsafe fn shrink(
202 &self,
203 pointer: NonNull<u8>,
204 old_layout: Layout,
205 new_layout: Layout,
206 ) -> Result<NonNull<[u8]>, AllocError> {
207 unsafe { Allocator::shrink(&self.0, pointer, old_layout, new_layout) }
209 }
210 };
211}
212
213unsafe impl<A: Allocator> Allocator for LocalArena<A> {
216 forward_allocator!();
217}
218
219unsafe impl<A: Allocator> Allocator for SharedArena<A> {
221 forward_allocator!();
222}
223
224unsafe impl<A: Allocator> Allocator for ScopedArena<'_, A> {
226 forward_allocator!();
227}
228
229struct ArenaFormatter<'buffer, 'arena, A: Allocator + ?Sized> {
230 buffer: &'buffer mut Vec<'arena, u8, A>,
231}
232
233impl<A: Allocator + ?Sized> fmt::Write for ArenaFormatter<'_, '_, A> {
234 #[inline]
235 fn write_str(&mut self, fragment: &str) -> fmt::Result {
236 self.buffer.extend_from_slice(fragment.as_bytes());
237
238 Ok(())
239 }
240}
241
242pub trait Arena: Allocator {
249 fn alloc<T>(&self, value: T) -> &mut T;
251
252 fn alloc_with<T>(&self, f: impl FnOnce() -> T) -> &mut T;
254
255 fn alloc_str(&self, src: &str) -> &mut str;
257
258 fn alloc_fmt(&self, arguments: fmt::Arguments<'_>) -> &mut str;
270
271 fn alloc_slice_copy<T>(&self, src: &[T]) -> &mut [T]
273 where
274 T: Copy;
275
276 fn alloc_slice_clone<T>(&self, src: &[T]) -> &mut [T]
278 where
279 T: Clone;
280
281 fn alloc_slice_fill_copy<T>(&self, len: usize, value: T) -> &mut [T]
283 where
284 T: Copy;
285
286 fn alloc_slice_fill_clone<T>(&self, len: usize, value: &T) -> &mut [T]
288 where
289 T: Clone;
290
291 fn alloc_slice_fill_with<T>(&self, len: usize, f: impl FnMut(usize) -> T) -> &mut [T];
293
294 fn alloc_slice_fill_default<T>(&self, len: usize) -> &mut [T]
296 where
297 T: Default;
298
299 fn alloc_slice_fill_iter<T>(&self, iter: impl IntoIterator<Item = T>) -> &mut [T];
301}
302
303impl<A: Allocator + ?Sized> Arena for A {
304 #[inline]
305 fn alloc<T>(&self, value: T) -> &mut T {
306 Box::leak(Box::new_in(value, self))
307 }
308
309 #[inline]
310 fn alloc_with<T>(&self, f: impl FnOnce() -> T) -> &mut T {
311 Box::leak(Box::new_in(f(), self))
312 }
313
314 #[inline]
315 fn alloc_str(&self, src: &str) -> &mut str {
316 let bytes = self.alloc_slice_copy(src.as_bytes());
317
318 unsafe { core::str::from_utf8_unchecked_mut(bytes) }
320 }
321
322 #[inline]
323 fn alloc_fmt(&self, arguments: fmt::Arguments<'_>) -> &mut str {
324 let mut buffer = Vec::new_in(self);
325 let mut formatter = ArenaFormatter { buffer: &mut buffer };
326 let _ = fmt::write(&mut formatter, arguments);
327
328 let bytes = buffer.leak();
329
330 unsafe { core::str::from_utf8_unchecked_mut(bytes) }
333 }
334
335 #[inline]
336 fn alloc_slice_copy<T>(&self, src: &[T]) -> &mut [T]
337 where
338 T: Copy,
339 {
340 let mut vec = Vec::with_capacity_in(src.len(), self);
341 vec.extend_from_slice(src);
342 vec.leak()
343 }
344
345 #[inline]
346 fn alloc_slice_clone<T>(&self, src: &[T]) -> &mut [T]
347 where
348 T: Clone,
349 {
350 let mut vec = Vec::with_capacity_in(src.len(), self);
351 vec.extend(src.iter().cloned());
352 vec.leak()
353 }
354
355 #[inline]
356 fn alloc_slice_fill_copy<T>(&self, len: usize, value: T) -> &mut [T]
357 where
358 T: Copy,
359 {
360 let mut vec = Vec::with_capacity_in(len, self);
361 vec.resize(len, value);
362 vec.leak()
363 }
364
365 #[inline]
366 fn alloc_slice_fill_clone<T>(&self, len: usize, value: &T) -> &mut [T]
367 where
368 T: Clone,
369 {
370 let mut vec = Vec::with_capacity_in(len, self);
371 vec.resize_with(len, || value.clone());
372 vec.leak()
373 }
374
375 #[inline]
376 fn alloc_slice_fill_with<T>(&self, len: usize, mut f: impl FnMut(usize) -> T) -> &mut [T] {
377 let mut vec = Vec::with_capacity_in(len, self);
378 for index in 0..len {
379 vec.push(f(index));
380 }
381 vec.leak()
382 }
383
384 #[inline]
385 fn alloc_slice_fill_default<T>(&self, len: usize) -> &mut [T]
386 where
387 T: Default,
388 {
389 self.alloc_slice_fill_with(len, |_| T::default())
390 }
391
392 #[inline]
393 fn alloc_slice_fill_iter<T>(&self, iter: impl IntoIterator<Item = T>) -> &mut [T] {
394 let mut vec = Vec::new_in(self);
395 vec.extend(iter);
396 vec.leak()
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403 use crate::collections::HashMap;
404 use crate::vec::Vec;
405
406 #[test]
407 fn local_alloc_roundtrips() {
408 let arena = LocalArena::new();
409 let value = arena.alloc(42u32);
410
411 assert_eq!(*value, 42);
412 }
413
414 #[test]
415 fn alloc_str_copies() {
416 let arena = LocalArena::new();
417 let copied = arena.alloc_str("hello");
418
419 assert_eq!(copied, "hello");
420 }
421
422 #[test]
423 fn alloc_fmt_formats_into_arena() {
424 let arena = LocalArena::new();
425 let formatted = arena.alloc_fmt(format_args!("{}+{}={}", 2, 3, 5));
426
427 assert_eq!(formatted, "2+3=5");
428 }
429
430 #[test]
431 fn format_in_macro_formats_into_arena() {
432 let arena = LocalArena::new();
433 let label = crate::format_in!(arena, "{}::{}", "App", "VERSION");
434
435 assert_eq!(label, "App::VERSION");
436 }
437
438 #[test]
439 fn alloc_slice_copy_copies() {
440 let arena = LocalArena::new();
441 let slice = arena.alloc_slice_copy(&[1, 2, 3]);
442
443 assert_eq!(slice, &[1, 2, 3]);
444 }
445
446 #[test]
447 fn alloc_slice_fill_with_invokes_closure() {
448 let arena = LocalArena::new();
449 let slice = arena.alloc_slice_fill_with(4, |index| index * 2);
450
451 assert_eq!(slice, &[0, 2, 4, 6]);
452 }
453
454 #[test]
455 fn shared_vec_grows_in_place() {
456 let arena = SharedArena::new();
457 let mut vec = Vec::new_in(&arena);
458 for value in 0..1000 {
459 vec.push(value);
460 }
461
462 assert_eq!(vec.len(), 1000);
463 assert_eq!(vec.last(), Some(&999));
464 }
465
466 #[test]
467 fn scoped_alloc_roundtrips() {
468 let shared = SharedArena::new();
469 let scoped = shared.scoped();
470 let value = scoped.alloc(7u8);
471
472 assert_eq!(*value, 7);
473 }
474
475 #[test]
476 fn arena_hashmap_roundtrips() {
477 let arena = SharedArena::new();
478 let mut map = HashMap::new_in(&arena);
479 map.insert(1u32, "one");
480
481 assert_eq!(map.get(&1), Some(&"one"));
482 }
483
484 #[cfg(feature = "serde")]
485 #[test]
486 fn arena_vec_serializes() {
487 let arena = LocalArena::new();
488 let mut numbers = Vec::new_in(&arena);
489 numbers.extend([1, 2, 3]);
490
491 let json = serde_json::to_string(&numbers);
492
493 assert!(matches!(json.as_deref(), Ok("[1,2,3]")));
494 }
495}