1use std::fmt;
10use std::marker::PhantomData;
11use std::sync::atomic::{AtomicU32, Ordering};
12
13static NEXT_ARENA_ID: AtomicU32 = AtomicU32::new(0);
16
17pub struct Id<T> {
23 index: u32,
24 arena_id: u32,
25 _marker: PhantomData<T>,
26}
27
28impl<T> Id<T> {
29 #[inline]
30 fn new(index: u32, arena_id: u32) -> Self {
31 Self {
32 index,
33 arena_id,
34 _marker: PhantomData,
35 }
36 }
37
38 #[inline]
39 pub fn index(self) -> usize {
40 self.index as usize
41 }
42
43 #[inline]
44 pub fn arena_id(self) -> u32 {
45 self.arena_id
46 }
47
48 #[inline]
53 pub fn rebase(self, offset: u32, new_arena_id: u32) -> Self {
54 Self {
55 index: self.index + offset,
56 arena_id: new_arena_id,
57 _marker: PhantomData,
58 }
59 }
60}
61
62impl<T> Clone for Id<T> {
63 fn clone(&self) -> Self {
64 *self
65 }
66}
67impl<T> Copy for Id<T> {}
68impl<T> PartialEq for Id<T> {
69 fn eq(&self, other: &Self) -> bool {
70 self.index == other.index && self.arena_id == other.arena_id
71 }
72}
73impl<T> Eq for Id<T> {}
74impl<T> std::hash::Hash for Id<T> {
75 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
76 self.index.hash(state);
77 self.arena_id.hash(state);
78 }
79}
80impl<T> fmt::Debug for Id<T> {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "Id({}@arena{})", self.index, self.arena_id)
83 }
84}
85
86#[derive(Debug)]
88pub struct Arena<T> {
89 id: u32,
90 items: Vec<T>,
91}
92
93impl<T> Arena<T> {
94 pub fn new() -> Self {
95 Self {
96 id: NEXT_ARENA_ID.fetch_add(1, Ordering::Relaxed),
97 items: Vec::new(),
98 }
99 }
100
101 pub fn with_capacity(cap: usize) -> Self {
102 Self {
103 id: NEXT_ARENA_ID.fetch_add(1, Ordering::Relaxed),
104 items: Vec::with_capacity(cap),
105 }
106 }
107
108 pub fn id(&self) -> u32 {
110 self.id
111 }
112
113 pub fn alloc(&mut self, item: T) -> Id<T> {
115 let index = self.items.len() as u32;
116 self.items.push(item);
117 Id::new(index, self.id)
118 }
119
120 pub fn get(&self, id: Id<T>) -> &T {
121 self.check_owner(id, "get");
122 let index = id.index();
123 if index >= self.items.len() {
124 panic!(
125 "Arena<{}>: index {} out of bounds (len {})",
126 std::any::type_name::<T>(),
127 index,
128 self.items.len()
129 );
130 }
131 &self.items[index]
132 }
133
134 pub fn get_mut(&mut self, id: Id<T>) -> &mut T {
135 self.check_owner(id, "get_mut");
136 let index = id.index();
137 let len = self.items.len();
138 if index >= len {
139 panic!(
140 "Arena<{}>: index {} out of bounds (len {})",
141 std::any::type_name::<T>(),
142 index,
143 len
144 );
145 }
146 &mut self.items[index]
147 }
148
149 pub fn len(&self) -> usize {
150 self.items.len()
151 }
152
153 pub fn is_empty(&self) -> bool {
154 self.items.is_empty()
155 }
156
157 #[inline]
162 fn check_owner(&self, id: Id<T>, op: &str) {
163 if id.arena_id != self.id {
164 panic!(
165 "Arena<{}>::{}: Id belongs to arena {} but this arena is {} - cross-arena access",
166 std::any::type_name::<T>(),
167 op,
168 id.arena_id,
169 self.id
170 );
171 }
172 }
173
174 pub fn raw_parts_mut(&mut self) -> (u32, &mut Vec<T>) {
178 (self.id, &mut self.items)
179 }
180}
181
182impl<T> Default for Arena<T> {
183 fn default() -> Self {
184 Self::new()
185 }
186}
187
188impl<T> std::ops::Index<Id<T>> for Arena<T> {
189 type Output = T;
190 fn index(&self, id: Id<T>) -> &T {
191 self.get(id)
192 }
193}
194
195impl<T> std::ops::IndexMut<Id<T>> for Arena<T> {
196 fn index_mut(&mut self, id: Id<T>) -> &mut T {
197 self.get_mut(id)
198 }
199}