wasmtime/runtime/vm/gc/
host_data.rs1use crate::bail_bug;
17use crate::prelude::*;
18use core::any::Any;
19use wasmtime_core::{
20 alloc::PanicOnOom,
21 slab::{Id, Slab},
22};
23
24#[derive(Default)]
26pub struct ExternRefHostDataTable {
27 slab: Slab<Box<dyn Any + Send + Sync>>,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
32#[repr(transparent)]
33pub struct ExternRefHostDataId(Id);
34
35fn deref_box<T: ?Sized>(b: &Box<T>) -> &T {
36 &**b
37}
38
39fn deref_box_mut<T: ?Sized>(b: &mut Box<T>) -> &mut T {
40 &mut **b
41}
42
43impl ExternRefHostDataTable {
44 pub fn alloc(&mut self, value: Box<dyn Any + Send + Sync>) -> ExternRefHostDataId {
46 let id = self.slab.alloc(value).panic_on_oom();
48 let id = ExternRefHostDataId(id);
49 log::trace!("allocated new externref host data: {id:?}");
50 id
51 }
52
53 pub fn dealloc(&mut self, id: ExternRefHostDataId) -> Result<Box<dyn Any + Send + Sync>> {
55 self.get(id)?;
57 log::trace!("deallocated externref host data: {id:?}");
58 Ok(self.slab.dealloc(id.0))
59 }
60
61 pub fn get(&self, id: ExternRefHostDataId) -> Result<&(dyn Any + Send + Sync)> {
63 let data: &Box<dyn Any + Send + Sync> = match self.slab.get(id.0) {
64 Some(data) => data,
65 None => bail_bug!("invalid `ExternRefHostDataId`"),
66 };
67 Ok(deref_box(data))
68 }
69
70 pub fn get_mut(&mut self, id: ExternRefHostDataId) -> Result<&mut (dyn Any + Send + Sync)> {
72 let data: &mut Box<dyn Any + Send + Sync> = match self.slab.get_mut(id.0) {
73 Some(data) => data,
74 None => bail_bug!("invalid `ExternRefHostDataId`"),
75 };
76 Ok(deref_box_mut(data))
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn correct_dyn_object() {
86 let mut table = ExternRefHostDataTable::default();
87
88 let x = 42_u32;
89 let id = table.alloc(Box::new(x));
90 assert!(table.get(id).unwrap().is::<u32>());
91 assert_eq!(*table.get(id).unwrap().downcast_ref::<u32>().unwrap(), 42);
92 assert!(table.get_mut(id).unwrap().is::<u32>());
93 assert_eq!(
94 *table.get_mut(id).unwrap().downcast_ref::<u32>().unwrap(),
95 42
96 );
97 }
98}