use std::marker::PhantomData; use std::mem::transmute; use std::sync::Arc; use crate::script_implementations::wasm::script_resolver::{ WebAssemblyEnv, WebAssemblyEnvironmentData, WebAssemblyScriptResolver, }; use unique_type_id::UniqueTypeId; use wasmer::FromToNativeWasmType; use wasmer::FunctionEnvMut; /// An Extern Ref allows us to pass objects to WASM without actually passing raw memory, or /// requiring us to make copies. Instead, we pass a simple increment index, that we can then use /// to find the relevant data. #[derive(Copy, Clone)] pub(crate) struct ExternRef> { /// The lookup index we can use to find the data. index: u32, /// Phantom data so we can get a type generic. _phantom: PhantomData, } impl> ExternRef { /// Instantiates a new ExternRef for a bit of data. If we already have made an Extern Ref for /// this data and type, we use that instead. pub fn new(env: &WebAssemblyEnvironmentData, value: &T) -> Self { Self { index: env.get_extern_ref_index(value), _phantom: Default::default(), } } /// Instantiates a new ExternRef for a bit of data using the function environment. If we already /// have made an Extern Ref for this data and type, we use that instead. pub fn func_new(env: &FunctionEnvMut, value: &T) -> Self { Self { index: env.data().data().get_extern_ref_index(value), _phantom: Default::default(), } } /// Creates an ExternRef with a given resolver. This can be used in cases where we do not have an environment variable. pub(crate) fn new_with_resolver(resolver: &WebAssemblyScriptResolver, value: &T) -> Self { Self { index: resolver.environment_data().get_extern_ref_index(value), _phantom: Default::default(), } } /// An empty value ExternRef. pub fn null() -> Self { Self { index: 0, _phantom: Default::default(), } } /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the /// value when it was passed before. If these types do not match, this will panic. pub fn value_func<'a, 'b>(&'a self, env: &'b FunctionEnvMut) -> Option<&'b T> { self.value(&env.data().data()) } /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the /// value when it was passed before. If these types do not match, this will panic. pub fn value<'a, 'b, 'c>(&'a self, env: &'b Arc) -> Option<&'c T> { let ptr = env.get_extern_ref_value(self.index) as *const T; unsafe { ptr.as_ref() } } } unsafe impl> FromToNativeWasmType for ExternRef { type Native = i32; fn from_native(native: Self::Native) -> Self { Self { index: native as u32, _phantom: Default::default(), } } fn to_native(self) -> Self::Native { self.index as i32 } } /// A VecExternRef is an Extern Ref for vector types. This allows us to pass Vecs to WASM without /// actually passing raw memory, or requiring us to make copies. pub(crate) struct VecExternRef { /// The lookup index we can use to find the data. index: u32, /// The number of items in the vec. size: u32, /// Phantom data so we can get a type generic. _phantom: PhantomData, } impl> VecExternRef { /// Instantiates a new VecExternRef for a given slice. pub fn new(env: &WebAssemblyEnvironmentData, value: &[T]) -> Self { Self { index: env.get_extern_vec_ref_index(value), size: value.len() as u32, _phantom: Default::default(), } } } unsafe impl> FromToNativeWasmType for VecExternRef { type Native = i64; fn from_native(native: Self::Native) -> Self { let split: (u32, u32) = unsafe { transmute(native) }; Self { index: split.0, size: split.1, _phantom: Default::default(), } } fn to_native(self) -> Self::Native { let v: i64 = unsafe { transmute((self.index, self.size)) }; v } }