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]
24 pub fn index(self) -> u32 {
25 self.index
26 }
27
28 #[inline]
29 pub fn generation(self) -> u32 {
30 self.generation
31 }
32}
33
34impl<T> Clone for Id<T> {
35 #[inline]
36 fn clone(&self) -> Self {
37 *self
38 }
39}
40
41impl<T> Copy for Id<T> {}
42
43impl<T> PartialEq for Id<T> {
44 #[inline]
45 fn eq(&self, other: &Self) -> bool {
46 self.index == other.index && self.generation == other.generation
47 }
48}
49
50impl<T> Eq for Id<T> {}
51
52impl<T> PartialOrd for Id<T> {
53 #[inline]
54 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
55 Some(self.cmp(other))
56 }
57}
58
59impl<T> Ord for Id<T> {
60 #[inline]
61 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
62 (self.index, self.generation).cmp(&(other.index, other.generation))
63 }
64}
65
66impl<T> core::hash::Hash for Id<T> {
67 #[inline]
68 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
69 core::hash::Hash::hash(&self.index, state);
70 core::hash::Hash::hash(&self.generation, state);
71 }
72}
73
74impl<T> core::fmt::Debug for Id<T> {
75 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76 write!(f, "Id({}@g{})", self.index, self.generation)
77 }
78}
79
80#[derive(Clone, Debug)]
81struct Slot<T> {
82 generation: u32,
83 value: Option<T>,
84}
85
86#[derive(Clone, Debug)]
94pub struct Arena<T> {
95 slots: Vec<Slot<T>>,
96 free: Vec<u32>,
97 len: usize,
98}
99
100impl<T> Arena<T> {
101 pub fn new() -> Self {
102 Self {
103 slots: Vec::new(),
104 free: Vec::new(),
105 len: 0,
106 }
107 }
108
109 pub fn with_capacity(capacity: usize) -> Self {
110 Self {
111 slots: Vec::with_capacity(capacity),
112 free: Vec::new(),
113 len: 0,
114 }
115 }
116
117 pub fn insert(&mut self, value: T) -> Id<T> {
120 self.len += 1;
121 if let Some(index) = self.free.pop() {
122 let slot = &mut self.slots[index as usize];
123 slot.generation = slot.generation.wrapping_add(1);
124 slot.value = Some(value);
125 return Id {
126 index,
127 generation: slot.generation,
128 _marker: PhantomData,
129 };
130 }
131
132 let index = u32::try_from(self.slots.len()).expect("arena index space exhausted");
133 self.slots.push(Slot {
134 generation: 0,
135 value: Some(value),
136 });
137 Id {
138 index,
139 generation: 0,
140 _marker: PhantomData,
141 }
142 }
143
144 pub fn get(&self, id: Id<T>) -> Option<&T> {
145 let slot = self.slots.get(id.index as usize)?;
146 if slot.generation != id.generation {
147 return None;
148 }
149 slot.value.as_ref()
150 }
151
152 pub fn get_mut(&mut self, id: Id<T>) -> Option<&mut T> {
153 let slot = self.slots.get_mut(id.index as usize)?;
154 if slot.generation != id.generation {
155 return None;
156 }
157 slot.value.as_mut()
158 }
159
160 pub fn contains(&self, id: Id<T>) -> bool {
161 self.get(id).is_some()
162 }
163
164 pub fn remove(&mut self, id: Id<T>) -> Option<T> {
167 let slot = self.slots.get_mut(id.index as usize)?;
168 if slot.generation != id.generation {
169 return None;
170 }
171 let value = slot.value.take()?;
172 slot.generation = slot.generation.wrapping_add(1);
173 self.free.push(id.index);
174 self.len -= 1;
175 Some(value)
176 }
177
178 pub fn len(&self) -> usize {
179 self.len
180 }
181
182 pub fn is_empty(&self) -> bool {
183 self.len == 0
184 }
185
186 pub fn iter(&self) -> impl Iterator<Item = (Id<T>, &T)> {
189 self.slots.iter().enumerate().filter_map(|(index, slot)| {
190 let value = slot.value.as_ref()?;
191 let index = u32::try_from(index).ok()?;
192 Some((
193 Id {
194 index,
195 generation: slot.generation,
196 _marker: PhantomData,
197 },
198 value,
199 ))
200 })
201 }
202}
203
204impl<T> Default for Arena<T> {
205 fn default() -> Self {
206 Self::new()
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use alloc::vec::Vec;
213
214 use super::Arena;
215
216 #[test]
217 fn insert_and_get() {
218 let mut arena = Arena::new();
219 let id = arena.insert(42u32);
220 assert_eq!(arena.get(id), Some(&42));
221 assert!(arena.contains(id));
222 assert_eq!(arena.len(), 1);
223 }
224
225 #[test]
226 fn removed_id_becomes_stale() {
227 let mut arena = Arena::new();
228 let id = arena.insert(7u32);
229 assert_eq!(arena.remove(id), Some(7));
230 assert!(!arena.contains(id));
231 assert_eq!(arena.get(id), None);
232 assert!(arena.is_empty());
233 }
234
235 #[test]
236 fn reused_slot_invalidates_previous_handle() {
237 let mut arena = Arena::new();
238 let first = arena.insert(1u32);
239 arena.remove(first);
240 let second = arena.insert(2u32);
241 assert_eq!(first.index(), second.index());
244 assert_ne!(first, second);
245 assert_eq!(arena.get(first), None);
246 assert_eq!(arena.get(second), Some(&2));
247 }
248
249 #[test]
250 fn iter_yields_live_pairs() {
251 let mut arena = Arena::new();
252 let a = arena.insert("a");
253 let b = arena.insert("b");
254 let c = arena.insert("c");
255 arena.remove(b);
256 let mut seen: Vec<&str> = arena.iter().map(|(_, v)| *v).collect();
257 seen.sort_unstable();
258 assert_eq!(seen, ["a", "c"]);
259 assert!(arena.contains(a) && arena.contains(c));
260 }
261}