1use core::{marker::PhantomData, mem};
2
3use alloc::vec::Vec;
4
5enum SlotContent<T> {
6 Unoccupied { prev_unoccupied: Option<usize> },
7 Occupied { item: T },
8}
9
10struct Slot<T> {
11 generation: u64,
12 content: SlotContent<T>,
13}
14
15pub struct SlotMap<T> {
19 slots: Vec<Slot<T>>,
20 last_unoccupied: Option<usize>,
21}
22
23impl<T> Default for SlotMap<T> {
24 fn default() -> Self {
25 Self {
26 slots: Vec::new(),
27 last_unoccupied: None,
28 }
29 }
30}
31
32pub struct SlotMapKey<T> {
33 index: usize,
34 generation: u64,
35 phantom: PhantomData<T>,
36}
37
38impl<T> SlotMap<T> {
39 pub fn insert(&mut self, item: T) -> SlotMapKey<T> {
40 match self.last_unoccupied {
41 Some(last_unoccupied) => {
42 let slot = &mut self.slots[last_unoccupied];
43 let SlotContent::Unoccupied { prev_unoccupied } = slot.content else {
44 unreachable!("last unoccupied slot in slotmap must be unoccupied")
45 };
46 self.last_unoccupied = prev_unoccupied;
47
48 slot.content = SlotContent::Occupied { item };
49 SlotMapKey {
50 index: last_unoccupied,
51 generation: slot.generation,
52 phantom: PhantomData,
53 }
54 }
55 None => {
56 let index = self.slots.len();
57 let generation = 0;
58 self.slots.push(Slot {
59 generation,
60 content: SlotContent::Occupied { item },
61 });
62 SlotMapKey {
63 index,
64 generation,
65 phantom: PhantomData,
66 }
67 }
68 }
69 }
70
71 #[allow(unused)]
72 pub fn get(&self, key: &SlotMapKey<T>) -> Option<&T> {
73 let slot = self.slots.get(key.index)?;
74 if slot.generation != key.generation {
75 return None;
76 }
77 match &slot.content {
78 SlotContent::Occupied { item } => Some(item),
79 SlotContent::Unoccupied { .. } => None,
80 }
81 }
82
83 pub fn get_mut(&mut self, key: &SlotMapKey<T>) -> Option<&mut T> {
84 let slot = self.slots.get_mut(key.index)?;
85 if slot.generation != key.generation {
86 return None;
87 }
88 match &mut slot.content {
89 SlotContent::Occupied { item } => Some(item),
90 SlotContent::Unoccupied { .. } => None,
91 }
92 }
93
94 pub fn remove(&mut self, key: &SlotMapKey<T>) -> Option<T> {
95 let slot = self.slots.get_mut(key.index)?;
96 if slot.generation != key.generation
97 || matches!(slot.content, SlotContent::Unoccupied { .. })
98 {
99 return None;
100 }
101
102 let new_slot = if let Some(generation) = slot.generation.checked_add(1) {
103 let prev_unoccupied = self.last_unoccupied;
104 self.last_unoccupied = Some(key.index);
105 Slot {
106 generation,
107 content: SlotContent::Unoccupied { prev_unoccupied },
108 }
109 } else {
110 Slot {
112 generation: 0,
113 content: SlotContent::Unoccupied {
114 prev_unoccupied: None,
115 },
116 }
117 };
118 let previous_slot = mem::replace(slot, new_slot);
119
120 let SlotContent::Occupied { item } = previous_slot.content else {
121 unreachable!("slot was full")
122 };
123
124 Some(item)
125 }
126}
127
128#[test]
129fn test() {
130 let mut slotmap = SlotMap::<i32>::default();
131 let key = slotmap.insert(5);
132 assert_eq!(slotmap.get(&key), Some(&5));
133 slotmap.remove(&key);
134 assert_eq!(slotmap.get(&key), None);
135 let key2 = slotmap.insert(10);
136 assert_eq!(slotmap.get(&key), None);
137 assert_eq!(slotmap.get(&key2), Some(&10));
138 let n = slotmap.get_mut(&key2).unwrap();
139 *n = 42;
140 assert_eq!(slotmap.get(&key2), Some(&42));
141}