#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use alloc::{
boxed::Box,
string::{String, ToString},
sync::Arc,
vec::Vec,
};
use core::{any::Any, fmt};
use anyhow::Result;
use fxhash::FxBuildHasher;
use hashbrown::HashMap;
use ref_cast::RefCast;
use smallvec::SmallVec;
use crate::backend::*;
pub mod backend;
const DEFAULT_ARGUMENT_SIZE: usize = 4;
type ArgumentVec<T> = SmallVec<[T; DEFAULT_ARGUMENT_SIZE]>;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ValType {
I32,
I64,
F32,
F64,
V128,
FuncRef,
ExternRef,
}
impl fmt::Display for ValType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::I32 => write!(f, "i32"),
Self::I64 => write!(f, "i64"),
Self::F32 => write!(f, "f32"),
Self::F64 => write!(f, "f64"),
Self::V128 => write!(f, "v128"),
Self::FuncRef => write!(f, "funcref"),
Self::ExternRef => write!(f, "externref"),
}
}
}
impl From<RefType> for ValType {
fn from(ty: RefType) -> Self {
match ty {
RefType::FuncRef => Self::FuncRef,
RefType::ExternRef => Self::ExternRef,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum RefType {
FuncRef,
ExternRef,
}
impl fmt::Display for RefType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::FuncRef => write!(f, "funcref"),
Self::ExternRef => write!(f, "externref"),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct GlobalType {
content: ValType,
mutable: bool,
}
impl GlobalType {
pub fn new(content: ValType, mutable: bool) -> Self {
Self { content, mutable }
}
pub fn content(&self) -> ValType {
self.content
}
pub fn mutable(&self) -> bool {
self.mutable
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TableType {
element: RefType,
min: u32,
max: Option<u32>,
}
impl TableType {
pub fn new(element: RefType, min: u32, max: Option<u32>) -> Self {
if let Some(max) = max {
assert!(min <= max);
}
Self { element, min, max }
}
pub fn element(&self) -> RefType {
self.element
}
pub fn minimum(&self) -> u32 {
self.min
}
pub fn maximum(&self) -> Option<u32> {
self.max
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MemoryType {
initial: u32,
maximum: Option<u32>,
}
impl MemoryType {
pub fn new(initial: u32, maximum: Option<u32>) -> Self {
Self { initial, maximum }
}
pub fn initial_pages(self) -> u32 {
self.initial
}
pub fn maximum_pages(self) -> Option<u32> {
self.maximum
}
}
#[derive(Clone)]
pub struct FuncType {
len_params: usize,
params_results: Arc<[ValType]>,
name: Option<Arc<str>>,
}
impl fmt::Debug for FuncType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("FuncType")
.field("params", &self.params())
.field("results", &self.results())
.field("name", &self.name)
.finish()
}
}
impl PartialEq for FuncType {
fn eq(&self, other: &Self) -> bool {
self.len_params == other.len_params && self.params_results == other.params_results
}
}
impl Eq for FuncType {}
impl fmt::Display for FuncType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let params = self.params();
let results = self.results();
let mut first = true;
write!(f, "func(")?;
for param in params {
if !first {
write!(f, ", ")?;
} else {
first = false;
}
write!(f, "{param}")?;
}
let mut first = true;
write!(f, ")")?;
for result in results {
if !first {
first = false;
write!(f, ", ")?;
} else {
write!(f, " -> ")?;
}
write!(f, "{result}")?;
}
Ok(())
}
}
impl FuncType {
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator<Item = ValType>,
R: IntoIterator<Item = ValType>,
{
let mut params_results = params.into_iter().collect::<Vec<_>>();
let len_params = params_results.len();
params_results.extend(results);
Self {
params_results: params_results.into(),
len_params,
name: None,
}
}
pub fn params(&self) -> &[ValType] {
&self.params_results[..self.len_params]
}
pub fn results(&self) -> &[ValType] {
&self.params_results[self.len_params..]
}
pub fn with_name(mut self, name: impl Into<Arc<str>>) -> Self {
self.name = Some(name.into());
self
}
}
#[derive(Clone, Debug)]
pub enum ExternType {
Global(GlobalType),
Table(TableType),
Memory(MemoryType),
Func(FuncType),
}
impl From<GlobalType> for ExternType {
fn from(global: GlobalType) -> Self {
Self::Global(global)
}
}
impl From<TableType> for ExternType {
fn from(table: TableType) -> Self {
Self::Table(table)
}
}
impl From<MemoryType> for ExternType {
fn from(memory: MemoryType) -> Self {
Self::Memory(memory)
}
}
impl From<FuncType> for ExternType {
fn from(func: FuncType) -> Self {
Self::Func(func)
}
}
impl ExternType {
pub fn global(&self) -> Option<&GlobalType> {
match self {
Self::Global(ty) => Some(ty),
_ => None,
}
}
pub fn table(&self) -> Option<&TableType> {
match self {
Self::Table(ty) => Some(ty),
_ => None,
}
}
pub fn memory(&self) -> Option<&MemoryType> {
match self {
Self::Memory(ty) => Some(ty),
_ => None,
}
}
pub fn func(&self) -> Option<&FuncType> {
match self {
Self::Func(ty) => Some(ty),
_ => None,
}
}
pub fn try_into_func(self) -> core::result::Result<FuncType, Self> {
if let Self::Func(v) = self {
Ok(v)
} else {
Err(self)
}
}
pub fn try_into_table(self) -> Result<TableType, Self> {
if let Self::Table(v) = self {
Ok(v)
} else {
Err(self)
}
}
pub fn try_into_global(self) -> Result<GlobalType, Self> {
if let Self::Global(v) = self {
Ok(v)
} else {
Err(self)
}
}
pub fn try_into_memory(self) -> Result<MemoryType, Self> {
if let Self::Memory(v) = self {
Ok(v)
} else {
Err(self)
}
}
}
#[derive(Clone, Debug)]
pub struct ExportType<'module> {
pub name: &'module str,
pub ty: ExternType,
}
#[derive(Clone, Debug)]
pub struct ImportType<'module> {
pub module: &'module str,
pub name: &'module str,
pub ty: ExternType,
}
#[derive(Clone, Debug)]
pub enum Extern {
Global(Global),
Table(Table),
Memory(Memory),
Func(Func),
}
impl Extern {
pub fn into_global(self) -> Option<Global> {
if let Self::Global(global) = self {
return Some(global);
}
None
}
pub fn into_table(self) -> Option<Table> {
if let Self::Table(table) = self {
return Some(table);
}
None
}
pub fn into_memory(self) -> Option<Memory> {
if let Self::Memory(memory) = self {
return Some(memory);
}
None
}
pub fn into_func(self) -> Option<Func> {
if let Self::Func(func) = self {
return Some(func);
}
None
}
pub fn ty(&self, ctx: impl AsContext) -> ExternType {
match self {
Extern::Global(global) => global.ty(ctx).into(),
Extern::Table(table) => table.ty(ctx).into(),
Extern::Memory(memory) => memory.ty(ctx).into(),
Extern::Func(func) => func.ty(ctx).into(),
}
}
}
impl<E: WasmEngine> From<&crate::backend::Extern<E>> for Extern {
fn from(value: &crate::backend::Extern<E>) -> Self {
match value {
crate::backend::Extern::Global(x) => Self::Global(Global {
global: BackendObject::new(x.clone()),
}),
crate::backend::Extern::Table(x) => Self::Table(Table {
table: BackendObject::new(x.clone()),
}),
crate::backend::Extern::Memory(x) => Self::Memory(Memory {
memory: BackendObject::new(x.clone()),
}),
crate::backend::Extern::Func(x) => Self::Func(Func {
func: BackendObject::new(x.clone()),
}),
}
}
}
impl<E: WasmEngine> From<&Extern> for crate::backend::Extern<E> {
fn from(value: &Extern) -> Self {
match value {
Extern::Global(x) => Self::Global(x.global.cast::<E::Global>().clone()),
Extern::Table(x) => Self::Table(x.table.cast::<E::Table>().clone()),
Extern::Memory(x) => Self::Memory(x.memory.cast::<E::Memory>().clone()),
Extern::Func(x) => Self::Func(x.func.cast::<E::Func>().clone()),
}
}
}
pub struct Export {
pub name: String,
pub value: Extern,
}
impl<E: WasmEngine> From<crate::backend::Export<E>> for Export {
fn from(value: crate::backend::Export<E>) -> Self {
Self {
name: value.name,
value: (&value.value).into(),
}
}
}
#[derive(Clone, Debug)]
pub struct Imports {
pub(crate) map: HashMap<(String, String), Extern, FxBuildHasher>,
}
impl Imports {
pub fn new() -> Self {
Self {
map: HashMap::default(),
}
}
pub fn get_export(&self, module: &str, name: &str) -> Option<Extern> {
if self.exists(module, name) {
let ext = &self.map[&(module.to_string(), name.to_string())];
return Some(ext.clone());
}
None
}
pub fn exists(&self, module: &str, name: &str) -> bool {
self.map
.contains_key(&(module.to_string(), name.to_string()))
}
pub fn contains_namespace(&self, name: &str) -> bool {
self.map.keys().any(|(k, _)| k == name)
}
pub fn register_namespace(
&mut self,
ns: &str,
contents: impl IntoIterator<Item = (String, Extern)>,
) {
for (name, r#extern) in contents.into_iter() {
self.map.insert((ns.to_string(), name.clone()), r#extern);
}
}
pub fn define(&mut self, ns: &str, name: &str, val: impl Into<Extern>) {
self.map
.insert((ns.to_string(), name.to_string()), val.into());
}
pub fn iter(&self) -> ImportsIterator<'_> {
ImportsIterator::new(self)
}
}
pub struct ImportsIterator<'a> {
iter: hashbrown::hash_map::Iter<'a, (String, String), Extern>,
}
impl<'a> ImportsIterator<'a> {
fn new(imports: &'a Imports) -> Self {
let iter = imports.map.iter();
Self { iter }
}
}
impl<'a> Iterator for ImportsIterator<'a> {
type Item = (&'a str, &'a str, &'a Extern);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(k, v)| (k.0.as_str(), k.1.as_str(), v))
}
}
impl IntoIterator for &Imports {
type IntoIter = hashbrown::hash_map::IntoIter<(String, String), Extern>;
type Item = ((String, String), Extern);
fn into_iter(self) -> Self::IntoIter {
self.map.clone().into_iter()
}
}
impl Default for Imports {
fn default() -> Self {
Self::new()
}
}
impl Extend<((String, String), Extern)> for Imports {
fn extend<T: IntoIterator<Item = ((String, String), Extern)>>(&mut self, iter: T) {
for ((ns, name), ext) in iter.into_iter() {
self.define(&ns, &name, ext);
}
}
}
#[derive(RefCast, Clone)]
#[repr(transparent)]
pub struct Engine<E: WasmEngine> {
backend: E,
}
impl<E: WasmEngine> Engine<E> {
pub fn new(backend: E) -> Self {
Self { backend }
}
pub fn into_backend(self) -> E {
self.backend
}
}
pub struct Store<T: 'static, E: WasmEngine> {
inner: E::Store<T>,
}
impl<T: 'static, E: WasmEngine> Store<T, E> {
pub fn new(engine: &Engine<E>, data: T) -> Self {
Self {
inner: <E::Store<T> as WasmStore<T, E>>::new(&engine.backend, data),
}
}
pub fn engine(&self) -> &Engine<E> {
Engine::<E>::ref_cast(self.inner.engine())
}
pub fn data(&self) -> &T {
self.inner.data()
}
pub fn data_mut(&mut self) -> &mut T {
self.inner.data_mut()
}
pub fn into_data(self) -> T {
self.inner.into_data()
}
}
pub struct StoreContext<'a, T: 'static, E: WasmEngine> {
inner: E::StoreContext<'a, T>,
}
impl<'a, T: 'static, E: WasmEngine> StoreContext<'a, T, E> {
pub fn engine(&self) -> &Engine<E> {
Engine::<E>::ref_cast(self.inner.engine())
}
pub fn data(&self) -> &T {
self.inner.data()
}
}
pub struct StoreContextMut<'a, T: 'static, E: WasmEngine> {
pub inner: E::StoreContextMut<'a, T>,
}
impl<'a, T: 'static, E: WasmEngine> StoreContextMut<'a, T, E> {
pub fn engine(&self) -> &Engine<E> {
Engine::<E>::ref_cast(self.inner.engine())
}
pub fn data(&self) -> &T {
self.inner.data()
}
pub fn data_mut(&mut self) -> &mut T {
self.inner.data_mut()
}
}
#[derive(Clone, Debug)]
pub enum Val {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
V128(u128),
FuncRef(Option<Func>),
ExternRef(Option<ExternRef>),
}
impl Val {
#[must_use]
pub const fn ty(&self) -> ValType {
match self {
Self::I32(_) => ValType::I32,
Self::I64(_) => ValType::I64,
Self::F32(_) => ValType::F32,
Self::F64(_) => ValType::F64,
Self::V128(_) => ValType::V128,
Self::FuncRef(_) => ValType::FuncRef,
Self::ExternRef(_) => ValType::ExternRef,
}
}
}
impl PartialEq for Val {
fn eq(&self, o: &Self) -> bool {
match (self, o) {
(Self::I32(a), Self::I32(b)) => a == b,
(Self::I64(a), Self::I64(b)) => a == b,
(Self::F32(a), Self::F32(b)) => a == b,
(Self::F64(a), Self::F64(b)) => a == b,
(Self::V128(a), Self::V128(b)) => a == b,
(Self::FuncRef(_), Self::FuncRef(_)) => false,
(Self::ExternRef(_), Self::ExternRef(_)) => false,
_ => false,
}
}
}
impl From<Ref> for Val {
fn from(r#ref: Ref) -> Self {
match r#ref {
Ref::FuncRef(f) => Self::FuncRef(f),
Ref::ExternRef(e) => Self::ExternRef(e),
}
}
}
impl<E: WasmEngine> From<&Val> for crate::backend::Val<E> {
fn from(value: &Val) -> Self {
match value {
Val::I32(i32) => Self::I32(*i32),
Val::I64(i64) => Self::I64(*i64),
Val::F32(f32) => Self::F32(*f32),
Val::F64(f64) => Self::F64(*f64),
Val::V128(v128) => Self::V128(*v128),
Val::FuncRef(None) => Self::FuncRef(None),
Val::FuncRef(Some(func)) => Self::FuncRef(Some(func.func.cast::<E::Func>().clone())),
Val::ExternRef(None) => Self::ExternRef(None),
Val::ExternRef(Some(extern_ref)) => {
Self::ExternRef(Some(extern_ref.extern_ref.cast::<E::ExternRef>().clone()))
}
}
}
}
impl<E: WasmEngine> From<&backend::Val<E>> for Val {
fn from(value: &crate::backend::Val<E>) -> Self {
match value {
backend::Val::I32(i32) => Self::I32(*i32),
backend::Val::I64(i64) => Self::I64(*i64),
backend::Val::F32(f32) => Self::F32(*f32),
backend::Val::F64(f64) => Self::F64(*f64),
backend::Val::V128(v128) => Self::V128(*v128),
backend::Val::FuncRef(None) => Self::FuncRef(None),
backend::Val::FuncRef(Some(func)) => Self::FuncRef(Some(Func {
func: BackendObject::new(func.clone()),
})),
backend::Val::ExternRef(None) => Self::ExternRef(None),
backend::Val::ExternRef(Some(extern_ref)) => Self::ExternRef(Some(ExternRef {
extern_ref: BackendObject::new(extern_ref.clone()),
})),
}
}
}
#[derive(Clone, Debug)]
pub enum Ref {
FuncRef(Option<Func>),
ExternRef(Option<ExternRef>),
}
impl Ref {
#[must_use]
pub const fn ty(&self) -> RefType {
match self {
Self::FuncRef(_) => RefType::FuncRef,
Self::ExternRef(_) => RefType::ExternRef,
}
}
}
impl<E: WasmEngine> From<&Ref> for crate::backend::Ref<E> {
fn from(r#ref: &Ref) -> Self {
match r#ref {
Ref::FuncRef(None) => Self::FuncRef(None),
Ref::FuncRef(Some(func)) => Self::FuncRef(Some(func.func.cast::<E::Func>().clone())),
Ref::ExternRef(None) => Self::ExternRef(None),
Ref::ExternRef(Some(extern_ref)) => {
Self::ExternRef(Some(extern_ref.extern_ref.cast::<E::ExternRef>().clone()))
}
}
}
}
impl<E: WasmEngine> From<&backend::Ref<E>> for Ref {
fn from(r#ref: &backend::Ref<E>) -> Self {
match r#ref {
backend::Ref::FuncRef(None) => Self::FuncRef(None),
backend::Ref::FuncRef(Some(func)) => Self::FuncRef(Some(Func {
func: BackendObject::new(func.clone()),
})),
backend::Ref::ExternRef(None) => Self::ExternRef(None),
backend::Ref::ExternRef(Some(extern_ref)) => Self::ExternRef(Some(ExternRef {
extern_ref: BackendObject::new(extern_ref.clone()),
})),
}
}
}
#[derive(Clone, Debug)]
pub struct ExternRef {
extern_ref: BackendObject,
}
impl ExternRef {
pub fn new<T: 'static + Send + Sync, C: AsContextMut>(mut ctx: C, object: T) -> Self {
Self {
extern_ref: BackendObject::new(
<<C::Engine as WasmEngine>::ExternRef as WasmExternRef<C::Engine>>::new(
ctx.as_context_mut().inner,
object,
),
),
}
}
pub fn downcast<'a, 's: 'a, T: 'static, S: 'static, E: WasmEngine>(
&'a self,
ctx: StoreContext<'s, S, E>,
) -> Result<&'a T> {
self.extern_ref.cast::<E::ExternRef>().downcast(ctx.inner)
}
}
#[derive(Clone, Debug)]
pub struct Func {
func: BackendObject,
}
impl Func {
pub fn new<C: AsContextMut>(
mut ctx: C,
ty: FuncType,
func: impl 'static
+ Send
+ Sync
+ Fn(StoreContextMut<'_, C::UserState, C::Engine>, &[Val], &mut [Val]) -> Result<()>,
) -> Self {
let raw_func = <<C::Engine as WasmEngine>::Func as WasmFunc<C::Engine>>::new(
ctx.as_context_mut().inner,
ty,
move |ctx, args, results| {
let mut input = ArgumentVec::with_capacity(args.len());
input.extend(args.iter().map(Into::into));
let mut output = ArgumentVec::with_capacity(results.len());
output.extend(results.iter().map(Into::into));
func(StoreContextMut { inner: ctx }, &input, &mut output)?;
for (i, result) in output.iter().enumerate() {
results[i] = result.into();
}
Ok(())
},
);
Self {
func: BackendObject::new(raw_func),
}
}
pub fn ty<C: AsContext>(&self, ctx: C) -> FuncType {
self.func
.cast::<<C::Engine as WasmEngine>::Func>()
.ty(ctx.as_context().inner)
}
pub fn call<C: AsContextMut>(
&self,
mut ctx: C,
args: &[Val],
results: &mut [Val],
) -> Result<()> {
let raw_func = self.func.cast::<<C::Engine as WasmEngine>::Func>();
let mut input = ArgumentVec::with_capacity(args.len());
input.extend(args.iter().map(Into::into));
let mut output = ArgumentVec::with_capacity(results.len());
output.extend(results.iter().map(Into::into));
raw_func.call::<C::UserState>(ctx.as_context_mut().inner, &input, &mut output)?;
for (i, result) in output.iter().enumerate() {
results[i] = result.into();
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct Global {
global: BackendObject,
}
impl Global {
pub fn new<C: AsContextMut>(mut ctx: C, initial_value: Val, mutable: bool) -> Self {
Self {
global: BackendObject::new(<<C::Engine as WasmEngine>::Global as WasmGlobal<
C::Engine,
>>::new(
ctx.as_context_mut().inner,
(&initial_value).into(),
mutable,
)),
}
}
pub fn ty<C: AsContext>(&self, ctx: C) -> GlobalType {
self.global
.cast::<<C::Engine as WasmEngine>::Global>()
.ty(ctx.as_context().inner)
}
pub fn get<C: AsContextMut>(&self, mut ctx: C) -> Val {
(&self
.global
.cast::<<C::Engine as WasmEngine>::Global>()
.get(ctx.as_context_mut().inner))
.into()
}
pub fn set<C: AsContextMut>(&self, mut ctx: C, new_value: Val) -> Result<()> {
self.global
.cast::<<C::Engine as WasmEngine>::Global>()
.set(ctx.as_context_mut().inner, (&new_value).into())
}
}
#[derive(Clone, Debug)]
pub struct Module {
module: BackendObject,
}
impl Module {
pub fn new<E: WasmEngine>(engine: &Engine<E>, bytes: &[u8]) -> Result<Self> {
Ok(Self {
module: BackendObject::new(<E::Module as WasmModule<E>>::new(&engine.backend, bytes)?),
})
}
pub fn exports<E: WasmEngine>(
&self,
#[allow(unused_variables)] engine: &Engine<E>,
) -> impl '_ + Iterator<Item = ExportType<'_>> {
self.module.cast::<E::Module>().exports()
}
pub fn get_export<E: WasmEngine>(
&self,
#[allow(unused_variables)] engine: &Engine<E>,
name: &str,
) -> Option<ExternType> {
self.module.cast::<E::Module>().get_export(name)
}
pub fn imports<E: WasmEngine>(
&self,
#[allow(unused_variables)] engine: &Engine<E>,
) -> impl '_ + Iterator<Item = ImportType<'_>> {
self.module.cast::<E::Module>().imports()
}
}
#[derive(Clone, Debug)]
pub struct Instance {
instance: BackendObject,
}
impl Instance {
pub fn new<C: AsContextMut>(mut ctx: C, module: &Module, imports: &Imports) -> Result<Self> {
let mut backend_imports = crate::backend::Imports::default();
backend_imports.extend(
imports
.into_iter()
.map(|((host, name), val)| ((host, name), (&val).into())),
);
Ok(Self {
instance: BackendObject::new(<<C::Engine as WasmEngine>::Instance as WasmInstance<
C::Engine,
>>::new(
ctx.as_context_mut().inner,
module.module.cast(),
&backend_imports,
)?),
})
}
pub fn exports<C: AsContext>(&self, ctx: C) -> impl Iterator<Item = Export> {
let instance = self.instance.cast::<<C::Engine as WasmEngine>::Instance>();
<_ as WasmInstance<_>>::exports(instance, ctx.as_context().inner).map(Into::into)
}
pub fn get_export<C: AsContext>(&self, ctx: C, name: &str) -> Option<Extern> {
let instance = self.instance.cast::<<C::Engine as WasmEngine>::Instance>();
<_ as WasmInstance<_>>::get_export(instance, ctx.as_context().inner, name)
.as_ref()
.map(Into::into)
}
}
#[derive(Clone, Debug)]
pub struct Memory {
memory: BackendObject,
}
impl Memory {
pub fn new<C: AsContextMut>(mut ctx: C, ty: MemoryType) -> Result<Self> {
Ok(Self {
memory: BackendObject::new(<<C::Engine as WasmEngine>::Memory as WasmMemory<
C::Engine,
>>::new(ctx.as_context_mut().inner, ty)?),
})
}
pub fn ty<C: AsContext>(&self, ctx: C) -> MemoryType {
self.memory
.cast::<<C::Engine as WasmEngine>::Memory>()
.ty(ctx.as_context().inner)
}
pub fn grow<C: AsContextMut>(&self, mut ctx: C, additional: u32) -> Result<u32> {
self.memory
.cast::<<C::Engine as WasmEngine>::Memory>()
.grow(ctx.as_context_mut().inner, additional)
}
pub fn current_pages<C: AsContext>(&self, ctx: C) -> u32 {
self.memory
.cast::<<C::Engine as WasmEngine>::Memory>()
.current_pages(ctx.as_context().inner)
}
pub fn read<C: AsContext>(&self, ctx: C, offset: usize, buffer: &mut [u8]) -> Result<()> {
self.memory
.cast::<<C::Engine as WasmEngine>::Memory>()
.read(ctx.as_context().inner, offset, buffer)
}
pub fn write<C: AsContextMut>(&self, mut ctx: C, offset: usize, buffer: &[u8]) -> Result<()> {
self.memory
.cast::<<C::Engine as WasmEngine>::Memory>()
.write(ctx.as_context_mut().inner, offset, buffer)
}
}
#[derive(Clone, Debug)]
pub struct Table {
table: BackendObject,
}
impl Table {
pub fn new<C: AsContextMut>(mut ctx: C, ty: TableType, init: Ref) -> Result<Self> {
Ok(Self {
table: BackendObject::new(<<C::Engine as WasmEngine>::Table as WasmTable<
C::Engine,
>>::new(
ctx.as_context_mut().inner, ty, (&init).into()
)?),
})
}
pub fn ty<C: AsContext>(&self, ctx: C) -> TableType {
self.table
.cast::<<C::Engine as WasmEngine>::Table>()
.ty(ctx.as_context().inner)
}
pub fn size<C: AsContext>(&self, ctx: C) -> u32 {
self.table
.cast::<<C::Engine as WasmEngine>::Table>()
.size(ctx.as_context().inner)
}
pub fn grow<C: AsContextMut>(&self, mut ctx: C, delta: u32, init: Ref) -> Result<u32> {
let table = self.table.cast::<<C::Engine as WasmEngine>::Table>();
<_ as WasmTable<_>>::grow(table, ctx.as_context_mut().inner, delta, (&init).into())
}
pub fn get<C: AsContextMut>(&self, mut ctx: C, index: u32) -> Option<Ref> {
let table = self.table.cast::<<C::Engine as WasmEngine>::Table>();
<_ as WasmTable<_>>::get(table, ctx.as_context_mut().inner, index)
.as_ref()
.map(Into::into)
}
pub fn set<C: AsContextMut>(&self, mut ctx: C, index: u32, elem: Ref) -> Result<()> {
let table = self.table.cast::<<C::Engine as WasmEngine>::Table>();
<_ as WasmTable<_>>::set(table, ctx.as_context_mut().inner, index, (&elem).into())
}
}
struct BackendObject {
inner: Box<dyn AnyCloneBoxed>,
}
impl BackendObject {
pub fn new<T: 'static + Clone + Send + Sync>(value: T) -> Self {
Self {
inner: Box::new(value),
}
}
pub fn cast<T: 'static>(&self) -> &T {
self.inner
.as_any()
.downcast_ref()
.expect("Attempted to use incorrect context to access function.")
}
}
impl Clone for BackendObject {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone_boxed(),
}
}
}
impl fmt::Debug for BackendObject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BackendObject").finish()
}
}
trait AnyCloneBoxed: Any + Send + Sync {
fn as_any(&self) -> &(dyn Any + Send + Sync);
fn clone_boxed(&self) -> Box<dyn AnyCloneBoxed>;
}
impl<T: Any + Clone + Send + Sync> AnyCloneBoxed for T {
fn as_any(&self) -> &(dyn Any + Send + Sync) {
self
}
fn clone_boxed(&self) -> Box<dyn AnyCloneBoxed> {
Box::new(self.clone())
}
}
pub trait AsContext {
type Engine: WasmEngine;
type UserState: 'static;
fn as_context(&self) -> StoreContext<'_, Self::UserState, Self::Engine>;
}
pub trait AsContextMut: AsContext {
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState, Self::Engine>;
}
impl<T: 'static, E: WasmEngine> AsContext for Store<T, E> {
type Engine = E;
type UserState = T;
fn as_context(&self) -> StoreContext<'_, Self::UserState, Self::Engine> {
StoreContext {
inner: crate::backend::AsContext::as_context(&self.inner),
}
}
}
impl<T: 'static, E: WasmEngine> AsContextMut for Store<T, E> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState, Self::Engine> {
StoreContextMut {
inner: crate::backend::AsContextMut::as_context_mut(&mut self.inner),
}
}
}
impl<T: AsContext> AsContext for &T {
type Engine = T::Engine;
type UserState = T::UserState;
fn as_context(&self) -> StoreContext<'_, Self::UserState, Self::Engine> {
(**self).as_context()
}
}
impl<T: AsContext> AsContext for &mut T {
type Engine = T::Engine;
type UserState = T::UserState;
fn as_context(&self) -> StoreContext<'_, Self::UserState, Self::Engine> {
(**self).as_context()
}
}
impl<T: AsContextMut> AsContextMut for &mut T {
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState, Self::Engine> {
(**self).as_context_mut()
}
}
impl<'a, T: 'static, E: WasmEngine> AsContext for StoreContext<'a, T, E> {
type Engine = E;
type UserState = T;
fn as_context(&self) -> StoreContext<'_, Self::UserState, Self::Engine> {
StoreContext {
inner: crate::backend::AsContext::as_context(&self.inner),
}
}
}
impl<'a, T: 'static, E: WasmEngine> AsContext for StoreContextMut<'a, T, E> {
type Engine = E;
type UserState = T;
fn as_context(&self) -> StoreContext<'_, Self::UserState, Self::Engine> {
StoreContext {
inner: crate::backend::AsContext::as_context(&self.inner),
}
}
}
impl<'a, T: 'static, E: WasmEngine> AsContextMut for StoreContextMut<'a, T, E> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState, Self::Engine> {
StoreContextMut {
inner: crate::backend::AsContextMut::as_context_mut(&mut self.inner),
}
}
}