1use fast_mesh_store::StoreError;
4
5use crate::{Result, SceneError};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct MeshId {
13 index: u32,
14 generation: u32,
15}
16
17impl MeshId {
18 pub fn index(self) -> u32 {
22 self.index
23 }
24
25 pub fn generation(self) -> u32 {
27 self.generation
28 }
29}
30
31struct Slot<T> {
32 generation: u32,
33 value: Option<T>,
34}
35
36pub(crate) struct SlotMap<T> {
38 slots: Vec<Slot<T>>,
39 free: Vec<u32>,
41}
42
43fn oom() -> SceneError {
44 SceneError::Store(StoreError::OutOfMemory)
45}
46
47impl<T> SlotMap<T> {
48 pub(crate) fn new() -> Self {
49 SlotMap {
50 slots: Vec::new(),
51 free: Vec::new(),
52 }
53 }
54
55 pub(crate) fn insert(&mut self, value: T) -> Result<MeshId> {
57 if let Some(index) = self.free.pop() {
58 let slot = &mut self.slots[index as usize];
59 slot.value = Some(value);
60 return Ok(MeshId {
61 index,
62 generation: slot.generation,
63 });
64 }
65 let index = u32::try_from(self.slots.len()).map_err(|_| oom())?;
66 self.slots.try_reserve(1).map_err(|_| oom())?;
67 self.slots.push(Slot {
68 generation: 0,
69 value: Some(value),
70 });
71 Ok(MeshId {
72 index,
73 generation: 0,
74 })
75 }
76
77 pub(crate) fn remove(&mut self, id: MeshId) -> Option<T> {
79 let slot = self.slots.get_mut(id.index as usize)?;
80 if slot.generation != id.generation || slot.value.is_none() {
81 return None;
82 }
83 let value = slot.value.take();
84 if let Some(next) = slot.generation.checked_add(1) {
87 slot.generation = next;
88 if self.free.try_reserve(1).is_ok() {
89 self.free.push(id.index);
90 }
91 }
92 value
93 }
94
95 pub(crate) fn live_id(&self, index: u32, generation: u32) -> Option<MeshId> {
97 let id = MeshId { index, generation };
98 self.get(id).map(|_| id)
99 }
100
101 pub(crate) fn get(&self, id: MeshId) -> Option<&T> {
102 let slot = self.slots.get(id.index as usize)?;
103 if slot.generation == id.generation {
104 slot.value.as_ref()
105 } else {
106 None
107 }
108 }
109
110 pub(crate) fn get_mut(&mut self, id: MeshId) -> Option<&mut T> {
111 let slot = self.slots.get_mut(id.index as usize)?;
112 if slot.generation == id.generation {
113 slot.value.as_mut()
114 } else {
115 None
116 }
117 }
118
119 pub(crate) fn iter(&self) -> impl Iterator<Item = (MeshId, &T)> {
121 self.slots.iter().enumerate().filter_map(|(i, s)| {
122 s.value.as_ref().map(|v| {
123 (
124 MeshId {
125 index: i as u32,
126 generation: s.generation,
127 },
128 v,
129 )
130 })
131 })
132 }
133
134 pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = (MeshId, &mut T)> {
136 self.slots.iter_mut().enumerate().filter_map(|(i, s)| {
137 let generation = s.generation;
138 s.value.as_mut().map(|v| {
139 (
140 MeshId {
141 index: i as u32,
142 generation,
143 },
144 v,
145 )
146 })
147 })
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn reuse_bumps_generation() {
157 let mut m = SlotMap::new();
158 let a = m.insert("a").unwrap();
159 assert_eq!(m.remove(a), Some("a"));
160 assert_eq!(m.remove(a), None);
161 let b = m.insert("b").unwrap();
162 assert_eq!(a.index, b.index);
163 assert_ne!(a, b);
164 assert!(m.get(a).is_none());
165 assert_eq!(m.get(b), Some(&"b"));
166 }
167}