1 use super::Resource;
2 use crate::prelude::*;
3 use alloc::collections::{BTreeMap, BTreeSet};
4 use core::any::Any;
5 use core::fmt;
6 use core::mem;
7 
8 #[derive(Debug)]
9 /// Errors returned by operations on `ResourceTable`
10 pub enum ResourceTableError {
11     /// ResourceTable has no free keys
12     Full,
13     /// Resource not present in table
14     NotPresent,
15     /// Resource present in table, but with a different type
16     WrongType,
17     /// Resource cannot be deleted because child resources exist in the table. Consult wit docs for
18     /// the particular resource to see which methods may return child resources.
19     HasChildren,
20 }
21 
22 impl 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 
33 impl core::error::Error for ResourceTableError {}
34 
35 /// The `ResourceTable` type maps a `Resource<T>` to its `T`.
36 pub struct ResourceTable {
37     entries: Vec<Entry>,
38     free_head: Option<usize>,
39 }
40 
41 #[derive(Debug)]
42 enum Entry {
43     Free { next: Option<usize> },
44     Occupied { entry: TableEntry },
45 }
46 
47 impl 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 
63 struct Tombstone;
64 
65 // Change this to `true` to assist with handle debugging in development if
66 // necessary.
67 const DELETE_WITH_TOMBSTONE: bool = false;
68 
69 /// This structure tracks parent and child relationships for a given table entry.
70 ///
71 /// Parents and children are referred to by table index. We maintain the
72 /// following invariants:
73 /// * the parent must exist when adding a child.
74 /// * whenever a child is created, its index is added to children.
75 /// * whenever a child is deleted, its index is removed from children.
76 /// * an entry with children may not be deleted.
77 #[derive(Debug)]
78 struct TableEntry {
79     /// The entry in the table, as a boxed dynamically-typed object
80     entry: Box<dyn Any + Send>,
81     /// The index of the parent of this entry, if it has one.
82     parent: Option<u32>,
83     /// The indices of any children of this entry.
84     children: BTreeSet<u32>,
85 }
86 
87 impl TableEntry {
88     fn new(entry: Box<dyn Any + Send>, parent: Option<u32>) -> Self {
89         Self {
90             entry,
91             parent,
92             children: BTreeSet::new(),
93         }
94     }
95     fn add_child(&mut self, child: u32) {
96         debug_assert!(!self.children.contains(&child));
97         self.children.insert(child);
98     }
99     fn remove_child(&mut self, child: u32) {
100         let was_removed = self.children.remove(&child);
101         debug_assert!(was_removed);
102     }
103 }
104 
105 impl ResourceTable {
106     /// Create an empty table
107     pub fn new() -> Self {
108         ResourceTable {
109             entries: Vec::new(),
110             free_head: None,
111         }
112     }
113 
114     /// Returns whether or not this table is empty.
115     ///
116     /// Note that this is an `O(n)` operation, where `n` is the number of
117     /// entries in the backing `Vec`.
118     pub fn is_empty(&self) -> bool {
119         self.entries.iter().all(|entry| match entry {
120             Entry::Free { .. } => true,
121             Entry::Occupied { entry } => entry.entry.downcast_ref::<Tombstone>().is_some(),
122         })
123     }
124 
125     /// Create an empty table with at least the specified capacity.
126     pub fn with_capacity(capacity: usize) -> Self {
127         ResourceTable {
128             entries: Vec::with_capacity(capacity),
129             free_head: None,
130         }
131     }
132 
133     /// Inserts a new value `T` into this table, returning a corresponding
134     /// `Resource<T>` which can be used to refer to it after it was inserted.
135     pub fn push<T>(&mut self, entry: T) -> Result<Resource<T>, ResourceTableError>
136     where
137         T: Send + 'static,
138     {
139         let idx = self.push_(TableEntry::new(Box::new(entry), None))?;
140         Ok(Resource::new_own(idx))
141     }
142 
143     /// Pop an index off of the free list, if it's not empty.
144     fn pop_free_list(&mut self) -> Option<usize> {
145         if let Some(ix) = self.free_head {
146             // Advance free_head to the next entry if one is available.
147             match &self.entries[ix] {
148                 Entry::Free { next } => self.free_head = *next,
149                 Entry::Occupied { .. } => unreachable!(),
150             }
151             Some(ix)
152         } else {
153             None
154         }
155     }
156 
157     /// Free an entry in the table, returning its [`TableEntry`]. Add the index to the free list.
158     fn free_entry(&mut self, ix: usize, debug: bool) -> TableEntry {
159         if debug {
160             // Instead of making this entry available for reuse, we leave a
161             // tombstone in debug mode.  This helps detect use-after-delete and
162             // double-delete bugs.
163             match mem::replace(
164                 &mut self.entries[ix],
165                 Entry::Occupied {
166                     entry: TableEntry {
167                         entry: Box::new(Tombstone),
168                         parent: None,
169                         children: BTreeSet::new(),
170                     },
171                 },
172             ) {
173                 Entry::Occupied { entry } => entry,
174                 Entry::Free { .. } => unreachable!(),
175             }
176         } else {
177             let entry = match core::mem::replace(
178                 &mut self.entries[ix],
179                 Entry::Free {
180                     next: self.free_head,
181                 },
182             ) {
183                 Entry::Occupied { entry } => entry,
184                 Entry::Free { .. } => unreachable!(),
185             };
186 
187             self.free_head = Some(ix);
188 
189             entry
190         }
191     }
192 
193     /// Push a new entry into the table, returning its handle. This will prefer to use free entries
194     /// if they exist, falling back on pushing new entries onto the end of the table.
195     fn push_(&mut self, e: TableEntry) -> Result<u32, ResourceTableError> {
196         if let Some(free) = self.pop_free_list() {
197             self.entries[free] = Entry::Occupied { entry: e };
198             Ok(free.try_into().unwrap())
199         } else {
200             let ix = self
201                 .entries
202                 .len()
203                 .try_into()
204                 .map_err(|_| ResourceTableError::Full)?;
205             self.entries.push(Entry::Occupied { entry: e });
206             Ok(ix)
207         }
208     }
209 
210     fn occupied(&self, key: u32) -> Result<&TableEntry, ResourceTableError> {
211         self.entries
212             .get(key as usize)
213             .and_then(Entry::occupied)
214             .ok_or(ResourceTableError::NotPresent)
215     }
216 
217     fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, ResourceTableError> {
218         self.entries
219             .get_mut(key as usize)
220             .and_then(Entry::occupied_mut)
221             .ok_or(ResourceTableError::NotPresent)
222     }
223 
224     /// Insert a resource at the next available index, and track that it has a
225     /// parent resource.
226     ///
227     /// The parent must exist to create a child. All children resources must
228     /// be destroyed before a parent can be destroyed - otherwise
229     /// [`ResourceTable::delete`] will fail with
230     /// [`ResourceTableError::HasChildren`].
231     ///
232     /// Parent-child relationships are tracked inside the table to ensure that
233     /// a parent resource is not deleted while it has live children. This
234     /// allows child resources to hold "references" to a parent by table
235     /// index, to avoid needing e.g. an `Arc<Mutex<parent>>` and the associated
236     /// locking overhead and design issues, such as child existence extending
237     /// lifetime of parent referent even after parent resource is destroyed,
238     /// possibility for deadlocks.
239     pub fn push_child<T, U>(
240         &mut self,
241         entry: T,
242         parent: &Resource<U>,
243     ) -> Result<Resource<T>, ResourceTableError>
244     where
245         T: Send + 'static,
246         U: 'static,
247     {
248         let parent = parent.rep();
249         self.occupied(parent)?;
250         let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?;
251         self.occupied_mut(parent)?.add_child(child);
252         Ok(Resource::new_own(child))
253     }
254 
255     /// Add an already-resident child to a resource.
256     pub fn add_child<T: 'static, U: 'static>(
257         &mut self,
258         child: Resource<T>,
259         parent: Resource<U>,
260     ) -> Result<(), ResourceTableError> {
261         let entry = self.occupied_mut(child.rep())?;
262         assert!(entry.parent.is_none());
263         entry.parent = Some(parent.rep());
264         self.occupied_mut(parent.rep())?.add_child(child.rep());
265         Ok(())
266     }
267 
268     /// Remove a child to from a resource (but leave it in the table).
269     pub fn remove_child<T: 'static, U: 'static>(
270         &mut self,
271         child: Resource<T>,
272         parent: Resource<U>,
273     ) -> Result<(), ResourceTableError> {
274         let entry = self.occupied_mut(child.rep())?;
275         assert_eq!(entry.parent, Some(parent.rep()));
276         entry.parent = None;
277         self.occupied_mut(parent.rep())?.remove_child(child.rep());
278         Ok(())
279     }
280 
281     /// Get an immutable reference to a resource of a given type at a given
282     /// index.
283     ///
284     /// Multiple shared references can be borrowed at any given time.
285     pub fn get<T: Any + Sized>(&self, key: &Resource<T>) -> Result<&T, ResourceTableError> {
286         self.get_(key.rep())?
287             .downcast_ref()
288             .ok_or(ResourceTableError::WrongType)
289     }
290 
291     fn get_(&self, key: u32) -> Result<&dyn Any, ResourceTableError> {
292         let r = self.occupied(key)?;
293         Ok(&*r.entry)
294     }
295 
296     /// Get an mutable reference to a resource of a given type at a given
297     /// index.
298     pub fn get_mut<T: Any + Sized>(
299         &mut self,
300         key: &Resource<T>,
301     ) -> Result<&mut T, ResourceTableError> {
302         self.get_any_mut(key.rep())?
303             .downcast_mut()
304             .ok_or(ResourceTableError::WrongType)
305     }
306 
307     /// Returns the raw `Any` at the `key` index provided.
308     pub fn get_any_mut(&mut self, key: u32) -> Result<&mut dyn Any, ResourceTableError> {
309         let r = self.occupied_mut(key)?;
310         Ok(&mut *r.entry)
311     }
312 
313     /// Remove the specified entry from the table.
314     pub fn delete<T>(&mut self, resource: Resource<T>) -> Result<T, ResourceTableError>
315     where
316         T: Any,
317     {
318         self.delete_maybe_debug(resource, DELETE_WITH_TOMBSTONE)
319     }
320 
321     fn delete_maybe_debug<T>(
322         &mut self,
323         resource: Resource<T>,
324         debug: bool,
325     ) -> Result<T, ResourceTableError>
326     where
327         T: Any,
328     {
329         debug_assert!(resource.owned());
330         let entry = self.delete_entry(resource.rep(), debug)?;
331         match entry.entry.downcast() {
332             Ok(t) => Ok(*t),
333             Err(_e) => Err(ResourceTableError::WrongType),
334         }
335     }
336 
337     fn delete_entry(&mut self, key: u32, debug: bool) -> Result<TableEntry, ResourceTableError> {
338         if !self.occupied(key)?.children.is_empty() {
339             return Err(ResourceTableError::HasChildren);
340         }
341         let e = self.free_entry(key as usize, debug);
342         if let Some(parent) = e.parent {
343             // Remove deleted resource from parent's child list.
344             // Parent must still be present because it can't be deleted while still having
345             // children:
346             self.occupied_mut(parent)
347                 .expect("missing parent")
348                 .remove_child(key);
349         }
350         Ok(e)
351     }
352 
353     /// Zip the values of the map with mutable references to table entries corresponding to each
354     /// key. As the keys in the `BTreeMap` are unique, this iterator can give mutable references
355     /// with the same lifetime as the mutable reference to the [ResourceTable].
356     pub fn iter_entries<'a, T>(
357         &'a mut self,
358         map: BTreeMap<u32, T>,
359     ) -> impl Iterator<Item = (Result<&'a mut dyn Any, ResourceTableError>, T)> {
360         map.into_iter().map(move |(k, v)| {
361             let item = self
362                 .occupied_mut(k)
363                 .map(|e| Box::as_mut(&mut e.entry))
364                 // Safety: extending the lifetime of the mutable reference.
365                 .map(|item| unsafe { &mut *(item as *mut dyn Any) });
366             (item, v)
367         })
368     }
369 
370     /// Iterate over all children belonging to the provided parent
371     pub fn iter_children<T>(
372         &self,
373         parent: &Resource<T>,
374     ) -> Result<impl Iterator<Item = &(dyn Any + Send)> + use<'_, T>, ResourceTableError>
375     where
376         T: 'static,
377     {
378         let parent_entry = self.occupied(parent.rep())?;
379         Ok(parent_entry.children.iter().map(|child_index| {
380             let child = self.occupied(*child_index).expect("missing child");
381             child.entry.as_ref()
382         }))
383     }
384 
385     /// Iterate over all the entries in this table.
386     pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (dyn Any + Send)> {
387         self.entries.iter_mut().filter_map(|entry| match entry {
388             Entry::Occupied { entry } => Some(&mut *entry.entry),
389             Entry::Free { .. } => None,
390         })
391     }
392 }
393 
394 impl Default for ResourceTable {
395     fn default() -> Self {
396         ResourceTable::new()
397     }
398 }
399 
400 impl fmt::Debug for ResourceTable {
401     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402         write!(f, "[")?;
403         let mut wrote = false;
404         for (index, entry) in self.entries.iter().enumerate() {
405             if let Entry::Occupied { entry } = entry {
406                 if entry.entry.downcast_ref::<Tombstone>().is_none() {
407                     if wrote {
408                         write!(f, ", ")?;
409                     } else {
410                         wrote = true;
411                     }
412                     write!(f, "{index}")?;
413                 }
414             }
415         }
416         write!(f, "]")
417     }
418 }
419 
420 #[test]
421 pub fn test_free_list() {
422     let mut table = ResourceTable::new();
423 
424     let x = table.push(()).unwrap();
425     assert_eq!(x.rep(), 0);
426 
427     let y = table.push(()).unwrap();
428     assert_eq!(y.rep(), 1);
429 
430     // Deleting x should put it on the free list, so the next entry should have the same rep.
431     table.delete_maybe_debug(x, false).unwrap();
432     let x = table.push(()).unwrap();
433     assert_eq!(x.rep(), 0);
434 
435     // Deleting x and then y should yield indices 1 and then 0 for new entries.
436     table.delete_maybe_debug(x, false).unwrap();
437     table.delete_maybe_debug(y, false).unwrap();
438 
439     let y = table.push(()).unwrap();
440     assert_eq!(y.rep(), 1);
441 
442     let x = table.push(()).unwrap();
443     assert_eq!(x.rep(), 0);
444 
445     // As the free list is empty, this entry will have a new id.
446     let x = table.push(()).unwrap();
447     assert_eq!(x.rep(), 2);
448 }
449