dusk_wasmtime/runtime/component/
resource_table.rs1use super::Resource;
2use std::any::Any;
3use std::collections::{BTreeSet, HashMap};
4
5#[derive(Debug)]
6pub enum ResourceTableError {
8 Full,
10 NotPresent,
12 WrongType,
14 HasChildren,
17}
18
19impl std::fmt::Display for ResourceTableError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 Self::Full => write!(f, "resource table has no free keys"),
23 Self::NotPresent => write!(f, "resource not present"),
24 Self::WrongType => write!(f, "resource is of another type"),
25 Self::HasChildren => write!(f, "resource has children"),
26 }
27 }
28}
29impl std::error::Error for ResourceTableError {}
30
31#[derive(Debug)]
33pub struct ResourceTable {
34 entries: Vec<Entry>,
35 free_head: Option<usize>,
36}
37
38#[derive(Debug)]
39enum Entry {
40 Free { next: Option<usize> },
41 Occupied { entry: TableEntry },
42}
43
44impl Entry {
45 pub fn occupied(&self) -> Option<&TableEntry> {
46 match self {
47 Self::Occupied { entry } => Some(entry),
48 Self::Free { .. } => None,
49 }
50 }
51
52 pub fn occupied_mut(&mut self) -> Option<&mut TableEntry> {
53 match self {
54 Self::Occupied { entry } => Some(entry),
55 Self::Free { .. } => None,
56 }
57 }
58}
59
60#[derive(Debug)]
70struct TableEntry {
71 entry: Box<dyn Any + Send>,
73 parent: Option<u32>,
75 children: BTreeSet<u32>,
77}
78
79impl TableEntry {
80 fn new(entry: Box<dyn Any + Send>, parent: Option<u32>) -> Self {
81 Self {
82 entry,
83 parent,
84 children: BTreeSet::new(),
85 }
86 }
87 fn add_child(&mut self, child: u32) {
88 debug_assert!(!self.children.contains(&child));
89 self.children.insert(child);
90 }
91 fn remove_child(&mut self, child: u32) {
92 let was_removed = self.children.remove(&child);
93 debug_assert!(was_removed);
94 }
95}
96
97impl ResourceTable {
98 pub fn new() -> Self {
100 ResourceTable {
101 entries: Vec::new(),
102 free_head: None,
103 }
104 }
105
106 pub fn with_capacity(capacity: usize) -> Self {
108 ResourceTable {
109 entries: Vec::with_capacity(capacity),
110 free_head: None,
111 }
112 }
113
114 pub fn push<T>(&mut self, entry: T) -> Result<Resource<T>, ResourceTableError>
117 where
118 T: Send + 'static,
119 {
120 let idx = self.push_(TableEntry::new(Box::new(entry), None))?;
121 Ok(Resource::new_own(idx))
122 }
123
124 fn pop_free_list(&mut self) -> Option<usize> {
126 if let Some(ix) = self.free_head {
127 match &self.entries[ix] {
129 Entry::Free { next } => self.free_head = *next,
130 Entry::Occupied { .. } => unreachable!(),
131 }
132 Some(ix)
133 } else {
134 None
135 }
136 }
137
138 fn free_entry(&mut self, ix: usize) -> TableEntry {
140 let entry = match std::mem::replace(
141 &mut self.entries[ix],
142 Entry::Free {
143 next: self.free_head,
144 },
145 ) {
146 Entry::Occupied { entry } => entry,
147 Entry::Free { .. } => unreachable!(),
148 };
149
150 self.free_head = Some(ix);
151
152 entry
153 }
154
155 fn push_(&mut self, e: TableEntry) -> Result<u32, ResourceTableError> {
158 if let Some(free) = self.pop_free_list() {
159 self.entries[free] = Entry::Occupied { entry: e };
160 Ok(free as u32)
161 } else {
162 let ix = self
163 .entries
164 .len()
165 .try_into()
166 .map_err(|_| ResourceTableError::Full)?;
167 self.entries.push(Entry::Occupied { entry: e });
168 Ok(ix)
169 }
170 }
171
172 fn occupied(&self, key: u32) -> Result<&TableEntry, ResourceTableError> {
173 self.entries
174 .get(key as usize)
175 .and_then(Entry::occupied)
176 .ok_or(ResourceTableError::NotPresent)
177 }
178
179 fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, ResourceTableError> {
180 self.entries
181 .get_mut(key as usize)
182 .and_then(Entry::occupied_mut)
183 .ok_or(ResourceTableError::NotPresent)
184 }
185
186 pub fn push_child<T, U>(
207 &mut self,
208 entry: T,
209 parent: &Resource<U>,
210 ) -> Result<Resource<T>, ResourceTableError>
211 where
212 T: Send + 'static,
213 U: 'static,
214 {
215 let parent = parent.rep();
216 self.occupied(parent)?;
217 let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?;
218 self.occupied_mut(parent)?.add_child(child);
219 Ok(Resource::new_own(child))
220 }
221
222 pub fn get<T: Any + Sized>(&self, key: &Resource<T>) -> Result<&T, ResourceTableError> {
227 self.get_(key.rep())?
228 .downcast_ref()
229 .ok_or(ResourceTableError::WrongType)
230 }
231
232 fn get_(&self, key: u32) -> Result<&dyn Any, ResourceTableError> {
233 let r = self.occupied(key)?;
234 Ok(&*r.entry)
235 }
236
237 pub fn get_mut<T: Any + Sized>(
240 &mut self,
241 key: &Resource<T>,
242 ) -> Result<&mut T, ResourceTableError> {
243 self.get_any_mut(key.rep())?
244 .downcast_mut()
245 .ok_or(ResourceTableError::WrongType)
246 }
247
248 pub fn get_any_mut(&mut self, key: u32) -> Result<&mut dyn Any, ResourceTableError> {
250 let r = self.occupied_mut(key)?;
251 Ok(&mut *r.entry)
252 }
253
254 pub fn delete<T>(&mut self, resource: Resource<T>) -> Result<T, ResourceTableError>
256 where
257 T: Any,
258 {
259 debug_assert!(resource.owned());
260 let entry = self.delete_entry(resource.rep())?;
261 match entry.entry.downcast() {
262 Ok(t) => Ok(*t),
263 Err(_e) => Err(ResourceTableError::WrongType),
264 }
265 }
266
267 fn delete_entry(&mut self, key: u32) -> Result<TableEntry, ResourceTableError> {
268 if !self.occupied(key)?.children.is_empty() {
269 return Err(ResourceTableError::HasChildren);
270 }
271 let e = self.free_entry(key as usize);
272 if let Some(parent) = e.parent {
273 self.occupied_mut(parent)
277 .expect("missing parent")
278 .remove_child(key);
279 }
280 Ok(e)
281 }
282
283 pub fn iter_entries<'a, T>(
287 &'a mut self,
288 map: HashMap<u32, T>,
289 ) -> impl Iterator<Item = (Result<&'a mut dyn Any, ResourceTableError>, T)> {
290 map.into_iter().map(move |(k, v)| {
291 let item = self
292 .occupied_mut(k)
293 .map(|e| Box::as_mut(&mut e.entry))
294 .map(|item| unsafe { &mut *(item as *mut dyn Any) });
296 (item, v)
297 })
298 }
299
300 pub fn iter_children<T>(
302 &self,
303 parent: &Resource<T>,
304 ) -> Result<impl Iterator<Item = &(dyn Any + Send)>, ResourceTableError>
305 where
306 T: 'static,
307 {
308 let parent_entry = self.occupied(parent.rep())?;
309 Ok(parent_entry.children.iter().map(|child_index| {
310 let child = self.occupied(*child_index).expect("missing child");
311 child.entry.as_ref()
312 }))
313 }
314}
315
316impl Default for ResourceTable {
317 fn default() -> Self {
318 ResourceTable::new()
319 }
320}
321
322#[test]
323pub fn test_free_list() {
324 let mut table = ResourceTable::new();
325
326 let x = table.push(()).unwrap();
327 assert_eq!(x.rep(), 0);
328
329 let y = table.push(()).unwrap();
330 assert_eq!(y.rep(), 1);
331
332 table.delete(x).unwrap();
334 let x = table.push(()).unwrap();
335 assert_eq!(x.rep(), 0);
336
337 table.delete(x).unwrap();
339 table.delete(y).unwrap();
340
341 let y = table.push(()).unwrap();
342 assert_eq!(y.rep(), 1);
343
344 let x = table.push(()).unwrap();
345 assert_eq!(x.rep(), 0);
346
347 let x = table.push(()).unwrap();
349 assert_eq!(x.rep(), 2);
350}