wasmtime/runtime/component/
resource_table.rs1use super::Resource;
2use crate::prelude::*;
3use alloc::collections::{BTreeMap, BTreeSet};
4use core::any::Any;
5use core::fmt;
6
7#[derive(Debug)]
8pub enum ResourceTableError {
10 Full,
12 NotPresent,
14 WrongType,
16 HasChildren,
19}
20
21impl fmt::Display for ResourceTableError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 Self::Full => write!(f, "resource table has no free keys"),
25 Self::NotPresent => write!(f, "resource not present"),
26 Self::WrongType => write!(f, "resource is of another type"),
27 Self::HasChildren => write!(f, "resource has children"),
28 }
29 }
30}
31
32impl core::error::Error for ResourceTableError {}
33
34#[derive(Debug)]
36pub 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
63#[derive(Debug)]
73struct TableEntry {
74 entry: Box<dyn Any + Send>,
76 parent: Option<u32>,
78 children: BTreeSet<u32>,
80}
81
82impl TableEntry {
83 fn new(entry: Box<dyn Any + Send>, parent: Option<u32>) -> Self {
84 Self {
85 entry,
86 parent,
87 children: BTreeSet::new(),
88 }
89 }
90 fn add_child(&mut self, child: u32) {
91 debug_assert!(!self.children.contains(&child));
92 self.children.insert(child);
93 }
94 fn remove_child(&mut self, child: u32) {
95 let was_removed = self.children.remove(&child);
96 debug_assert!(was_removed);
97 }
98}
99
100impl ResourceTable {
101 pub fn new() -> Self {
103 ResourceTable {
104 entries: Vec::new(),
105 free_head: None,
106 }
107 }
108
109 pub fn with_capacity(capacity: usize) -> Self {
111 ResourceTable {
112 entries: Vec::with_capacity(capacity),
113 free_head: None,
114 }
115 }
116
117 pub fn push<T>(&mut self, entry: T) -> Result<Resource<T>, ResourceTableError>
120 where
121 T: Send + 'static,
122 {
123 let idx = self.push_(TableEntry::new(Box::new(entry), None))?;
124 Ok(Resource::new_own(idx))
125 }
126
127 fn pop_free_list(&mut self) -> Option<usize> {
129 if let Some(ix) = self.free_head {
130 match &self.entries[ix] {
132 Entry::Free { next } => self.free_head = *next,
133 Entry::Occupied { .. } => unreachable!(),
134 }
135 Some(ix)
136 } else {
137 None
138 }
139 }
140
141 fn free_entry(&mut self, ix: usize) -> TableEntry {
143 let entry = match core::mem::replace(
144 &mut self.entries[ix],
145 Entry::Free {
146 next: self.free_head,
147 },
148 ) {
149 Entry::Occupied { entry } => entry,
150 Entry::Free { .. } => unreachable!(),
151 };
152
153 self.free_head = Some(ix);
154
155 entry
156 }
157
158 fn push_(&mut self, e: TableEntry) -> Result<u32, ResourceTableError> {
161 if let Some(free) = self.pop_free_list() {
162 self.entries[free] = Entry::Occupied { entry: e };
163 Ok(free.try_into().unwrap())
164 } else {
165 let ix = self
166 .entries
167 .len()
168 .try_into()
169 .map_err(|_| ResourceTableError::Full)?;
170 self.entries.push(Entry::Occupied { entry: e });
171 Ok(ix)
172 }
173 }
174
175 fn occupied(&self, key: u32) -> Result<&TableEntry, ResourceTableError> {
176 self.entries
177 .get(key as usize)
178 .and_then(Entry::occupied)
179 .ok_or(ResourceTableError::NotPresent)
180 }
181
182 fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, ResourceTableError> {
183 self.entries
184 .get_mut(key as usize)
185 .and_then(Entry::occupied_mut)
186 .ok_or(ResourceTableError::NotPresent)
187 }
188
189 pub fn push_child<T, U>(
210 &mut self,
211 entry: T,
212 parent: &Resource<U>,
213 ) -> Result<Resource<T>, ResourceTableError>
214 where
215 T: Send + 'static,
216 U: 'static,
217 {
218 let parent = parent.rep();
219 self.occupied(parent)?;
220 let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?;
221 self.occupied_mut(parent)?.add_child(child);
222 Ok(Resource::new_own(child))
223 }
224
225 pub fn get<T: Any + Sized>(&self, key: &Resource<T>) -> Result<&T, ResourceTableError> {
230 self.get_(key.rep())?
231 .downcast_ref()
232 .ok_or(ResourceTableError::WrongType)
233 }
234
235 fn get_(&self, key: u32) -> Result<&dyn Any, ResourceTableError> {
236 let r = self.occupied(key)?;
237 Ok(&*r.entry)
238 }
239
240 pub fn get_mut<T: Any + Sized>(
243 &mut self,
244 key: &Resource<T>,
245 ) -> Result<&mut T, ResourceTableError> {
246 self.get_any_mut(key.rep())?
247 .downcast_mut()
248 .ok_or(ResourceTableError::WrongType)
249 }
250
251 pub fn get_any_mut(&mut self, key: u32) -> Result<&mut dyn Any, ResourceTableError> {
253 let r = self.occupied_mut(key)?;
254 Ok(&mut *r.entry)
255 }
256
257 pub fn delete<T>(&mut self, resource: Resource<T>) -> Result<T, ResourceTableError>
259 where
260 T: Any,
261 {
262 debug_assert!(resource.owned());
263 let entry = self.delete_entry(resource.rep())?;
264 match entry.entry.downcast() {
265 Ok(t) => Ok(*t),
266 Err(_e) => Err(ResourceTableError::WrongType),
267 }
268 }
269
270 fn delete_entry(&mut self, key: u32) -> Result<TableEntry, ResourceTableError> {
271 if !self.occupied(key)?.children.is_empty() {
272 return Err(ResourceTableError::HasChildren);
273 }
274 let e = self.free_entry(key as usize);
275 if let Some(parent) = e.parent {
276 self.occupied_mut(parent)
280 .expect("missing parent")
281 .remove_child(key);
282 }
283 Ok(e)
284 }
285
286 pub fn iter_entries<'a, T>(
290 &'a mut self,
291 map: BTreeMap<u32, T>,
292 ) -> impl Iterator<Item = (Result<&'a mut dyn Any, ResourceTableError>, T)> {
293 map.into_iter().map(move |(k, v)| {
294 let item = self
295 .occupied_mut(k)
296 .map(|e| Box::as_mut(&mut e.entry))
297 .map(|item| unsafe { &mut *(item as *mut dyn Any) });
299 (item, v)
300 })
301 }
302
303 pub fn iter_children<T>(
305 &self,
306 parent: &Resource<T>,
307 ) -> Result<impl Iterator<Item = &(dyn Any + Send)> + use<'_, T>, ResourceTableError>
308 where
309 T: 'static,
310 {
311 let parent_entry = self.occupied(parent.rep())?;
312 Ok(parent_entry.children.iter().map(|child_index| {
313 let child = self.occupied(*child_index).expect("missing child");
314 child.entry.as_ref()
315 }))
316 }
317}
318
319impl Default for ResourceTable {
320 fn default() -> Self {
321 ResourceTable::new()
322 }
323}
324
325#[test]
326pub fn test_free_list() {
327 let mut table = ResourceTable::new();
328
329 let x = table.push(()).unwrap();
330 assert_eq!(x.rep(), 0);
331
332 let y = table.push(()).unwrap();
333 assert_eq!(y.rep(), 1);
334
335 table.delete(x).unwrap();
337 let x = table.push(()).unwrap();
338 assert_eq!(x.rep(), 0);
339
340 table.delete(x).unwrap();
342 table.delete(y).unwrap();
343
344 let y = table.push(()).unwrap();
345 assert_eq!(y.rep(), 1);
346
347 let x = table.push(()).unwrap();
348 assert_eq!(x.rep(), 0);
349
350 let x = table.push(()).unwrap();
352 assert_eq!(x.rep(), 2);
353}