PkmnLib_rs/src/script_implementations/wasm/export_registry/wasm_result.rs

142 lines
4.4 KiB
Rust

use crate::script_implementations::wasm::script_resolver::{WebAssemblyEnv, WebAssemblyEnvironmentData};
use anyhow::Error;
use std::ffi::{c_char, CString};
use std::sync::Arc;
use wasmer::{FromToNativeWasmType, FunctionEnvMut};
/// A result type that can be given to, or returned from WASM.
pub type WasmResult<T> = (u32, T);
/// A result type that can be given to, or returned from WASM, but does not contain a value.
pub type WasmVoidResult = u32;
pub(crate) trait WasmVoidResultExtension {
fn into_result(self, env: FunctionEnvMut<WebAssemblyEnv>) -> anyhow_ext::Result<()>;
fn into_result_env(self, env: &Arc<WebAssemblyEnvironmentData>) -> anyhow_ext::Result<()>;
fn from_result(res: anyhow_ext::Result<()>, env: &FunctionEnvMut<WebAssemblyEnv>) -> Self;
fn ok() -> Self;
fn err(err: anyhow::Error, env: &FunctionEnvMut<WebAssemblyEnv>) -> Self;
}
pub(super) fn wasm_ok<T>(value: T) -> WasmResult<T>
where
T: FromToNativeWasmType,
<T as FromToNativeWasmType>::Native: Default,
{
(0, value)
}
pub(super) fn wasm_err<T>(err: Error, env: &FunctionEnvMut<WebAssemblyEnv>) -> WasmResult<T>
where
T: FromToNativeWasmType + Default,
{
let s = CString::new(err.to_string()).unwrap();
let ptr = env.data().data().copy_value_vec_to_wasm(s.as_bytes()).unwrap();
(ptr, <T as Default>::default())
}
impl WasmVoidResultExtension for WasmVoidResult {
fn into_result(self, env: FunctionEnvMut<WebAssemblyEnv>) -> anyhow::Result<()> {
Self::into_result_env(self, &env.data().data())
}
fn into_result_env(self, env: &Arc<WebAssemblyEnvironmentData>) -> anyhow::Result<()> {
if self == 0 {
Ok(())
} else {
unsafe {
let ptr = self;
let mem: *mut c_char = env.get_raw_pointer(ptr as u32);
let string = std::ffi::CStr::from_ptr(mem);
let e = anyhow_ext::anyhow!("{}", string.to_str().unwrap());
env.script_function_cache().dealloc_cstring(&env, ptr as u32).unwrap();
Err(e)
}
}
}
fn from_result(res: anyhow::Result<()>, env: &FunctionEnvMut<WebAssemblyEnv>) -> Self {
match res {
Ok(_) => 0,
Err(e) => {
let s = CString::new(e.to_string()).unwrap();
let ptr = env.data().data().copy_value_vec_to_wasm(s.as_bytes()).unwrap();
ptr as u32
}
}
}
fn ok() -> Self {
0
}
fn err(err: Error, env: &FunctionEnvMut<WebAssemblyEnv>) -> Self {
let s = CString::new(err.to_string()).unwrap();
let ptr = env.data().data().copy_value_vec_to_wasm(s.as_bytes()).unwrap();
ptr as u32
}
}
macro_rules! try_wasm {
($e:expr, $env:expr) => {
match $e.with_context(|| format!("WASM function {}", stdext::function_name!())) {
Ok(v) => v,
Err(e) => {
return crate::script_implementations::wasm::export_registry::wasm_err(e.into(), &$env);
}
}
};
}
macro_rules! try_wasm_void {
($e:expr, $env:expr) => {
match $e.with_context(|| format!("WASM function {}", stdext::function_name!())) {
Ok(v) => v,
Err(e) => {
return WasmVoidResult::from_result(Err(e.into()), &$env);
}
}
};
}
pub(super) use try_wasm;
pub(super) use try_wasm_void;
macro_rules! get_value {
($e:expr, $env:expr) => {
crate::script_implementations::wasm::export_registry::try_wasm!($e.value_func(&$env), $env)
};
}
macro_rules! get_value_arc {
($e:expr, $env:expr) => {
crate::script_implementations::wasm::export_registry::try_wasm!($e.value_func_arc(&$env), $env)
};
}
macro_rules! get_value_void {
($e:expr, $env:expr) => {
crate::script_implementations::wasm::export_registry::try_wasm_void!($e.value_func(&$env), $env)
};
}
macro_rules! get_value_arc_void {
($e:expr, $env:expr) => {
crate::script_implementations::wasm::export_registry::try_wasm_void!($e.value_func_arc(&$env), $env)
};
}
pub(super) use get_value;
pub(super) use get_value_arc;
pub(super) use get_value_arc_void;
pub(super) use get_value_void;
macro_rules! get_value_call_getter {
($e:ident.$func:ident(), $env:expr) => {{
let _value = crate::script_implementations::wasm::export_registry::try_wasm!($e.value_func(&$env), $env);
_value.$func()
}};
}
pub(super) use get_value_call_getter;