1use 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 free_count: usize,
41 max_capacity: usize,
42 live: usize,
43}
44
45#[derive(Debug)]
46enum Entry {
47 Free { next: Option<usize> },
48 Occupied { entry: TableEntry },
49}
50
51impl Entry {
52 pub fn occupied(&self) -> Option<&TableEntry> {
53 match self {
54 Self::Occupied { entry } => Some(entry),
55 Self::Free { .. } => None,
56 }
57 }
58
59 pub fn occupied_mut(&mut self) -> Option<&mut TableEntry> {
60 match self {
61 Self::Occupied { entry } => Some(entry),
62 Self::Free { .. } => None,
63 }
64 }
65}
66
67struct Tombstone;
68
69const DELETE_WITH_TOMBSTONE: bool = false;
72
73const DEFAULT_MAX_CAPACITY: usize = 1_000_000;
77
78#[derive(Debug)]
87struct TableEntry {
88 entry: Box<dyn Any + Send>,
90 parent: Option<u32>,
92 children: BTreeSet<u32>,
94}
95
96impl TableEntry {
97 fn new(entry: Box<dyn Any + Send>, parent: Option<u32>) -> Self {
98 Self {
99 entry,
100 parent,
101 children: BTreeSet::new(),
102 }
103 }
104 fn add_child(&mut self, child: u32) {
105 debug_assert!(!self.children.contains(&child));
106 self.children.insert(child);
107 }
108 fn remove_child(&mut self, child: u32) {
109 let was_removed = self.children.remove(&child);
110 debug_assert!(was_removed);
111 }
112}
113
114impl ResourceTable {
115 pub fn new() -> Self {
117 ResourceTable::with_capacity(0)
118 }
119
120 pub fn len(&self) -> usize {
125 self.live
126 }
127
128 pub fn is_empty(&self) -> bool {
130 self.len() == 0
131 }
132
133 #[cfg(any(feature = "component-model-async", test))]
138 pub(crate) fn ensure_capacity(&self, additional: usize) -> Result<(), ResourceTableError> {
139 let Some(to_append) = additional.checked_sub(self.free_count) else {
140 return Ok(());
141 };
142 if to_append > self.max_capacity.saturating_sub(self.entries.len()) {
143 Err(ResourceTableError::Full)
144 } else {
145 Ok(())
146 }
147 }
148
149 pub fn max_capacity(&self) -> usize {
152 self.max_capacity
153 }
154
155 pub fn set_max_capacity(&mut self, max: usize) {
162 self.max_capacity = max;
163 }
164
165 pub fn with_capacity(capacity: usize) -> Self {
167 ResourceTable {
168 entries: Vec::with_capacity(capacity),
169 free_head: None,
170 free_count: 0,
171 max_capacity: DEFAULT_MAX_CAPACITY,
172 live: 0,
173 }
174 }
175
176 pub fn push<T>(&mut self, entry: T) -> Result<Resource<T>, ResourceTableError>
179 where
180 T: Send + 'static,
181 {
182 let idx = self.push_(TableEntry::new(Box::new(entry), None))?;
183 Ok(Resource::new_own(idx))
184 }
185
186 fn pop_free_list(&mut self) -> Option<usize> {
188 if let Some(ix) = self.free_head {
189 match &self.entries[ix] {
191 Entry::Free { next } => self.free_head = *next,
192 Entry::Occupied { .. } => unreachable!(),
193 }
194 self.free_count -= 1;
195 Some(ix)
196 } else {
197 None
198 }
199 }
200
201 fn free_entry(&mut self, ix: usize, debug: bool) -> TableEntry {
203 let removed_entry = if debug {
204 match mem::replace(
208 &mut self.entries[ix],
209 Entry::Occupied {
210 entry: TableEntry {
211 entry: Box::new(Tombstone),
212 parent: None,
213 children: BTreeSet::new(),
214 },
215 },
216 ) {
217 Entry::Occupied { entry } => entry,
218 Entry::Free { .. } => unreachable!(),
219 }
220 } else {
221 let entry = match core::mem::replace(
222 &mut self.entries[ix],
223 Entry::Free {
224 next: self.free_head,
225 },
226 ) {
227 Entry::Occupied { entry } => entry,
228 Entry::Free { .. } => unreachable!(),
229 };
230
231 self.free_head = Some(ix);
232 self.free_count += 1;
233
234 entry
235 };
236 if !removed_entry.entry.is::<Tombstone>() {
237 self.live -= 1;
238 }
239 removed_entry
240 }
241
242 fn push_(&mut self, e: TableEntry) -> Result<u32, ResourceTableError> {
245 if let Some(free) = self.pop_free_list() {
246 self.entries[free] = Entry::Occupied { entry: e };
247 self.live += 1;
248 Ok(free.try_into().unwrap())
249 } else {
250 if self.entries.len() >= self.max_capacity {
251 return Err(ResourceTableError::Full);
252 }
253 let ix = self
254 .entries
255 .len()
256 .try_into()
257 .map_err(|_| ResourceTableError::Full)?;
258 self.entries.push(Entry::Occupied { entry: e });
259 self.live += 1;
260 Ok(ix)
261 }
262 }
263
264 fn occupied(&self, key: u32) -> Result<&TableEntry, ResourceTableError> {
265 self.entries
266 .get(key as usize)
267 .and_then(Entry::occupied)
268 .ok_or(ResourceTableError::NotPresent)
269 }
270
271 fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, ResourceTableError> {
272 self.entries
273 .get_mut(key as usize)
274 .and_then(Entry::occupied_mut)
275 .ok_or(ResourceTableError::NotPresent)
276 }
277
278 pub fn push_child<T, U>(
294 &mut self,
295 entry: T,
296 parent: &Resource<U>,
297 ) -> Result<Resource<T>, ResourceTableError>
298 where
299 T: Send + 'static,
300 U: 'static,
301 {
302 let parent = parent.rep();
303 self.occupied(parent)?;
304 let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?;
305 self.occupied_mut(parent)?.add_child(child);
306 Ok(Resource::new_own(child))
307 }
308
309 pub fn add_child<T: 'static, U: 'static>(
311 &mut self,
312 child: Resource<T>,
313 parent: Resource<U>,
314 ) -> Result<(), ResourceTableError> {
315 let entry = self.occupied_mut(child.rep())?;
316 assert!(entry.parent.is_none());
317 entry.parent = Some(parent.rep());
318 self.occupied_mut(parent.rep())?.add_child(child.rep());
319 Ok(())
320 }
321
322 pub fn remove_child<T: 'static, U: 'static>(
324 &mut self,
325 child: Resource<T>,
326 parent: Resource<U>,
327 ) -> Result<(), ResourceTableError> {
328 let entry = self.occupied_mut(child.rep())?;
329 assert_eq!(entry.parent, Some(parent.rep()));
330 entry.parent = None;
331 self.occupied_mut(parent.rep())?.remove_child(child.rep());
332 Ok(())
333 }
334
335 pub fn get<T: Any + Sized>(&self, key: &Resource<T>) -> Result<&T, ResourceTableError> {
340 self.get_(key.rep())?
341 .downcast_ref()
342 .ok_or(ResourceTableError::WrongType)
343 }
344
345 fn get_(&self, key: u32) -> Result<&dyn Any, ResourceTableError> {
346 let r = self.occupied(key)?;
347 Ok(&*r.entry)
348 }
349
350 pub fn get_mut<T: Any + Sized>(
353 &mut self,
354 key: &Resource<T>,
355 ) -> Result<&mut T, ResourceTableError> {
356 self.get_any_mut(key.rep())?
357 .downcast_mut()
358 .ok_or(ResourceTableError::WrongType)
359 }
360
361 pub fn get_any_mut(&mut self, key: u32) -> Result<&mut dyn Any, ResourceTableError> {
363 let r = self.occupied_mut(key)?;
364 Ok(&mut *r.entry)
365 }
366
367 pub fn delete<T>(&mut self, resource: Resource<T>) -> Result<T, ResourceTableError>
369 where
370 T: Any,
371 {
372 self.delete_maybe_debug(resource, DELETE_WITH_TOMBSTONE)
373 }
374
375 fn delete_maybe_debug<T>(
376 &mut self,
377 resource: Resource<T>,
378 debug: bool,
379 ) -> Result<T, ResourceTableError>
380 where
381 T: Any,
382 {
383 debug_assert!(resource.owned());
384 let entry = self.delete_entry(resource.rep(), debug)?;
385 match entry.entry.downcast() {
386 Ok(t) => Ok(*t),
387 Err(_e) => Err(ResourceTableError::WrongType),
388 }
389 }
390
391 fn delete_entry(&mut self, key: u32, debug: bool) -> Result<TableEntry, ResourceTableError> {
392 if !self.occupied(key)?.children.is_empty() {
393 return Err(ResourceTableError::HasChildren);
394 }
395 let e = self.free_entry(key as usize, debug);
396 if let Some(parent) = e.parent {
397 self.occupied_mut(parent)
401 .expect("missing parent")
402 .remove_child(key);
403 }
404 Ok(e)
405 }
406
407 pub fn iter_entries<'a, T>(
411 &'a mut self,
412 map: BTreeMap<u32, T>,
413 ) -> impl Iterator<Item = (Result<&'a mut dyn Any, ResourceTableError>, T)> {
414 map.into_iter().map(move |(k, v)| {
415 let item = self
416 .occupied_mut(k)
417 .map(|e| Box::as_mut(&mut e.entry))
418 .map(|item| unsafe { &mut *(item as *mut dyn Any) });
420 (item, v)
421 })
422 }
423
424 pub fn iter_children<T>(
426 &self,
427 parent: &Resource<T>,
428 ) -> Result<impl Iterator<Item = &(dyn Any + Send)> + use<'_, T>, ResourceTableError>
429 where
430 T: 'static,
431 {
432 let parent_entry = self.occupied(parent.rep())?;
433 Ok(parent_entry.children.iter().map(|child_index| {
434 let child = self.occupied(*child_index).expect("missing child");
435 child.entry.as_ref()
436 }))
437 }
438
439 pub fn iter_mut(&mut self) -> impl Iterator<Item = (u32, &mut (dyn Any + Send))> {
441 self.entries
442 .iter_mut()
443 .enumerate()
444 .filter_map(|(rep, entry)| match entry {
445 Entry::Occupied { entry } => Some((u32::try_from(rep).unwrap(), &mut *entry.entry)),
446 Entry::Free { .. } => None,
447 })
448 }
449}
450
451impl Default for ResourceTable {
452 fn default() -> Self {
453 ResourceTable::new()
454 }
455}
456
457impl fmt::Debug for ResourceTable {
458 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
459 write!(f, "[")?;
460 let mut wrote = false;
461 for (index, entry) in self.entries.iter().enumerate() {
462 if let Entry::Occupied { entry } = entry {
463 if entry.entry.downcast_ref::<Tombstone>().is_none() {
464 if wrote {
465 write!(f, ", ")?;
466 } else {
467 wrote = true;
468 }
469 write!(f, "{index}")?;
470 }
471 }
472 }
473 write!(f, "]")
474 }
475}
476
477#[test]
478pub fn test_free_list() {
479 let mut table = ResourceTable::new();
480 assert!(table.is_empty());
481
482 let x = table.push(()).unwrap();
483 assert_eq!(x.rep(), 0);
484 assert_eq!(table.len(), 1);
485
486 let y = table.push(()).unwrap();
487 assert_eq!(y.rep(), 1);
488 assert_eq!(table.len(), 2);
489
490 table.delete_maybe_debug(x, false).unwrap();
492 assert_eq!(table.len(), 1);
493 let x = table.push(()).unwrap();
494 assert_eq!(x.rep(), 0);
495 assert_eq!(table.len(), 2);
496
497 table.delete_maybe_debug(x, false).unwrap();
499 table.delete_maybe_debug(y, false).unwrap();
500
501 let y = table.push(()).unwrap();
502 assert_eq!(y.rep(), 1);
503
504 let x = table.push(()).unwrap();
505 assert_eq!(x.rep(), 0);
506
507 let x = table.push(()).unwrap();
509 assert_eq!(x.rep(), 2);
510 assert_eq!(table.len(), 3);
511}
512
513#[test]
514fn test_max_capacity() {
515 let mut table = ResourceTable::new();
516 assert_eq!(table.max_capacity(), DEFAULT_MAX_CAPACITY);
517
518 table.set_max_capacity(0);
519 assert_eq!(table.max_capacity(), 0);
520 assert!(table.push(()).is_err());
521
522 table.set_max_capacity(1);
523 assert_eq!(table.max_capacity(), 1);
524 let x = table.push(()).unwrap();
525 assert!(table.push(()).is_err());
526 assert_eq!(table.len(), 1);
527
528 table.set_max_capacity(0);
529 assert!(table.push(()).is_err());
530 table.delete(x).unwrap();
531 let x = table.push(()).unwrap();
532 table.delete(x).unwrap();
533
534 table.set_max_capacity(10);
535
536 let handles = (0..10).map(|_| table.push(()).unwrap()).collect::<Vec<_>>();
537 assert!(table.push(()).is_err());
538 for handle in handles {
539 table.delete(handle).unwrap();
540 }
541 assert!(table.is_empty());
542
543 table.push(()).unwrap();
544}
545
546#[test]
547fn test_len_and_delete_errors() {
548 let mut table = ResourceTable::new();
549 let parent = table.push(()).unwrap();
550 let child = table.push_child(1u32, &parent).unwrap();
551 assert_eq!(table.len(), 2);
552 table.set_max_capacity(2);
553 assert!(matches!(
554 table.push_child(2u32, &parent),
555 Err(ResourceTableError::Full)
556 ));
557 assert_eq!(table.len(), 2);
558 assert!(matches!(
559 table.delete(Resource::<()>::new_own(parent.rep())),
560 Err(ResourceTableError::HasChildren)
561 ));
562 assert_eq!(table.len(), 2);
563 assert!(matches!(
564 table.push_child((), &Resource::<()>::new_own(100)),
565 Err(ResourceTableError::NotPresent)
566 ));
567 assert_eq!(table.len(), 2);
568 assert!(matches!(
569 table.delete(Resource::<()>::new_own(child.rep())),
570 Err(ResourceTableError::WrongType)
571 ));
572 assert_eq!(table.len(), 1);
573 assert!(matches!(
574 table.delete(Resource::<()>::new_own(100)),
575 Err(ResourceTableError::NotPresent)
576 ));
577 assert_eq!(table.len(), 1);
578 table.delete(parent).unwrap();
579 assert!(table.is_empty());
580}
581
582#[test]
583fn test_len_and_tombstones() {
584 let mut table = ResourceTable::new();
585 table.set_max_capacity(1);
586 let value = table.push(1u32).unwrap();
587 let rep = value.rep();
588 table.delete_maybe_debug(value, true).unwrap();
589 assert_eq!(table.len(), 0);
590 assert!(table.is_empty());
591 assert_eq!(table.entries.len(), 1);
592 assert!(matches!(
593 table.ensure_capacity(1),
594 Err(ResourceTableError::Full)
595 ));
596 assert!(matches!(
597 table.delete_maybe_debug(Resource::<u32>::new_own(rep), true),
598 Err(ResourceTableError::WrongType)
599 ));
600 assert_eq!(table.len(), 0);
601 assert!(matches!(
602 table.delete_maybe_debug(Resource::<u32>::new_own(rep), false),
603 Err(ResourceTableError::WrongType)
604 ));
605 assert_eq!(table.len(), 0);
606 table.ensure_capacity(1).unwrap();
607 assert_eq!(table.push(()).unwrap().rep(), rep);
608 assert_eq!(table.len(), 1);
609 assert!(matches!(
610 table.ensure_capacity(1),
611 Err(ResourceTableError::Full)
612 ));
613}
614
615#[test]
616fn test_batch_capacity() {
617 let mut table = ResourceTable::new();
618 table.set_max_capacity(3);
619 table.ensure_capacity(0).unwrap();
620 table.ensure_capacity(3).unwrap();
621 assert!(matches!(
622 table.ensure_capacity(4),
623 Err(ResourceTableError::Full)
624 ));
625 assert_eq!(table.entries.len(), 0);
626 let first = table.push(()).unwrap();
627 table.ensure_capacity(2).unwrap();
628 assert!(matches!(
629 table.ensure_capacity(3),
630 Err(ResourceTableError::Full)
631 ));
632 table.delete_maybe_debug(first, false).unwrap();
633 table.ensure_capacity(3).unwrap();
635 let handles = (0..3).map(|_| table.push(()).unwrap()).collect::<Vec<_>>();
636 for handle in handles {
637 table.delete_maybe_debug(handle, false).unwrap();
638 }
639 table.set_max_capacity(0);
640 table.ensure_capacity(3).unwrap();
642 assert!(matches!(
643 table.ensure_capacity(4),
644 Err(ResourceTableError::Full)
645 ));
646 assert_eq!(table.len(), 0);
647 assert_eq!(table.entries.len(), 3);
648}