1use std::{cell::Cell, mem};
9
10use loaned::{drop, LoanedMut};
11
12pub struct Arena<'t, T> {
13 cursor: &'t mut [Option<T>],
14 chunks: Vec<LoanedMut<'t, Box<[Option<T>]>>>,
15 capacity: usize,
16}
17
18impl<'t, T> Arena<'t, T> {
19 pub fn with_capacity(capacity: usize) -> Self {
20 let capacity = capacity.max(1);
21 let (cursor, chunk) = Self::new_chunk(capacity);
22 Arena {
23 cursor,
24 chunks: vec![chunk],
25 capacity,
26 }
27 }
28
29 fn new_chunk(capacity: usize) -> (&'t mut [Option<T>], LoanedMut<'t, Box<[Option<T>]>>) {
30 let mut chunk = Vec::with_capacity(capacity);
31 chunk.resize_with(capacity, || None);
32 let chunk = chunk.into_boxed_slice();
33 let (cursor, chunk) = LoanedMut::loan(chunk);
34 (cursor, chunk)
35 }
36
37 pub fn alloc(&mut self, value: T) -> &'t mut T {
38 if self.cursor.is_empty() {
39 self.capacity *= 2;
40 let (cursor, chunk) = Self::new_chunk(self.capacity);
41 self.cursor = cursor;
42 self.chunks.push(chunk);
43 }
44 let cursor = mem::replace(&mut self.cursor, &mut []);
45 let (slot, cursor) = cursor.split_first_mut().unwrap();
46 self.cursor = cursor;
47 *slot = Some(value);
48 let Some(slot) = slot else { unreachable!() };
49 slot
50 }
51
52 pub fn into_inner(self) -> LoanedMut<'t, Vec<Box<[Option<T>]>>> {
53 self.chunks.into()
54 }
55}
56
57#[cfg_attr(test, test)]
58fn main() {
59 let mut arena = Arena::with_capacity(1);
60
61 struct CycleParticipant<'a> {
62 name: &'static str,
63 next: Cell<Option<&'a CycleParticipant<'a>>>,
64 }
65
66 impl<'a> CycleParticipant<'a> {
67 fn next(&self) -> &'a CycleParticipant<'a> {
68 self.next.get().unwrap()
69 }
70 }
71
72 let a = arena.alloc(CycleParticipant {
73 name: "a",
74 next: Cell::new(None),
75 });
76
77 let b = arena.alloc(CycleParticipant {
78 name: "b",
79 next: Cell::new(None),
80 });
81
82 a.next.set(Some(b));
83 b.next.set(Some(a));
84
85 print_assert_eq!(a.name, "a");
86 print_assert_eq!(a.next().name, "b");
87 print_assert_eq!(a.next().next().name, "a");
88
89 drop!(arena.into_inner());
90}
91
92#[macro_export]
93macro_rules! print_assert_eq {
94 ($x:expr, $y:expr) => {
95 println!("{} = {:?}", stringify!($x), $x);
96 assert_eq!($x, $y);
97 };
98}