PkmnLib_rs/src/script_implementations/wasm/extern_ref.rs

181 lines
5.6 KiB
Rust
Executable File

use anyhow_ext::Result;
use std::marker::PhantomData;
use std::mem::transmute;
use std::sync::Arc;
use crate::script_implementations::wasm::export_registry::{FromWasmObj, WasmObject};
use crate::script_implementations::wasm::script_resolver::{
WebAssemblyEnv, WebAssemblyEnvironmentData, WebAssemblyScriptResolver,
};
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.
pub(crate) struct ExternRef<T: ?Sized> {
/// The lookup index we can use to find the data.
index: usize,
/// Phantom data so we can get a type generic.
_phantom: PhantomData<T>,
}
impl<T: ?Sized> Copy for ExternRef<T> {}
impl<T: ?Sized> Clone for ExternRef<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Default for ExternRef<T> {
fn default() -> Self {
Self {
index: 0,
_phantom: Default::default(),
}
}
}
impl<T: ?Sized> ExternRef<T> {
/// 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: WasmObject) -> 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<WebAssemblyEnv>, value: WasmObject) -> 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: WasmObject) -> 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(&self, env: &FunctionEnvMut<WebAssemblyEnv>) -> Result<T>
where
T: FromWasmObj,
{
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_func_arc(&self, env: &FunctionEnvMut<WebAssemblyEnv>) -> Result<Arc<T>>
where
Arc<T>: FromWasmObj,
{
self.value_arc(&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(&self, env: &Arc<WebAssemblyEnvironmentData>) -> Result<T>
where
T: FromWasmObj,
{
let value = env.get_extern_ref_value::<T>(self.index)?;
let o = FromWasmObj::from_wasm_obj(value)?;
Ok(o)
}
/// 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_arc(&self, env: &Arc<WebAssemblyEnvironmentData>) -> Result<Arc<T>>
where
Arc<T>: FromWasmObj,
{
let wasm_obj = env.get_extern_ref_value::<T>(self.index)?;
FromWasmObj::from_wasm_obj(wasm_obj)
}
/// Returns the internal index for this ExternRef.
pub(crate) fn index(&self) -> usize {
self.index
}
}
unsafe impl<T: ?Sized> FromToNativeWasmType for ExternRef<T> {
type Native = i32;
fn from_native(native: Self::Native) -> Self {
Self {
index: native as usize,
_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<T> {
/// The lookup index we can use to find the data.
index: usize,
/// The number of items in the vec.
size: u32,
/// Phantom data so we can get a type generic.
_phantom: PhantomData<T>,
}
impl<T> Clone for VecExternRef<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for VecExternRef<T> {}
impl<T> Default for VecExternRef<T> {
fn default() -> Self {
Self {
index: 0,
size: 0,
_phantom: Default::default(),
}
}
}
unsafe impl<T> FromToNativeWasmType for VecExternRef<T> {
type Native = i64;
fn from_native(native: Self::Native) -> Self {
let split: (u32, u32) = unsafe { transmute(native) };
Self {
index: split.0 as usize,
size: split.1,
_phantom: Default::default(),
}
}
fn to_native(self) -> Self::Native {
let v: i64 = unsafe { transmute((self.index as u32, self.size)) };
v
}
}