watt-non-static-runtime 0.4.0

Runtime for executing Rust procedural macros compiled as WebAssembly.
Documentation
use super::{ffi, FuncType, Store, Trap, Val, ValType, ValTypeVec};
use std::ffi::c_void;
use std::marker;
use std::ptr;

#[repr(transparent)]
pub struct Func {
    pub(crate) raw: *mut ffi::wasm_func_t,
}

impl Func {
    unsafe fn into_host_func(
        store: &Store,
        ty: &FuncType,
        callback: ffi::wasm_func_callback_with_env_t,
        ptr: *mut c_void,
        dtor: unsafe extern "C" fn(*mut c_void),
    ) -> Func {
        let raw = ffi::wasm_func_new_with_env(store.raw, ty.raw, callback, ptr, Some(dtor));
        assert!(!raw.is_null());
        Func { raw }
    }
}

impl Drop for Func {
    fn drop(&mut self) {
        unsafe {
            ffi::wasm_func_delete(self.raw);
        }
    }
}

pub unsafe trait WasmVal {
    fn push_valtype(list: &mut Vec<ValType>);
}

pub unsafe trait WasmArg: WasmVal + Sized {
    unsafe fn from(ptr: *const ffi::wasm_val_t) -> (Self, *const ffi::wasm_val_t);
}

pub unsafe trait WasmRet: WasmVal + Sized {
    unsafe fn into(value: Self, ptr: *mut ffi::wasm_val_t);
}

unsafe impl WasmVal for u32 {
    fn push_valtype(list: &mut Vec<ValType>) {
        list.push(ValType::i32());
    }
}

unsafe impl WasmArg for u32 {
    unsafe fn from(ptr: *const ffi::wasm_val_t) -> (Self, *const ffi::wasm_val_t) {
        ((*ptr).of.i32 as u32, ptr.offset(1))
    }
}

unsafe impl WasmRet for u32 {
    unsafe fn into(value: Self, ptr: *mut ffi::wasm_val_t) {
        (*ptr).of.i32 = value as i32;
    }
}

unsafe impl WasmVal for () {
    fn push_valtype(_list: &mut Vec<ValType>) {}
}

unsafe impl WasmRet for () {
    unsafe fn into(_value: Self, _ptr: *mut ffi::wasm_val_t) {}
}

unsafe extern "C" fn dtor<T>(env: *mut c_void) {
    drop(Box::from_raw(env as *mut T));
}

pub fn func1<A, R, F>(func: F, store: &Store) -> Func
where
    A: WasmArg,
    R: WasmRet,
    F: Fn(A) -> R + 'static,
{
    let mut params = Vec::new();
    A::push_valtype(&mut params);
    let mut results = Vec::new();
    R::push_valtype(&mut results);
    let ty = FuncType::new(ValTypeVec::new(&params), ValTypeVec::new(&results));
    let ptr = Box::into_raw(Box::new(func));
    return unsafe {
        Func::into_host_func(
            store,
            &ty,
            Some(callback::<A, R, F>),
            ptr as *mut c_void,
            dtor::<F>,
        )
    };

    unsafe extern "C" fn callback<A, R, F>(
        env: *mut c_void,
        args: *const ffi::wasm_val_t,
        results: *mut ffi::wasm_val_t,
    ) -> *mut ffi::wasm_trap_t
    where
        A: WasmArg,
        R: WasmRet,
        F: Fn(A) -> R,
    {
        let env = &*(env as *const F);
        let (a, _args) = A::from(args);
        let ret = env(a);
        R::into(ret, results);
        ptr::null_mut()
    }
}

pub fn mem_func2<A, B, R, F>(func: F, store: &Store) -> Func
where
    A: WasmArg,
    B: WasmArg,
    R: WasmRet,
    F: Fn(&mut [u8], A, B) -> R + 'static,
{
    let mut params = Vec::new();
    A::push_valtype(&mut params);
    B::push_valtype(&mut params);
    let mut results = Vec::new();
    R::push_valtype(&mut results);
    let ty = FuncType::new(ValTypeVec::new(&params), ValTypeVec::new(&results));
    let ptr = Box::into_raw(Box::new(func));
    return unsafe {
        Func::into_host_func(
            store,
            &ty,
            Some(callback::<A, B, R, F>),
            ptr as *mut c_void,
            dtor::<F>,
        )
    };

    unsafe extern "C" fn callback<A, B, R, F>(
        env: *mut c_void,
        args: *const ffi::wasm_val_t,
        results: *mut ffi::wasm_val_t,
    ) -> *mut ffi::wasm_trap_t
    where
        A: WasmArg,
        B: WasmArg,
        R: WasmRet,
        F: Fn(&mut [u8], A, B) -> R,
    {
        let env = &*(env as *const F);
        let mem = super::current_memory::with(|m| m.as_slice());
        let (a, args) = A::from(args);
        let (b, _args) = B::from(args);
        let ret = env(&mut *mem, a, b);
        R::into(ret, results);
        ptr::null_mut()
    }
}

#[repr(transparent)]
pub struct FuncRef<'a> {
    pub(crate) raw: *mut ffi::wasm_func_t,
    pub(crate) _marker: marker::PhantomData<&'a i32>,
}

impl FuncRef<'_> {
    pub fn call(&self, args: &[Val]) -> Result<Vec<Val>, Trap> {
        assert_eq!(args.len(), self.param_arity());
        let mut results = Vec::new();
        for _ in 0..self.result_arity() {
            results.push(Val::i32(0));
        }
        unsafe {
            let trap = ffi::wasm_func_call(
                self.raw,
                args.as_ptr() as *const ffi::wasm_val_t,
                results.as_mut_ptr() as *mut ffi::wasm_val_t,
            );
            if trap.is_null() {
                Ok(results)
            } else {
                Err(Trap { raw: trap })
            }
        }
    }

    pub fn param_arity(&self) -> usize {
        unsafe { ffi::wasm_func_param_arity(self.raw) }
    }

    pub fn result_arity(&self) -> usize {
        unsafe { ffi::wasm_func_result_arity(self.raw) }
    }
}