1use alloc::vec::Vec;
14use core::num::NonZeroU32;
15use core::ops::{Index, IndexMut};
16
17#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub struct NodeId {
26 index: u32,
27 generation: NonZeroU32,
30}
31
32impl NodeId {
33 const NONE: Self = Self {
35 index: u32::MAX,
36 generation: NonZeroU32::MIN,
37 };
38
39 #[inline]
43 pub fn as_ffi(self) -> u64 {
44 (u64::from(self.generation.get()) << 32) | u64::from(self.index.wrapping_add(1))
45 }
46
47 #[inline]
50 pub fn from_ffi(value: u64) -> Self {
51 let (slot, generation) = (value as u32, (value >> 32) as u32);
53 match (slot.checked_sub(1), NonZeroU32::new(generation)) {
54 (Some(index), Some(generation)) => Self { index, generation },
55 _ => Self::NONE,
56 }
57 }
58}
59
60impl Default for NodeId {
61 fn default() -> Self {
63 Self::NONE
64 }
65}
66
67impl core::fmt::Debug for NodeId {
68 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
69 write!(f, "NodeId({}v{})", self.index, self.generation)
70 }
71}
72
73enum Entry<T> {
74 Occupied(T),
75 Free(Option<u32>),
77}
78
79struct Slot<T> {
80 generation: NonZeroU32,
83 entry: Entry<T>,
84}
85
86pub(crate) struct Arena<T> {
87 slots: Vec<Slot<T>>,
88 free: Option<u32>,
89 len: usize,
90}
91
92impl<T> Arena<T> {
93 pub(crate) const fn new() -> Self {
94 Self {
95 slots: Vec::new(),
96 free: None,
97 len: 0,
98 }
99 }
100
101 pub(crate) fn len(&self) -> usize {
102 self.len
103 }
104
105 pub(crate) fn insert(&mut self, value: T) -> NodeId {
106 self.len += 1;
107 if let Some(index) = self.free {
108 let slot = &mut self.slots[index as usize];
109 let Entry::Free(next) = slot.entry else {
110 unreachable!("the free list only threads free slots");
111 };
112 self.free = next;
113 slot.entry = Entry::Occupied(value);
114 return NodeId {
115 index,
116 generation: slot.generation,
117 };
118 }
119 let index = u32::try_from(self.slots.len())
121 .ok()
122 .filter(|&index| index < u32::MAX)
123 .expect("a tree of four thousand million nodes");
124 let generation = NonZeroU32::MIN;
125 self.slots.push(Slot {
126 generation,
127 entry: Entry::Occupied(value),
128 });
129 NodeId { index, generation }
130 }
131
132 pub(crate) fn remove(&mut self, id: NodeId) -> Option<T> {
133 let slot = self.slots.get_mut(id.index as usize)?;
134 if slot.generation != id.generation || matches!(slot.entry, Entry::Free(_)) {
135 return None;
136 }
137 let entry = match slot.generation.checked_add(1) {
142 Some(next) => {
143 slot.generation = next;
144 Entry::Free(self.free.replace(id.index))
145 }
146 None => Entry::Free(None),
147 };
148 self.len -= 1;
149 match core::mem::replace(&mut slot.entry, entry) {
150 Entry::Occupied(value) => Some(value),
151 Entry::Free(_) => unreachable!("checked above"),
152 }
153 }
154
155 pub(crate) fn get(&self, id: NodeId) -> Option<&T> {
156 match self.slots.get(id.index as usize) {
157 Some(Slot {
158 generation,
159 entry: Entry::Occupied(value),
160 }) if *generation == id.generation => Some(value),
161 _ => None,
162 }
163 }
164
165 pub(crate) fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
166 match self.slots.get_mut(id.index as usize) {
167 Some(Slot {
168 generation,
169 entry: Entry::Occupied(value),
170 }) if *generation == id.generation => Some(value),
171 _ => None,
172 }
173 }
174
175 pub(crate) fn contains_key(&self, id: NodeId) -> bool {
176 self.get(id).is_some()
177 }
178}
179
180impl<T> Index<NodeId> for Arena<T> {
181 type Output = T;
182
183 fn index(&self, id: NodeId) -> &T {
184 self.get(id).expect("a node that is no longer in the tree")
185 }
186}
187
188impl<T> IndexMut<NodeId> for Arena<T> {
189 fn index_mut(&mut self, id: NodeId) -> &mut T {
190 self.get_mut(id)
191 .expect("a node that is no longer in the tree")
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn ffi_round_trip_preserves_identity() {
201 let mut arena = Arena::new();
202 let a = arena.insert(1);
203 let b = arena.insert(2);
204 assert_eq!(NodeId::from_ffi(a.as_ffi()), a);
205 assert_eq!(NodeId::from_ffi(b.as_ffi()), b);
206 assert_ne!(a.as_ffi(), b.as_ffi());
207 }
208
209 #[test]
210 fn the_first_id_is_the_one_c_callers_have_always_seen() {
211 let mut arena = Arena::new();
213 assert_eq!(arena.insert(()).as_ffi(), 0x0000_0001_0000_0001);
214 }
215
216 #[test]
217 fn no_id_crosses_the_abi_as_zero_and_zero_names_nothing() {
218 let mut arena = Arena::new();
219 let first = arena.insert(1);
220 assert_ne!(first.as_ffi(), 0);
221 assert_eq!(arena.get(NodeId::from_ffi(0)), None);
222 assert_eq!(arena.get(NodeId::default()), None);
223 }
224
225 #[test]
226 fn nonsense_from_the_other_side_of_the_abi_resolves_to_nothing() {
227 let mut arena = Arena::new();
228 arena.insert(1);
229 for value in [
230 1,
231 1 << 32,
232 u64::MAX,
233 0xdead_beef_0000_0001,
234 0x0000_0001_0000_0009,
235 ] {
236 assert_eq!(arena.get(NodeId::from_ffi(value)), None, "{value:#x}");
237 }
238 }
239
240 #[test]
241 fn a_stale_id_does_not_resolve_to_the_next_node() {
242 let mut arena = Arena::new();
243 let a = arena.insert(1);
244 assert_eq!(arena.remove(a), Some(1));
245 let b = arena.insert(2);
246 assert_ne!(a, b);
247 assert_eq!(arena.get(a), None);
248 assert_eq!(arena.get_mut(a), None);
249 assert!(!arena.contains_key(a));
250 assert_eq!(arena.remove(a), None, "and cannot take the new tenant out");
251 assert_eq!(arena.get(b), Some(&2));
252 }
253
254 #[test]
255 fn a_vacated_slot_is_used_again_before_the_arena_grows() {
256 let mut arena = Arena::new();
257 let ids: Vec<NodeId> = (0..4).map(|n| arena.insert(n)).collect();
258 arena.remove(ids[1]);
259 arena.remove(ids[2]);
260 assert_eq!(arena.len(), 2);
261 let (c, d, e) = (arena.insert(10), arena.insert(11), arena.insert(12));
262 assert_eq!(arena.slots.len(), 5, "two reused, one new");
263 assert_eq!(arena.len(), 5);
264 assert_eq!((arena[c], arena[d], arena[e]), (10, 11, 12));
265 assert_eq!((arena[ids[0]], arena[ids[3]]), (0, 3));
266 }
267
268 #[test]
269 fn removing_twice_takes_nothing_the_second_time() {
270 let mut arena = Arena::new();
271 let a = arena.insert(1);
272 let b = arena.insert(2);
273 assert_eq!(arena.remove(a), Some(1));
274 assert_eq!(arena.remove(a), None);
275 assert_eq!(arena.len(), 1);
276 let c = arena.insert(3);
278 let d = arena.insert(4);
279 assert_eq!((arena[b], arena[c], arena[d]), (2, 3, 4));
280 }
281
282 #[test]
283 fn a_slot_out_of_generations_is_retired_not_wrapped() {
284 let mut arena = Arena::new();
285 let first = arena.insert(1);
286 arena.remove(first);
287 arena.slots[0].generation = NonZeroU32::MAX;
288 let last = arena.insert(2);
289 assert_eq!(last.generation, NonZeroU32::MAX);
290 assert_eq!(arena.remove(last), Some(2));
291 assert_eq!(arena.get(last), None);
292 assert_eq!(arena.len(), 0);
293
294 let next = arena.insert(3);
295 assert_eq!(next.index, 1, "the worn-out slot is not handed out again");
296 assert_eq!(arena.get(first), None);
297 assert_eq!(arena.get(last), None);
298 }
299
300 #[test]
301 fn an_optional_id_is_no_bigger_than_an_id() {
302 assert_eq!(size_of::<Option<NodeId>>(), size_of::<NodeId>());
303 assert_eq!(size_of::<NodeId>(), 8);
304 }
305
306 #[test]
307 #[should_panic(expected = "no longer in the tree")]
308 fn indexing_with_a_stale_id_panics() {
309 let mut arena = Arena::new();
310 let a = arena.insert(1);
311 arena.remove(a);
312 let _ = arena[a];
313 }
314}