216 lines
6.9 KiB
Rust
Executable File
216 lines
6.9 KiB
Rust
Executable File
use crate::{PkmnError, ValueIdentifiable};
|
|
use anyhow_ext::Result;
|
|
use std::any::Any;
|
|
use std::marker::PhantomData;
|
|
use std::mem::transmute;
|
|
use std::sync::Arc;
|
|
|
|
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 {
|
|
index: self.index,
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> Default for ExternRef<T> {
|
|
fn default() -> Self {
|
|
Self {
|
|
index: 0,
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ValueIdentifiable + ?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: &dyn Any) -> Self {
|
|
Self {
|
|
index: env.get_extern_ref_index::<T>(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: &dyn Any) -> Self {
|
|
Self {
|
|
index: env.data().data().get_extern_ref_index::<T>(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: &dyn Any) -> Self {
|
|
Self {
|
|
index: resolver.environment_data().get_extern_ref_index::<T>(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>(&self, env: &'a FunctionEnvMut<WebAssemblyEnv>) -> Result<&'a T>
|
|
where
|
|
T: Sized + 'static,
|
|
{
|
|
self.value(&env.data().data())?.ok_or(PkmnError::NullReference.into())
|
|
}
|
|
|
|
/// 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
|
|
T: 'static,
|
|
{
|
|
self.value_arc(&env.data().data())?
|
|
.ok_or(PkmnError::NullReference.into())
|
|
}
|
|
|
|
/// 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_box(&self, env: &FunctionEnvMut<WebAssemblyEnv>) -> Result<&Box<T>>
|
|
where
|
|
T: 'static,
|
|
{
|
|
self.value_box(&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>(&self, env: &Arc<WebAssemblyEnvironmentData>) -> Result<Option<&'a T>>
|
|
where
|
|
T: Sized + 'static,
|
|
{
|
|
Ok(env.get_extern_ref_value::<T>(self.index)?.downcast_ref::<T>())
|
|
}
|
|
|
|
/// 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<Option<Arc<T>>>
|
|
where
|
|
T: 'static,
|
|
{
|
|
Ok(env
|
|
.get_extern_ref_value::<T>(self.index)?
|
|
.downcast_ref::<Arc<T>>()
|
|
.cloned())
|
|
}
|
|
|
|
/// 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_box(&self, env: &Arc<WebAssemblyEnvironmentData>) -> Result<&Box<T>>
|
|
where
|
|
T: 'static,
|
|
{
|
|
env.get_extern_ref_value::<T>(self.index)?
|
|
.downcast_ref::<Box<T>>()
|
|
.ok_or(PkmnError::NullReference.into())
|
|
}
|
|
}
|
|
|
|
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 {
|
|
index: self.index,
|
|
size: self.size,
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> Copy for VecExternRef<T> {}
|
|
|
|
impl<T> Default for VecExternRef<T> {
|
|
fn default() -> Self {
|
|
Self {
|
|
index: 0,
|
|
size: 0,
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: 'static> VecExternRef<T> {
|
|
/// Instantiates a new VecExternRef for a given slice.
|
|
pub fn new(env: &WebAssemblyEnvironmentData, value: &Vec<T>) -> Self {
|
|
Self {
|
|
index: env.get_extern_vec_ref_index(value),
|
|
size: value.len() as u32,
|
|
_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
|
|
}
|
|
}
|