1use std::{
9 fmt::{Debug, Formatter},
10 iter::Zip,
11 ops::{Index, IndexMut},
12 slice, vec,
13};
14
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16
17use crate::registry::{Identified, Identifier};
18
19const DEAD: usize = usize::MAX;
20
21#[derive(Clone, PartialEq, Eq)]
23pub struct StableArena<Id: Identifier, T> {
24 values: Vec<T>,
25 slot_ids: Vec<Id>,
26 locations: Vec<usize>,
27}
28
29impl<Id: Identifier, T> StableArena<Id, T> {
30 pub fn push(&mut self, value: T) -> Id {
32 let raw = self.locations.len();
33 assert!(raw < DEAD, "StableArena identifier space exhausted");
34 let id = Id::from(raw);
35 assert_eq!(
36 Into::<usize>::into(id),
37 raw,
38 "StableArena identifier does not round-trip through its backing type"
39 );
40
41 let slot = self.values.len();
42 assert!(slot < DEAD, "StableArena physical slot space exhausted");
43 self.values.push(value);
44 self.slot_ids.push(id);
45 self.locations.push(slot);
46 id
47 }
48
49 pub fn len(&self) -> usize {
51 self.values.len()
52 }
53
54 pub fn issued_len(&self) -> usize {
56 self.locations.len()
57 }
58
59 pub fn capacity(&self) -> usize {
61 self.values.capacity()
62 }
63
64 pub fn structural_bytes(&self) -> usize {
68 self.values
69 .capacity()
70 .saturating_mul(std::mem::size_of::<T>())
71 .saturating_add(
72 self.slot_ids
73 .capacity()
74 .saturating_mul(std::mem::size_of::<Id>()),
75 )
76 .saturating_add(
77 self.locations
78 .capacity()
79 .saturating_mul(std::mem::size_of::<usize>()),
80 )
81 }
82
83 pub fn is_empty(&self) -> bool {
85 self.values.is_empty()
86 }
87
88 pub fn shrink_to_fit(&mut self) {
96 self.values.shrink_to_fit();
97 self.slot_ids.shrink_to_fit();
98 self.locations.shrink_to_fit();
99 }
100
101 pub fn contains(&self, id: Id) -> bool {
103 self.live_slot(id).is_some()
104 }
105
106 pub fn get(&self, id: Id) -> Option<Identified<Id, &T>> {
108 let slot = self.live_slot(id)?;
109 Some(Identified::new(id, &self.values[slot]))
110 }
111
112 pub fn get_mut(&mut self, id: Id) -> Option<Identified<Id, &mut T>> {
114 let slot = self.live_slot(id)?;
115 Some(Identified::new(id, &mut self.values[slot]))
116 }
117
118 pub fn remove(&mut self, id: Id) -> T {
124 let raw = id.into();
125 let slot = self.live_slot(id).unwrap_or_else(|| {
126 panic!(
127 "StableArena::remove: dead or unknown id {id:?} (issued {}, live {})",
128 self.issued_len(),
129 self.len()
130 )
131 });
132
133 self.locations[raw] = DEAD;
134 let removed = self.values.swap_remove(slot);
135 let removed_id = self.slot_ids.swap_remove(slot);
136 debug_assert_eq!(removed_id, id);
137
138 if slot < self.values.len() {
139 let moved_id = self.slot_ids[slot];
140 self.locations[Into::<usize>::into(moved_id)] = slot;
141 }
142 removed
143 }
144
145 pub fn clear(&mut self) {
153 self.values.clear();
154 self.slot_ids.clear();
155 self.locations.clear();
156 }
157
158 pub fn truncate_issued(&mut self, issued: usize) {
166 for raw in (issued..self.locations.len()).rev() {
167 let id = Id::from(raw);
168 if self.contains(id) {
169 self.remove(id);
170 }
171 }
172 self.locations.truncate(issued);
173 }
174
175 pub fn iter(&self) -> Iter<'_, Id, T> {
177 Iter {
178 inner: self.slot_ids.iter().zip(self.values.iter()),
179 }
180 }
181
182 pub fn iter_mut(&mut self) -> IterMut<'_, Id, T> {
184 IterMut {
185 inner: self.slot_ids.iter().zip(self.values.iter_mut()),
186 }
187 }
188
189 #[inline]
190 fn live_slot(&self, id: Id) -> Option<usize> {
191 let slot = *self.locations.get(Into::<usize>::into(id))?;
192 (slot != DEAD).then_some(slot)
193 }
194}
195
196impl<Id: Identifier, T> Default for StableArena<Id, T> {
197 fn default() -> Self {
198 Self {
199 values: Vec::new(),
200 slot_ids: Vec::new(),
201 locations: Vec::new(),
202 }
203 }
204}
205
206impl<Id: Identifier, T: Debug> Debug for StableArena<Id, T> {
207 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208 f.debug_struct("StableArena")
209 .field("issued", &self.issued_len())
210 .field(
211 "entries",
212 &self
213 .iter()
214 .map(|entry| (entry.id, entry.inner))
215 .collect::<Vec<_>>(),
216 )
217 .finish()
218 }
219}
220
221impl<Id: Identifier, T> Index<Id> for StableArena<Id, T> {
222 type Output = T;
223
224 fn index(&self, id: Id) -> &Self::Output {
225 self.get(id).map(|entry| entry.inner).unwrap_or_else(|| {
226 panic!(
227 "StableArena index: dead or unknown id {id:?} (issued {}, live {})",
228 self.issued_len(),
229 self.len()
230 )
231 })
232 }
233}
234
235impl<Id: Identifier, T> IndexMut<Id> for StableArena<Id, T> {
236 fn index_mut(&mut self, id: Id) -> &mut Self::Output {
237 let issued = self.issued_len();
238 let live = self.len();
239 self.get_mut(id)
240 .map(|entry| entry.inner)
241 .unwrap_or_else(|| {
242 panic!(
243 "StableArena mutable index: dead or unknown id {id:?} (issued {issued}, live {live})"
244 )
245 })
246 }
247}
248
249pub struct Iter<'a, Id: Identifier, T> {
251 inner: Zip<slice::Iter<'a, Id>, slice::Iter<'a, T>>,
252}
253
254impl<'a, Id: Identifier, T> Iterator for Iter<'a, Id, T> {
255 type Item = Identified<Id, &'a T>;
256
257 fn next(&mut self) -> Option<Self::Item> {
258 let (id, value) = self.inner.next()?;
259 Some(Identified::new(*id, value))
260 }
261
262 fn size_hint(&self) -> (usize, Option<usize>) {
263 self.inner.size_hint()
264 }
265}
266
267impl<Id: Identifier, T> ExactSizeIterator for Iter<'_, Id, T> {}
268
269pub struct IterMut<'a, Id: Identifier, T> {
271 inner: Zip<slice::Iter<'a, Id>, slice::IterMut<'a, T>>,
272}
273
274impl<'a, Id: Identifier, T> Iterator for IterMut<'a, Id, T> {
275 type Item = Identified<Id, &'a mut T>;
276
277 fn next(&mut self) -> Option<Self::Item> {
278 let (id, value) = self.inner.next()?;
279 Some(Identified::new(*id, value))
280 }
281
282 fn size_hint(&self) -> (usize, Option<usize>) {
283 self.inner.size_hint()
284 }
285}
286
287impl<Id: Identifier, T> ExactSizeIterator for IterMut<'_, Id, T> {}
288
289pub struct IntoIter<Id: Identifier, T> {
291 inner: Zip<vec::IntoIter<Id>, vec::IntoIter<T>>,
292}
293
294impl<Id: Identifier, T> Iterator for IntoIter<Id, T> {
295 type Item = Identified<Id, T>;
296
297 fn next(&mut self) -> Option<Self::Item> {
298 let (id, value) = self.inner.next()?;
299 Some(Identified::new(id, value))
300 }
301
302 fn size_hint(&self) -> (usize, Option<usize>) {
303 self.inner.size_hint()
304 }
305}
306
307impl<Id: Identifier, T> ExactSizeIterator for IntoIter<Id, T> {}
308
309impl<'a, Id: Identifier, T> IntoIterator for &'a StableArena<Id, T> {
310 type Item = Identified<Id, &'a T>;
311 type IntoIter = Iter<'a, Id, T>;
312
313 fn into_iter(self) -> Self::IntoIter {
314 self.iter()
315 }
316}
317
318impl<'a, Id: Identifier, T> IntoIterator for &'a mut StableArena<Id, T> {
319 type Item = Identified<Id, &'a mut T>;
320 type IntoIter = IterMut<'a, Id, T>;
321
322 fn into_iter(self) -> Self::IntoIter {
323 self.iter_mut()
324 }
325}
326
327impl<Id: Identifier, T> IntoIterator for StableArena<Id, T> {
328 type Item = Identified<Id, T>;
329 type IntoIter = IntoIter<Id, T>;
330
331 fn into_iter(self) -> Self::IntoIter {
332 IntoIter {
333 inner: self.slot_ids.into_iter().zip(self.values),
334 }
335 }
336}
337
338impl<Id: Identifier, T> FromIterator<T> for StableArena<Id, T> {
339 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
340 let mut arena = Self::default();
341 for value in iter {
342 arena.push(value);
343 }
344 arena
345 }
346}
347
348#[derive(Serialize)]
349struct StableArenaWireRef<'a, T> {
350 next_id: usize,
351 entries: Vec<(usize, &'a T)>,
352}
353
354#[derive(Serialize, Deserialize)]
355struct StableArenaWire<T> {
356 next_id: usize,
357 entries: Vec<(usize, T)>,
358}
359
360impl<Id: Identifier, T: Serialize> Serialize for StableArena<Id, T> {
361 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
362 where
363 S: Serializer,
364 {
365 StableArenaWireRef {
366 next_id: self.issued_len(),
367 entries: self
368 .slot_ids
369 .iter()
370 .copied()
371 .map(Into::<usize>::into)
372 .zip(self.values.iter())
373 .collect(),
374 }
375 .serialize(serializer)
376 }
377}
378
379impl<'de, Id: Identifier, T: Deserialize<'de>> Deserialize<'de> for StableArena<Id, T> {
380 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
381 where
382 D: Deserializer<'de>,
383 {
384 let StableArenaWire { next_id, entries } = StableArenaWire::deserialize(deserializer)?;
385 if next_id == DEAD {
386 return Err(serde::de::Error::custom(
387 "StableArena next ID exhausts the location sentinel",
388 ));
389 }
390 if let Some(last_issued) = next_id.checked_sub(1)
391 && Into::<usize>::into(Id::from(last_issued)) != last_issued
392 {
393 return Err(serde::de::Error::custom(format!(
394 "StableArena next ID {next_id} exceeds its backing type"
395 )));
396 }
397
398 let mut arena = Self {
399 values: Vec::with_capacity(entries.len()),
400 slot_ids: Vec::with_capacity(entries.len()),
401 locations: vec![DEAD; next_id],
402 };
403 for (raw, value) in entries {
404 if raw >= next_id {
405 return Err(serde::de::Error::custom(format!(
406 "StableArena live ID {raw} is outside next ID {next_id}"
407 )));
408 }
409 let id = Id::from(raw);
410 if Into::<usize>::into(id) != raw {
411 return Err(serde::de::Error::custom(format!(
412 "StableArena ID {raw} does not fit its backing type"
413 )));
414 }
415 if arena.locations[raw] != DEAD {
416 return Err(serde::de::Error::custom(format!(
417 "StableArena contains duplicate live ID {raw}"
418 )));
419 }
420 let slot = arena.values.len();
421 arena.locations[raw] = slot;
422 arena.slot_ids.push(id);
423 arena.values.push(value);
424 }
425 Ok(arena)
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432 use jstd_derive::Identifier;
433
434 #[derive(Identifier)]
435 struct Id(u32);
436
437 #[test]
438 fn clear_starts_a_new_epoch_with_the_old_capacity() {
439 let mut arena = StableArena::<Id, &str>::default();
440 let a = arena.push("a");
441 arena.push("b");
442 arena.remove(a);
443 let capacity = arena.capacity();
444
445 arena.clear();
446 assert!(arena.is_empty());
447 assert_eq!(arena.issued_len(), 0);
448 assert_eq!(arena.capacity(), capacity);
449 assert_eq!(arena.push("c"), a, "ids are issued again");
450 assert_eq!(arena[a], "c");
451 }
452
453 #[test]
454 fn truncate_issued_takes_back_the_newest_ids() {
455 let mut arena = StableArena::<Id, &str>::default();
456 let a = arena.push("a");
457 let b = arena.push("b");
458 let issued = arena.issued_len();
459 let c = arena.push("c");
460 let d = arena.push("d");
461 arena.remove(c);
462
463 arena.truncate_issued(issued);
464 assert_eq!(arena.issued_len(), issued);
465 assert!(!arena.contains(d));
466 assert_eq!(
467 arena.iter().map(|entry| entry.id).collect::<Vec<_>>(),
468 [a, b],
469 "the surviving entries keep their order"
470 );
471 assert_eq!(arena.push("e"), c, "the taken-back ids are reissued");
472 }
473
474 #[test]
475 fn removal_repairs_moved_slot_and_never_reuses_ids() {
476 let mut arena = StableArena::<Id, &str>::default();
477 let a = arena.push("a");
478 let b = arena.push("b");
479 let c = arena.push("c");
480
481 assert_eq!(arena.remove(b), "b");
482 assert!(!arena.contains(b));
483 assert_eq!(arena.get(b).map(|entry| **entry), None);
484 assert_eq!(arena[c], "c");
485 assert_eq!(arena[a], "a");
486 assert_eq!(
487 arena.iter().map(|entry| entry.id).collect::<Vec<_>>(),
488 [a, c]
489 );
490
491 let d = arena.push("d");
492 assert_eq!(usize::from(d), 3);
493 assert_eq!(arena.issued_len(), 4);
494 assert_eq!(arena.len(), 3);
495 }
496
497 #[test]
498 fn removes_first_last_and_only_entries() {
499 let mut arena = StableArena::<Id, i32>::default();
500 let a = arena.push(1);
501 let b = arena.push(2);
502 let c = arena.push(3);
503 assert_eq!(arena.remove(a), 1);
504 assert_eq!(arena.remove(c), 3);
505 assert_eq!(arena.remove(b), 2);
506 assert!(arena.is_empty());
507 assert_eq!(arena.issued_len(), 3);
508 }
509
510 #[test]
511 #[should_panic(expected = "dead or unknown id")]
512 fn indexing_removed_id_panics() {
513 let mut arena = StableArena::<Id, i32>::default();
514 let id = arena.push(1);
515 arena.remove(id);
516 let _ = arena[id];
517 }
518
519 #[test]
520 #[should_panic(expected = "dead or unknown id")]
521 fn double_remove_panics() {
522 let mut arena = StableArena::<Id, i32>::default();
523 let id = arena.push(1);
524 arena.remove(id);
525 arena.remove(id);
526 }
527
528 #[test]
529 fn mutable_and_consuming_iteration_keep_stable_ids() {
530 let mut arena = StableArena::<Id, i32>::default();
531 let a = arena.push(1);
532 let b = arena.push(2);
533 let c = arena.push(3);
534 arena.remove(b);
535 for mut entry in &mut arena {
536 **entry += 10;
537 }
538 let entries = arena
539 .into_iter()
540 .map(|entry| (entry.id, entry.inner))
541 .collect::<Vec<_>>();
542 assert_eq!(entries, [(a, 11), (c, 13)]);
543 }
544
545 #[test]
546 fn shrink_to_fit_preserves_ids_order_and_liveness() {
547 let mut arena = StableArena::<Id, u64>::default();
548 let ids = (0..1_000).map(|step| arena.push(step)).collect::<Vec<_>>();
549 for id in &ids[..900] {
550 arena.remove(*id);
551 }
552 let before = arena.clone();
553 arena.shrink_to_fit();
554 assert_eq!(arena, before);
555 assert!(arena.capacity() < 1_000);
556 assert_eq!(arena.len(), 100);
557 assert_eq!(arena.issued_len(), 1_000);
558 assert_eq!(arena[ids[950]], 950);
559 let next = arena.push(1_000);
560 assert_eq!(usize::from(next), 1_000);
561 }
562
563 #[test]
564 fn clone_and_equality_preserve_holes_and_physical_order() {
565 let mut arena = StableArena::<Id, i32>::default();
566 arena.push(1);
567 let removed = arena.push(2);
568 arena.push(3);
569 arena.remove(removed);
570 let clone = arena.clone();
571 assert_eq!(clone, arena);
572 assert_eq!(
573 clone.iter().map(|entry| entry.id).collect::<Vec<_>>(),
574 arena.iter().map(|entry| entry.id).collect::<Vec<_>>()
575 );
576 }
577
578 #[test]
579 fn serde_round_trip_preserves_holes_order_and_cursor() {
580 let mut arena = StableArena::<Id, String>::default();
581 let a = arena.push("a".into());
582 let b = arena.push("b".into());
583 let c = arena.push("c".into());
584 arena.remove(a);
585 arena.remove(b);
586 let bytes = bincode::serde::encode_to_vec(&arena, bincode::config::standard()).unwrap();
587 let (mut decoded, used): (StableArena<Id, String>, _) =
588 bincode::serde::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
589 assert_eq!(used, bytes.len());
590 assert_eq!(decoded, arena);
591 assert_eq!(decoded[c], "c");
592 let d = decoded.push("d".into());
593 assert_eq!(usize::from(d), 3);
594
595 decoded.remove(c);
596 decoded.remove(d);
597 let bytes = bincode::serde::encode_to_vec(&decoded, bincode::config::standard()).unwrap();
598 let (empty, _): (StableArena<Id, String>, _) =
599 bincode::serde::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
600 assert!(empty.is_empty());
601 assert_eq!(empty.issued_len(), 4);
602 }
603
604 #[test]
605 fn malformed_wire_is_rejected() {
606 let duplicate = StableArenaWire {
607 next_id: 2,
608 entries: vec![(0, 1_i32), (0, 2)],
609 };
610 let bytes = bincode::serde::encode_to_vec(duplicate, bincode::config::standard()).unwrap();
611 assert!(
612 bincode::serde::decode_from_slice::<StableArena<Id, i32>, _>(
613 &bytes,
614 bincode::config::standard()
615 )
616 .is_err()
617 );
618
619 let outside = StableArenaWire {
620 next_id: 1,
621 entries: vec![(1, 1_i32)],
622 };
623 let bytes = bincode::serde::encode_to_vec(outside, bincode::config::standard()).unwrap();
624 assert!(
625 bincode::serde::decode_from_slice::<StableArena<Id, i32>, _>(
626 &bytes,
627 bincode::config::standard()
628 )
629 .is_err()
630 );
631
632 let too_wide = StableArenaWire {
633 next_id: u32::MAX as usize + 2,
634 entries: Vec::<(usize, i32)>::new(),
635 };
636 let bytes = bincode::serde::encode_to_vec(too_wide, bincode::config::standard()).unwrap();
637 assert!(
638 bincode::serde::decode_from_slice::<StableArena<Id, i32>, _>(
639 &bytes,
640 bincode::config::standard()
641 )
642 .is_err()
643 );
644 }
645
646 #[test]
647 fn deterministic_mixed_operations_match_option_vec_model() {
648 let mut arena = StableArena::<Id, u64>::default();
649 let mut model: Vec<Option<u64>> = Vec::new();
650 let mut state = 0x1234_5678_9abc_def0_u64;
651
652 for step in 0..2_000_u64 {
653 state = state
654 .wrapping_mul(6_364_136_223_846_793_005)
655 .wrapping_add(1);
656 let live = model
657 .iter()
658 .enumerate()
659 .filter_map(|(id, value)| value.as_ref().map(|_| id))
660 .collect::<Vec<_>>();
661 if live.is_empty() || state & 3 != 0 {
662 let id = arena.push(step);
663 assert_eq!(usize::from(id), model.len());
664 model.push(Some(step));
665 } else {
666 let raw = live[state as usize % live.len()];
667 let expected = model[raw].take().unwrap();
668 assert_eq!(arena.remove(Id::from(raw)), expected);
669 }
670
671 for (raw, expected) in model.iter().enumerate() {
672 assert_eq!(
673 arena.get(Id::from(raw)).map(|entry| **entry),
674 *expected,
675 "model mismatch at step {step}, id {raw}"
676 );
677 }
678 }
679 }
680
681 #[test]
682 fn public_views_iteration_and_capacity_accounting_work() {
683 let mut arena = StableArena::<Id, i32>::default();
684 assert!(arena.is_empty());
685 assert_eq!(arena.structural_bytes(), 0);
686
687 let first = arena.push(1);
688 let second = arena.push(2);
689 let capacity_before = arena.capacity();
690 assert!(arena.structural_bytes() >= capacity_before * std::mem::size_of::<i32>());
691 assert_eq!(arena.get(first).unwrap().id, first);
692 **arena.get_mut(second).unwrap() = 20;
693 arena[first] = 10;
694 assert_eq!(arena[first], 10);
695 assert_eq!(arena[second], 20);
696
697 let mut entries = arena.iter();
698 assert_eq!(entries.size_hint(), (2, Some(2)));
699 assert_eq!(entries.next().unwrap().id, first);
700 assert_eq!(entries.next().unwrap().id, second);
701 assert!(entries.next().is_none());
702 assert!(format!("{arena:?}").contains("issued"));
703
704 let rebuilt: StableArena<Id, i32> = [3, 4].into_iter().collect();
705 assert_eq!(
706 rebuilt.iter().map(|entry| *entry.inner).collect::<Vec<_>>(),
707 [3, 4]
708 );
709 }
710}