use crate::bail_bug;
use crate::prelude::*;
use core::any::Any;
use wasmtime_core::{
alloc::PanicOnOom,
slab::{Id, Slab},
};
#[derive(Default)]
pub struct ExternRefHostDataTable {
slab: Slab<Box<dyn Any + Send + Sync>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct ExternRefHostDataId(Id);
fn deref_box<T: ?Sized>(b: &Box<T>) -> &T {
&**b
}
fn deref_box_mut<T: ?Sized>(b: &mut Box<T>) -> &mut T {
&mut **b
}
impl ExternRefHostDataTable {
pub fn alloc(&mut self, value: Box<dyn Any + Send + Sync>) -> ExternRefHostDataId {
let id = self.slab.alloc(value).panic_on_oom();
let id = ExternRefHostDataId(id);
log::trace!("allocated new externref host data: {id:?}");
id
}
pub fn dealloc(&mut self, id: ExternRefHostDataId) -> Result<Box<dyn Any + Send + Sync>> {
self.get(id)?;
log::trace!("deallocated externref host data: {id:?}");
Ok(self.slab.dealloc(id.0))
}
pub fn get(&self, id: ExternRefHostDataId) -> Result<&(dyn Any + Send + Sync)> {
let data: &Box<dyn Any + Send + Sync> = match self.slab.get(id.0) {
Some(data) => data,
None => bail_bug!("invalid `ExternRefHostDataId`"),
};
Ok(deref_box(data))
}
pub fn get_mut(&mut self, id: ExternRefHostDataId) -> Result<&mut (dyn Any + Send + Sync)> {
let data: &mut Box<dyn Any + Send + Sync> = match self.slab.get_mut(id.0) {
Some(data) => data,
None => bail_bug!("invalid `ExternRefHostDataId`"),
};
Ok(deref_box_mut(data))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn correct_dyn_object() {
let mut table = ExternRefHostDataTable::default();
let x = 42_u32;
let id = table.alloc(Box::new(x));
assert!(table.get(id).unwrap().is::<u32>());
assert_eq!(*table.get(id).unwrap().downcast_ref::<u32>().unwrap(), 42);
assert!(table.get_mut(id).unwrap().is::<u32>());
assert_eq!(
*table.get_mut(id).unwrap().downcast_ref::<u32>().unwrap(),
42
);
}
}