1use alloc::vec::Vec;
2use core::marker::PhantomData;
3
4pub struct Id<T> {
17 index: u32,
18 generation: u32,
19 _marker: PhantomData<fn() -> T>,
20}
21
22impl<T> Id<T> {
23 #[inline]
26 #[must_use]
27 pub fn index(self) -> u32 {
28 self.index
29 }
30
31 #[inline]
34 #[must_use]
35 pub fn generation(self) -> u32 {
36 self.generation
37 }
38}
39
40impl<T> Clone for Id<T> {
41 #[inline]
42 fn clone(&self) -> Self {
43 *self
44 }
45}
46
47impl<T> Copy for Id<T> {}
48
49impl<T> PartialEq for Id<T> {
50 #[inline]
51 fn eq(&self, other: &Self) -> bool {
52 self.index == other.index && self.generation == other.generation
53 }
54}
55
56impl<T> Eq for Id<T> {}
57
58impl<T> PartialOrd for Id<T> {
59 #[inline]
60 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
61 Some(self.cmp(other))
62 }
63}
64
65impl<T> Ord for Id<T> {
66 #[inline]
67 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
68 (self.index, self.generation).cmp(&(other.index, other.generation))
69 }
70}
71
72impl<T> core::hash::Hash for Id<T> {
73 #[inline]
74 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
75 core::hash::Hash::hash(&self.index, state);
76 core::hash::Hash::hash(&self.generation, state);
77 }
78}
79
80impl<T> core::fmt::Debug for Id<T> {
81 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82 write!(f, "Id({}@g{})", self.index, self.generation)
83 }
84}
85
86#[derive(Clone, Debug)]
87struct Slot<T> {
88 generation: u32,
89 value: Option<T>,
90}
91
92#[derive(Clone, Debug)]
100pub struct Arena<T> {
101 slots: Vec<Slot<T>>,
102 free: Vec<u32>,
103 len: usize,
104}
105
106impl<T> Arena<T> {
107 #[must_use]
110 pub fn new() -> Self {
111 Self {
112 slots: Vec::new(),
113 free: Vec::new(),
114 len: 0,
115 }
116 }
117
118 #[must_use]
121 pub fn with_capacity(capacity: usize) -> Self {
122 Self {
123 slots: Vec::with_capacity(capacity),
124 free: Vec::new(),
125 len: 0,
126 }
127 }
128
129 pub fn insert(&mut self, value: T) -> Id<T> {
136 self.len += 1;
137 if let Some(index) = self.free.pop() {
138 let slot = &mut self.slots[index as usize];
139 slot.generation = slot.generation.wrapping_add(1);
140 slot.value = Some(value);
141 return Id {
142 index,
143 generation: slot.generation,
144 _marker: PhantomData,
145 };
146 }
147
148 let index = u32::try_from(self.slots.len()).expect("arena index space exhausted");
149 self.slots.push(Slot {
150 generation: 0,
151 value: Some(value),
152 });
153 Id {
154 index,
155 generation: 0,
156 _marker: PhantomData,
157 }
158 }
159
160 #[must_use]
163 pub fn get(&self, id: Id<T>) -> Option<&T> {
164 let slot = self.slots.get(id.index as usize)?;
165 if slot.generation != id.generation {
166 return None;
167 }
168 slot.value.as_ref()
169 }
170
171 #[must_use]
174 pub fn get_mut(&mut self, id: Id<T>) -> Option<&mut T> {
175 let slot = self.slots.get_mut(id.index as usize)?;
176 if slot.generation != id.generation {
177 return None;
178 }
179 slot.value.as_mut()
180 }
181
182 #[must_use]
185 pub fn contains(&self, id: Id<T>) -> bool {
186 self.get(id).is_some()
187 }
188
189 #[must_use]
192 pub fn remove(&mut self, id: Id<T>) -> Option<T> {
193 let slot = self.slots.get_mut(id.index as usize)?;
194 if slot.generation != id.generation {
195 return None;
196 }
197 let value = slot.value.take()?;
198 slot.generation = slot.generation.wrapping_add(1);
199 self.free.push(id.index);
200 self.len -= 1;
201 Some(value)
202 }
203
204 #[must_use]
207 pub fn len(&self) -> usize {
208 self.len
209 }
210
211 #[must_use]
214 pub fn is_empty(&self) -> bool {
215 self.len == 0
216 }
217
218 pub fn iter(&self) -> impl Iterator<Item = (Id<T>, &T)> {
221 self.slots.iter().enumerate().filter_map(|(index, slot)| {
222 let value = slot.value.as_ref()?;
223 let index = u32::try_from(index).ok()?;
224 Some((
225 Id {
226 index,
227 generation: slot.generation,
228 _marker: PhantomData,
229 },
230 value,
231 ))
232 })
233 }
234
235 pub fn iter_mut(&mut self) -> impl Iterator<Item = (Id<T>, &mut T)> {
238 self
239 .slots
240 .iter_mut()
241 .enumerate()
242 .filter_map(|(index, slot)| {
243 let value = slot.value.as_mut()?;
244 let index = u32::try_from(index).ok()?;
245 Some((
246 Id {
247 index,
248 generation: slot.generation,
249 _marker: PhantomData,
250 },
251 value,
252 ))
253 })
254 }
255}
256
257impl<T> Default for Arena<T> {
258 fn default() -> Self {
259 Self::new()
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use alloc::vec::Vec;
266
267 use super::Arena;
268
269 #[test]
270 fn insert_and_get() {
271 let mut arena = Arena::new();
272 let id = arena.insert(42u32);
273 assert_eq!(arena.get(id), Some(&42));
274 assert!(arena.contains(id));
275 assert_eq!(arena.len(), 1);
276 }
277
278 #[test]
279 fn removed_id_becomes_stale() {
280 let mut arena = Arena::new();
281 let id = arena.insert(7u32);
282 assert_eq!(arena.remove(id), Some(7));
283 assert!(!arena.contains(id));
284 assert_eq!(arena.get(id), None);
285 assert!(arena.is_empty());
286 }
287
288 #[test]
289 fn reused_slot_invalidates_previous_handle() {
290 let mut arena = Arena::new();
291 let first = arena.insert(1u32);
292 let _ = arena.remove(first);
293 let second = arena.insert(2u32);
294 assert_eq!(first.index(), second.index());
297 assert_ne!(first, second);
298 assert_eq!(arena.get(first), None);
299 assert_eq!(arena.get(second), Some(&2));
300 }
301
302 #[test]
303 fn iter_yields_live_pairs() {
304 let mut arena = Arena::new();
305 let a = arena.insert("a");
306 let b = arena.insert("b");
307 let c = arena.insert("c");
308 let _ = arena.remove(b);
309 let mut seen: Vec<&str> = arena.iter().map(|(_, v)| *v).collect();
310 seen.sort_unstable();
311 assert_eq!(seen, ["a", "c"]);
312 assert!(arena.contains(a) && arena.contains(c));
313 }
314}