wasmtime/runtime/component/
resource_table.rs1use super::Resource;
2use crate::prelude::*;
3use alloc::collections::{BTreeMap, BTreeSet};
4use core::any::Any;
5use core::fmt;
6use core::mem;
7
8#[derive(Debug)]
9pub enum ResourceTableError {
11 Full,
13 NotPresent,
15 WrongType,
17 HasChildren,
20}
21
22impl fmt::Display for ResourceTableError {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 Self::Full => write!(f, "resource table has no free keys"),
26 Self::NotPresent => write!(f, "resource not present"),
27 Self::WrongType => write!(f, "resource is of another type"),
28 Self::HasChildren => write!(f, "resource has children"),
29 }
30 }
31}
32
33impl core::error::Error for ResourceTableError {}
34
35pub struct ResourceTable {
37 entries: Vec<Entry>,
38 free_head: Option<usize>,
39}
40
41#[derive(Debug)]
42enum Entry {
43 Free { next: Option<usize> },
44 Occupied { entry: TableEntry },
45}
46
47impl Entry {
48 pub fn occupied(&self) -> Option<&TableEntry> {
49 match self {
50 Self::Occupied { entry } => Some(entry),
51 Self::Free { .. } => None,
52 }
53 }
54
55 pub fn occupied_mut(&mut self) -> Option<&mut TableEntry> {
56 match self {
57 Self::Occupied { entry } => Some(entry),
58 Self::Free { .. } => None,
59 }
60 }
61}
62
63struct Tombstone;
64
65#[derive(Debug)]
74struct TableEntry {
75 entry: Box<dyn Any + Send>,
77 parent: Option<u32>,
79 children: BTreeSet<u32>,
81}
82
83impl TableEntry {
84 fn new(entry: Box<dyn Any + Send>, parent: Option<u32>) -> Self {
85 Self {
86 entry,
87 parent,
88 children: BTreeSet::new(),
89 }
90 }
91 fn add_child(&mut self, child: u32) {
92 debug_assert!(!self.children.contains(&child));
93 self.children.insert(child);
94 }
95 fn remove_child(&mut self, child: u32) {
96 let was_removed = self.children.remove(&child);
97 debug_assert!(was_removed);
98 }
99}
100
101impl ResourceTable {
102 pub fn new() -> Self {
104 ResourceTable {
105 entries: Vec::new(),
106 free_head: None,
107 }
108 }
109
110 pub fn is_empty(&self) -> bool {
115 self.entries.iter().all(|entry| match entry {
116 Entry::Free { .. } => true,
117 Entry::Occupied { entry } => entry.entry.downcast_ref::<Tombstone>().is_some(),
118 })
119 }
120
121 pub fn with_capacity(capacity: usize) -> Self {
123 ResourceTable {
124 entries: Vec::with_capacity(capacity),
125 free_head: None,
126 }
127 }
128
129 pub fn push<T>(&mut self, entry: T) -> Result<Resource<T>, ResourceTableError>
132 where
133 T: Send + 'static,
134 {
135 let idx = self.push_(TableEntry::new(Box::new(entry), None))?;
136 Ok(Resource::new_own(idx))
137 }
138
139 fn pop_free_list(&mut self) -> Option<usize> {
141 if let Some(ix) = self.free_head {
142 match &self.entries[ix] {
144 Entry::Free { next } => self.free_head = *next,
145 Entry::Occupied { .. } => unreachable!(),
146 }
147 Some(ix)
148 } else {
149 None
150 }
151 }
152
153 fn free_entry(&mut self, ix: usize, debug: bool) -> TableEntry {
155 if debug {
156 match mem::replace(
160 &mut self.entries[ix],
161 Entry::Occupied {
162 entry: TableEntry {
163 entry: Box::new(Tombstone),
164 parent: None,
165 children: BTreeSet::new(),
166 },
167 },
168 ) {
169 Entry::Occupied { entry } => entry,
170 Entry::Free { .. } => unreachable!(),
171 }
172 } else {
173 let entry = match core::mem::replace(
174 &mut self.entries[ix],
175 Entry::Free {
176 next: self.free_head,
177 },
178 ) {
179 Entry::Occupied { entry } => entry,
180 Entry::Free { .. } => unreachable!(),
181 };
182
183 self.free_head = Some(ix);
184
185 entry
186 }
187 }
188
189 fn push_(&mut self, e: TableEntry) -> Result<u32, ResourceTableError> {
192 if let Some(free) = self.pop_free_list() {
193 self.entries[free] = Entry::Occupied { entry: e };
194 Ok(free.try_into().unwrap())
195 } else {
196 let ix = self
197 .entries
198 .len()
199 .try_into()
200 .map_err(|_| ResourceTableError::Full)?;
201 self.entries.push(Entry::Occupied { entry: e });
202 Ok(ix)
203 }
204 }
205
206 fn occupied(&self, key: u32) -> Result<&TableEntry, ResourceTableError> {
207 self.entries
208 .get(key as usize)
209 .and_then(Entry::occupied)
210 .ok_or(ResourceTableError::NotPresent)
211 }
212
213 fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, ResourceTableError> {
214 self.entries
215 .get_mut(key as usize)
216 .and_then(Entry::occupied_mut)
217 .ok_or(ResourceTableError::NotPresent)
218 }
219
220 pub fn push_child<T, U>(
236 &mut self,
237 entry: T,
238 parent: &Resource<U>,
239 ) -> Result<Resource<T>, ResourceTableError>
240 where
241 T: Send + 'static,
242 U: 'static,
243 {
244 let parent = parent.rep();
245 self.occupied(parent)?;
246 let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?;
247 self.occupied_mut(parent)?.add_child(child);
248 Ok(Resource::new_own(child))
249 }
250
251 pub fn add_child<T: 'static, U: 'static>(
253 &mut self,
254 child: Resource<T>,
255 parent: Resource<U>,
256 ) -> Result<(), ResourceTableError> {
257 let entry = self.occupied_mut(child.rep())?;
258 assert!(entry.parent.is_none());
259 entry.parent = Some(parent.rep());
260 self.occupied_mut(parent.rep())?.add_child(child.rep());
261 Ok(())
262 }
263
264 pub fn remove_child<T: 'static, U: 'static>(
266 &mut self,
267 child: Resource<T>,
268 parent: Resource<U>,
269 ) -> Result<(), ResourceTableError> {
270 let entry = self.occupied_mut(child.rep())?;
271 assert_eq!(entry.parent, Some(parent.rep()));
272 entry.parent = None;
273 self.occupied_mut(parent.rep())?.remove_child(child.rep());
274 Ok(())
275 }
276
277 pub fn get<T: Any + Sized>(&self, key: &Resource<T>) -> Result<&T, ResourceTableError> {
282 self.get_(key.rep())?
283 .downcast_ref()
284 .ok_or(ResourceTableError::WrongType)
285 }
286
287 fn get_(&self, key: u32) -> Result<&dyn Any, ResourceTableError> {
288 let r = self.occupied(key)?;
289 Ok(&*r.entry)
290 }
291
292 pub fn get_mut<T: Any + Sized>(
295 &mut self,
296 key: &Resource<T>,
297 ) -> Result<&mut T, ResourceTableError> {
298 self.get_any_mut(key.rep())?
299 .downcast_mut()
300 .ok_or(ResourceTableError::WrongType)
301 }
302
303 pub fn get_any_mut(&mut self, key: u32) -> Result<&mut dyn Any, ResourceTableError> {
305 let r = self.occupied_mut(key)?;
306 Ok(&mut *r.entry)
307 }
308
309 pub fn delete<T>(&mut self, resource: Resource<T>) -> Result<T, ResourceTableError>
311 where
312 T: Any,
313 {
314 self.delete_maybe_debug(resource, cfg!(debug_assertions))
315 }
316
317 fn delete_maybe_debug<T>(
318 &mut self,
319 resource: Resource<T>,
320 debug: bool,
321 ) -> Result<T, ResourceTableError>
322 where
323 T: Any,
324 {
325 debug_assert!(resource.owned());
326 let entry = self.delete_entry(resource.rep(), debug)?;
327 match entry.entry.downcast() {
328 Ok(t) => Ok(*t),
329 Err(_e) => Err(ResourceTableError::WrongType),
330 }
331 }
332
333 fn delete_entry(&mut self, key: u32, debug: bool) -> Result<TableEntry, ResourceTableError> {
334 if !self.occupied(key)?.children.is_empty() {
335 return Err(ResourceTableError::HasChildren);
336 }
337 let e = self.free_entry(key as usize, debug);
338 if let Some(parent) = e.parent {
339 self.occupied_mut(parent)
343 .expect("missing parent")
344 .remove_child(key);
345 }
346 Ok(e)
347 }
348
349 pub fn iter_entries<'a, T>(
353 &'a mut self,
354 map: BTreeMap<u32, T>,
355 ) -> impl Iterator<Item = (Result<&'a mut dyn Any, ResourceTableError>, T)> {
356 map.into_iter().map(move |(k, v)| {
357 let item = self
358 .occupied_mut(k)
359 .map(|e| Box::as_mut(&mut e.entry))
360 .map(|item| unsafe { &mut *(item as *mut dyn Any) });
362 (item, v)
363 })
364 }
365
366 pub fn iter_children<T>(
368 &self,
369 parent: &Resource<T>,
370 ) -> Result<impl Iterator<Item = &(dyn Any + Send)> + use<'_, T>, ResourceTableError>
371 where
372 T: 'static,
373 {
374 let parent_entry = self.occupied(parent.rep())?;
375 Ok(parent_entry.children.iter().map(|child_index| {
376 let child = self.occupied(*child_index).expect("missing child");
377 child.entry.as_ref()
378 }))
379 }
380
381 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (dyn Any + Send)> {
383 self.entries.iter_mut().filter_map(|entry| match entry {
384 Entry::Occupied { entry } => Some(&mut *entry.entry),
385 Entry::Free { .. } => None,
386 })
387 }
388}
389
390impl Default for ResourceTable {
391 fn default() -> Self {
392 ResourceTable::new()
393 }
394}
395
396impl fmt::Debug for ResourceTable {
397 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
398 write!(f, "[")?;
399 let mut wrote = false;
400 for (index, entry) in self.entries.iter().enumerate() {
401 if let Entry::Occupied { entry } = entry {
402 if entry.entry.downcast_ref::<Tombstone>().is_none() {
403 if wrote {
404 write!(f, ", ")?;
405 } else {
406 wrote = true;
407 }
408 write!(f, "{index}")?;
409 }
410 }
411 }
412 write!(f, "]")
413 }
414}
415
416#[test]
417pub fn test_free_list() {
418 let mut table = ResourceTable::new();
419
420 let x = table.push(()).unwrap();
421 assert_eq!(x.rep(), 0);
422
423 let y = table.push(()).unwrap();
424 assert_eq!(y.rep(), 1);
425
426 table.delete_maybe_debug(x, false).unwrap();
428 let x = table.push(()).unwrap();
429 assert_eq!(x.rep(), 0);
430
431 table.delete_maybe_debug(x, false).unwrap();
433 table.delete_maybe_debug(y, false).unwrap();
434
435 let y = table.push(()).unwrap();
436 assert_eq!(y.rep(), 1);
437
438 let x = table.push(()).unwrap();
439 assert_eq!(x.rep(), 0);
440
441 let x = table.push(()).unwrap();
443 assert_eq!(x.rep(), 2);
444}