use alloc::{boxed::Box, vec::Vec};
use core::{
fmt, mem,
ops::{Deref, DerefMut},
};
use slab::Slab;
use wasm_runtime_layer::backend::{
AsContext, AsContextMut, WasmEngine, WasmStore, WasmStoreContext, WasmStoreContextMut,
};
use crate::{
func::FuncInner, instance::InstanceInner, memory::MemoryInner, table::TableInner, DropResource,
Engine, Func, Global, GlobalInner, Instance, Memory, Table,
};
pub struct Store<T: 'static> {
inner: *mut StoreInner<T>,
}
impl<T: 'static> Store<T> {
fn from_inner(inner: Box<StoreInner<T>>) -> Self {
Self {
inner: Box::into_raw(inner),
}
}
pub(crate) fn get(&self) -> StoreContext<'_, T> {
let inner = unsafe { &*self.inner };
StoreContext::from_ref(inner)
}
pub(crate) fn get_mut(&mut self) -> StoreContextMut<'_, T> {
let inner = unsafe { &mut *self.inner };
StoreContextMut::from_ref(inner)
}
}
impl<T: 'static> Drop for Store<T> {
fn drop(&mut self) {
unsafe { drop(Box::from_raw(self.inner)) }
}
}
impl<T: 'static> WasmStore<T, Engine> for Store<T> {
fn new(engine: &Engine, data: T) -> Self {
#[cfg(feature = "tracing")]
let _span = tracing::debug_span!("Store::new").entered();
Self::from_inner(Box::new(StoreInner {
engine: engine.clone(),
instances: Slab::new(),
funcs: Slab::new(),
globals: Slab::new(),
tables: Slab::new(),
memories: Slab::new(),
drop_resources: Vec::new(),
data,
}))
}
fn engine(&self) -> &Engine {
&self.get().store.engine
}
fn data(&self) -> &T {
&self.get().store.data
}
fn data_mut(&mut self) -> &mut T {
&mut self.get_mut().store.data
}
fn into_data(self) -> T {
let ptr = unsafe { Box::from_raw(self.inner) };
mem::forget(self);
ptr.data
}
}
impl<T: 'static> AsContext<Engine> for Store<T> {
type UserState = T;
fn as_context(&self) -> <Engine as WasmEngine>::StoreContext<'_, Self::UserState> {
self.get()
}
}
impl<T: 'static> AsContextMut<Engine> for Store<T> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
self.get_mut()
}
}
impl<T: 'static + fmt::Debug> fmt::Debug for Store<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[derive(Debug)]
pub struct StoreInner<T: 'static> {
pub(crate) engine: Engine,
pub(crate) instances: Slab<InstanceInner>,
pub(crate) funcs: Slab<FuncInner>,
pub(crate) globals: Slab<GlobalInner>,
pub(crate) tables: Slab<TableInner>,
pub(crate) memories: Slab<MemoryInner>,
pub(crate) data: T,
drop_resources: Vec<DropResource>,
}
impl<T: 'static> StoreInner<T> {
pub(crate) fn insert_func(&mut self, func: FuncInner) -> Func {
Func {
id: self.funcs.insert(func),
}
}
pub(crate) fn insert_global(&mut self, global: GlobalInner) -> Global {
Global {
id: self.globals.insert(global),
}
}
pub(crate) fn insert_table(&mut self, table: TableInner) -> Table {
Table {
id: self.tables.insert(table),
}
}
pub(crate) fn insert_instance(&mut self, instance: InstanceInner) -> Instance {
Instance {
id: self.instances.insert(instance),
}
}
pub(crate) fn insert_memory(&mut self, memory: MemoryInner) -> Memory {
Memory {
id: self.memories.insert(memory),
}
}
pub(crate) fn insert_drop_resource(&mut self, value: DropResource) {
self.drop_resources.push(value)
}
}
pub struct StoreContext<'a, T: 'static> {
store: &'a StoreInner<T>,
}
impl<'a, T: 'static> StoreContext<'a, T> {
pub fn from_ref(store: &'a StoreInner<T>) -> Self {
Self { store }
}
}
impl<T: 'static> Deref for StoreContext<'_, T> {
type Target = StoreInner<T>;
fn deref(&self) -> &Self::Target {
self.store
}
}
pub struct StoreContextMut<'a, T: 'static> {
store: &'a mut StoreInner<T>,
}
impl<'a, T: 'static> StoreContextMut<'a, T> {
pub(crate) fn as_ptr(&mut self) -> *mut StoreInner<T> {
self.store as *mut _
}
pub(crate) fn from_ref(store: &'a mut StoreInner<T>) -> Self {
Self { store }
}
}
impl<T: 'static> Deref for StoreContextMut<'_, T> {
type Target = StoreInner<T>;
fn deref(&self) -> &Self::Target {
&*self.store
}
}
impl<T: 'static> DerefMut for StoreContextMut<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.store
}
}
impl<'a, T: 'static> WasmStoreContext<'a, T, Engine> for StoreContext<'a, T> {
fn engine(&self) -> &Engine {
&self.engine
}
fn data(&self) -> &T {
&self.data
}
}
impl<'a, T: 'static> AsContext<Engine> for StoreContext<'a, T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, T> {
StoreContext { store: self.store }
}
}
impl<'a, T: 'static> WasmStoreContext<'a, T, Engine> for StoreContextMut<'a, T> {
fn engine(&self) -> &Engine {
&self.engine
}
fn data(&self) -> &T {
&self.data
}
}
impl<'a, T: 'static> WasmStoreContextMut<'a, T, Engine> for StoreContextMut<'a, T> {
fn data_mut(&mut self) -> &mut T {
&mut self.data
}
}
impl<'a, T: 'static> AsContext<Engine> for StoreContextMut<'a, T> {
type UserState = T;
fn as_context(&self) -> <Engine as WasmEngine>::StoreContext<'_, T> {
StoreContext { store: self.store }
}
}
impl<'a, T: 'static> AsContextMut<Engine> for StoreContextMut<'a, T> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
StoreContextMut { store: self.store }
}
}