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 max_capacity: usize,
40}
41
42#[derive(Debug)]
43enum Entry {
44 Free { next: Option<usize> },
45 Occupied { entry: TableEntry },
46}
47
48impl Entry {
49 pub fn occupied(&self) -> Option<&TableEntry> {
50 match self {
51 Self::Occupied { entry } => Some(entry),
52 Self::Free { .. } => None,
53 }
54 }
55
56 pub fn occupied_mut(&mut self) -> Option<&mut TableEntry> {
57 match self {
58 Self::Occupied { entry } => Some(entry),
59 Self::Free { .. } => None,
60 }
61 }
62}
63
64struct Tombstone;
65
66const DELETE_WITH_TOMBSTONE: bool = false;
69
70const DEFAULT_MAX_CAPACITY: usize = 1_000_000;
74
75#[derive(Debug)]
84struct TableEntry {
85 entry: Box<dyn Any + Send>,
87 parent: Option<u32>,
89 children: BTreeSet<u32>,
91}
92
93impl TableEntry {
94 fn new(entry: Box<dyn Any + Send>, parent: Option<u32>) -> Self {
95 Self {
96 entry,
97 parent,
98 children: BTreeSet::new(),
99 }
100 }
101 fn add_child(&mut self, child: u32) {
102 debug_assert!(!self.children.contains(&child));
103 self.children.insert(child);
104 }
105 fn remove_child(&mut self, child: u32) {
106 let was_removed = self.children.remove(&child);
107 debug_assert!(was_removed);
108 }
109}
110
111impl ResourceTable {
112 pub fn new() -> Self {
114 ResourceTable::with_capacity(0)
115 }
116
117 pub fn is_empty(&self) -> bool {
122 self.entries.iter().all(|entry| match entry {
123 Entry::Free { .. } => true,
124 Entry::Occupied { entry } => entry.entry.downcast_ref::<Tombstone>().is_some(),
125 })
126 }
127
128 pub fn max_capacity(&self) -> usize {
131 self.max_capacity
132 }
133
134 pub fn set_max_capacity(&mut self, max: usize) {
141 self.max_capacity = max;
142 }
143
144 pub fn with_capacity(capacity: usize) -> Self {
146 ResourceTable {
147 entries: Vec::with_capacity(capacity),
148 free_head: None,
149 max_capacity: DEFAULT_MAX_CAPACITY,
150 }
151 }
152
153 pub fn push<T>(&mut self, entry: T) -> Result<Resource<T>, ResourceTableError>
156 where
157 T: Send + 'static,
158 {
159 let idx = self.push_(TableEntry::new(Box::new(entry), None))?;
160 Ok(Resource::new_own(idx))
161 }
162
163 fn pop_free_list(&mut self) -> Option<usize> {
165 if let Some(ix) = self.free_head {
166 match &self.entries[ix] {
168 Entry::Free { next } => self.free_head = *next,
169 Entry::Occupied { .. } => unreachable!(),
170 }
171 Some(ix)
172 } else {
173 None
174 }
175 }
176
177 fn free_entry(&mut self, ix: usize, debug: bool) -> TableEntry {
179 if debug {
180 match mem::replace(
184 &mut self.entries[ix],
185 Entry::Occupied {
186 entry: TableEntry {
187 entry: Box::new(Tombstone),
188 parent: None,
189 children: BTreeSet::new(),
190 },
191 },
192 ) {
193 Entry::Occupied { entry } => entry,
194 Entry::Free { .. } => unreachable!(),
195 }
196 } else {
197 let entry = match core::mem::replace(
198 &mut self.entries[ix],
199 Entry::Free {
200 next: self.free_head,
201 },
202 ) {
203 Entry::Occupied { entry } => entry,
204 Entry::Free { .. } => unreachable!(),
205 };
206
207 self.free_head = Some(ix);
208
209 entry
210 }
211 }
212
213 fn push_(&mut self, e: TableEntry) -> Result<u32, ResourceTableError> {
216 if let Some(free) = self.pop_free_list() {
217 self.entries[free] = Entry::Occupied { entry: e };
218 Ok(free.try_into().unwrap())
219 } else {
220 if self.entries.len() >= self.max_capacity {
221 return Err(ResourceTableError::Full);
222 }
223 let ix = self
224 .entries
225 .len()
226 .try_into()
227 .map_err(|_| ResourceTableError::Full)?;
228 self.entries.push(Entry::Occupied { entry: e });
229 Ok(ix)
230 }
231 }
232
233 fn occupied(&self, key: u32) -> Result<&TableEntry, ResourceTableError> {
234 self.entries
235 .get(key as usize)
236 .and_then(Entry::occupied)
237 .ok_or(ResourceTableError::NotPresent)
238 }
239
240 fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, ResourceTableError> {
241 self.entries
242 .get_mut(key as usize)
243 .and_then(Entry::occupied_mut)
244 .ok_or(ResourceTableError::NotPresent)
245 }
246
247 pub fn push_child<T, U>(
263 &mut self,
264 entry: T,
265 parent: &Resource<U>,
266 ) -> Result<Resource<T>, ResourceTableError>
267 where
268 T: Send + 'static,
269 U: 'static,
270 {
271 let parent = parent.rep();
272 self.occupied(parent)?;
273 let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?;
274 self.occupied_mut(parent)?.add_child(child);
275 Ok(Resource::new_own(child))
276 }
277
278 pub fn add_child<T: 'static, U: 'static>(
280 &mut self,
281 child: Resource<T>,
282 parent: Resource<U>,
283 ) -> Result<(), ResourceTableError> {
284 let entry = self.occupied_mut(child.rep())?;
285 assert!(entry.parent.is_none());
286 entry.parent = Some(parent.rep());
287 self.occupied_mut(parent.rep())?.add_child(child.rep());
288 Ok(())
289 }
290
291 pub fn remove_child<T: 'static, U: 'static>(
293 &mut self,
294 child: Resource<T>,
295 parent: Resource<U>,
296 ) -> Result<(), ResourceTableError> {
297 let entry = self.occupied_mut(child.rep())?;
298 assert_eq!(entry.parent, Some(parent.rep()));
299 entry.parent = None;
300 self.occupied_mut(parent.rep())?.remove_child(child.rep());
301 Ok(())
302 }
303
304 pub fn get<T: Any + Sized>(&self, key: &Resource<T>) -> Result<&T, ResourceTableError> {
309 self.get_(key.rep())?
310 .downcast_ref()
311 .ok_or(ResourceTableError::WrongType)
312 }
313
314 fn get_(&self, key: u32) -> Result<&dyn Any, ResourceTableError> {
315 let r = self.occupied(key)?;
316 Ok(&*r.entry)
317 }
318
319 pub fn get_mut<T: Any + Sized>(
322 &mut self,
323 key: &Resource<T>,
324 ) -> Result<&mut T, ResourceTableError> {
325 self.get_any_mut(key.rep())?
326 .downcast_mut()
327 .ok_or(ResourceTableError::WrongType)
328 }
329
330 pub fn get_any_mut(&mut self, key: u32) -> Result<&mut dyn Any, ResourceTableError> {
332 let r = self.occupied_mut(key)?;
333 Ok(&mut *r.entry)
334 }
335
336 pub fn delete<T>(&mut self, resource: Resource<T>) -> Result<T, ResourceTableError>
338 where
339 T: Any,
340 {
341 self.delete_maybe_debug(resource, DELETE_WITH_TOMBSTONE)
342 }
343
344 fn delete_maybe_debug<T>(
345 &mut self,
346 resource: Resource<T>,
347 debug: bool,
348 ) -> Result<T, ResourceTableError>
349 where
350 T: Any,
351 {
352 debug_assert!(resource.owned());
353 let entry = self.delete_entry(resource.rep(), debug)?;
354 match entry.entry.downcast() {
355 Ok(t) => Ok(*t),
356 Err(_e) => Err(ResourceTableError::WrongType),
357 }
358 }
359
360 fn delete_entry(&mut self, key: u32, debug: bool) -> Result<TableEntry, ResourceTableError> {
361 if !self.occupied(key)?.children.is_empty() {
362 return Err(ResourceTableError::HasChildren);
363 }
364 let e = self.free_entry(key as usize, debug);
365 if let Some(parent) = e.parent {
366 self.occupied_mut(parent)
370 .expect("missing parent")
371 .remove_child(key);
372 }
373 Ok(e)
374 }
375
376 pub fn iter_entries<'a, T>(
380 &'a mut self,
381 map: BTreeMap<u32, T>,
382 ) -> impl Iterator<Item = (Result<&'a mut dyn Any, ResourceTableError>, T)> {
383 map.into_iter().map(move |(k, v)| {
384 let item = self
385 .occupied_mut(k)
386 .map(|e| Box::as_mut(&mut e.entry))
387 .map(|item| unsafe { &mut *(item as *mut dyn Any) });
389 (item, v)
390 })
391 }
392
393 pub fn iter_children<T>(
395 &self,
396 parent: &Resource<T>,
397 ) -> Result<impl Iterator<Item = &(dyn Any + Send)> + use<'_, T>, ResourceTableError>
398 where
399 T: 'static,
400 {
401 let parent_entry = self.occupied(parent.rep())?;
402 Ok(parent_entry.children.iter().map(|child_index| {
403 let child = self.occupied(*child_index).expect("missing child");
404 child.entry.as_ref()
405 }))
406 }
407
408 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (dyn Any + Send)> {
410 self.entries.iter_mut().filter_map(|entry| match entry {
411 Entry::Occupied { entry } => Some(&mut *entry.entry),
412 Entry::Free { .. } => None,
413 })
414 }
415}
416
417impl Default for ResourceTable {
418 fn default() -> Self {
419 ResourceTable::new()
420 }
421}
422
423impl fmt::Debug for ResourceTable {
424 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425 write!(f, "[")?;
426 let mut wrote = false;
427 for (index, entry) in self.entries.iter().enumerate() {
428 if let Entry::Occupied { entry } = entry {
429 if entry.entry.downcast_ref::<Tombstone>().is_none() {
430 if wrote {
431 write!(f, ", ")?;
432 } else {
433 wrote = true;
434 }
435 write!(f, "{index}")?;
436 }
437 }
438 }
439 write!(f, "]")
440 }
441}
442
443#[test]
444pub fn test_free_list() {
445 let mut table = ResourceTable::new();
446
447 let x = table.push(()).unwrap();
448 assert_eq!(x.rep(), 0);
449
450 let y = table.push(()).unwrap();
451 assert_eq!(y.rep(), 1);
452
453 table.delete_maybe_debug(x, false).unwrap();
455 let x = table.push(()).unwrap();
456 assert_eq!(x.rep(), 0);
457
458 table.delete_maybe_debug(x, false).unwrap();
460 table.delete_maybe_debug(y, false).unwrap();
461
462 let y = table.push(()).unwrap();
463 assert_eq!(y.rep(), 1);
464
465 let x = table.push(()).unwrap();
466 assert_eq!(x.rep(), 0);
467
468 let x = table.push(()).unwrap();
470 assert_eq!(x.rep(), 2);
471}
472
473#[test]
474fn test_max_capacity() {
475 let mut table = ResourceTable::new();
476 assert_eq!(table.max_capacity(), DEFAULT_MAX_CAPACITY);
477
478 table.set_max_capacity(0);
479 assert_eq!(table.max_capacity(), 0);
480 assert!(table.push(()).is_err());
481
482 table.set_max_capacity(1);
483 assert_eq!(table.max_capacity(), 1);
484 let x = table.push(()).unwrap();
485 assert!(table.push(()).is_err());
486
487 table.set_max_capacity(0);
488 assert!(table.push(()).is_err());
489 table.delete(x).unwrap();
490 let x = table.push(()).unwrap();
491 table.delete(x).unwrap();
492
493 table.set_max_capacity(10);
494
495 let handles = (0..10).map(|_| table.push(()).unwrap()).collect::<Vec<_>>();
496 assert!(table.push(()).is_err());
497 for handle in handles {
498 table.delete(handle).unwrap();
499 }
500
501 table.push(()).unwrap();
502}