2022-07-18 08:16:47 +00:00
|
|
|
use std::ffi::CString;
|
2022-07-18 13:36:03 +00:00
|
|
|
use std::mem::{align_of, forget};
|
2022-07-18 08:16:47 +00:00
|
|
|
|
2022-08-20 10:22:12 +00:00
|
|
|
use wasmer::{Exports, Store};
|
|
|
|
|
2022-07-18 08:16:47 +00:00
|
|
|
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
|
|
|
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
2022-08-26 16:23:35 +00:00
|
|
|
use crate::static_data::EffectParameter;
|
2022-07-18 08:16:47 +00:00
|
|
|
use crate::StringKey;
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Dynamic data registration
|
2022-08-20 10:22:12 +00:00
|
|
|
mod dynamic_data;
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Static data registration
|
2022-08-20 10:22:12 +00:00
|
|
|
mod static_data;
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Register a single function.
|
2022-07-18 13:36:03 +00:00
|
|
|
#[allow(unused_macros)]
|
2022-07-18 08:16:47 +00:00
|
|
|
macro_rules! register_func {
|
|
|
|
($exports: ident, $store: ident, $func: ident) => {
|
|
|
|
$exports.insert(stringify!($func), Function::new_native($store, $func));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Register a single function that requires environment data.
|
2022-07-18 08:16:47 +00:00
|
|
|
macro_rules! register_func_with_env {
|
|
|
|
($exports: ident, $store: ident, $func: ident, $env: expr) => {
|
|
|
|
$exports.insert(
|
|
|
|
stringify!($func),
|
2022-08-20 10:22:12 +00:00
|
|
|
wasmer::Function::new_native_with_env($store, $env.clone(), $func),
|
2022-07-18 08:16:47 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Utility macro to register a bunch of WASM functions easily.
|
2022-08-20 10:22:12 +00:00
|
|
|
macro_rules! register {
|
|
|
|
(
|
|
|
|
$(
|
2022-08-20 11:17:20 +00:00
|
|
|
fn $name:ident($($par:ident: $par_type:ty),*$(,)?) $(-> $return:ty)? $block:block
|
2022-08-20 10:22:12 +00:00
|
|
|
)*
|
2022-08-26 16:23:35 +00:00
|
|
|
$(
|
|
|
|
manual $manual_name:ident
|
|
|
|
)?
|
2022-08-20 10:22:12 +00:00
|
|
|
) => {
|
|
|
|
pub(crate) fn register(exports: &mut crate::script_implementations::wasm::export_registry::Exports,
|
|
|
|
store: &crate::script_implementations::wasm::export_registry::Store,
|
|
|
|
env: crate::script_implementations::wasm::script_resolver::WebAssemblyEnv) {
|
|
|
|
$(
|
|
|
|
|
2022-08-20 11:17:20 +00:00
|
|
|
fn $name(
|
2022-08-20 10:22:12 +00:00
|
|
|
$(
|
|
|
|
$par: $par_type,
|
|
|
|
)*
|
|
|
|
) $(-> $return)* $block
|
|
|
|
crate::script_implementations::wasm::export_registry::register_func_with_env!(exports, store, $name, env);
|
|
|
|
)*
|
2022-08-26 16:23:35 +00:00
|
|
|
$( $manual_name(exports, store, env) )*
|
2022-08-20 10:22:12 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-08-20 11:17:20 +00:00
|
|
|
pub(crate) use register;
|
|
|
|
pub(crate) use register_func_with_env;
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Register the functions we expose to WASM.
|
2022-07-18 08:16:47 +00:00
|
|
|
pub(crate) fn register_webassembly_funcs(exports: &mut Exports, store: &Store, env: WebAssemblyEnv) {
|
|
|
|
register_func_with_env!(exports, store, _print, env);
|
|
|
|
register_func_with_env!(exports, store, _error, env);
|
2022-08-20 10:22:12 +00:00
|
|
|
register_func_with_env!(exports, store, _vec_extern_ref_get_value, env);
|
|
|
|
|
|
|
|
static_data::register(exports, store, env.clone());
|
|
|
|
dynamic_data::register(exports, store, env.clone());
|
|
|
|
|
|
|
|
register_func_with_env!(exports, store, string_key_get_hash, env);
|
|
|
|
register_func_with_env!(exports, store, string_key_get_str, env);
|
|
|
|
register_func_with_env!(exports, store, effect_parameter_get_type, env);
|
|
|
|
register_func_with_env!(exports, store, effect_parameter_as_bool, env);
|
|
|
|
register_func_with_env!(exports, store, effect_parameter_as_int, env);
|
|
|
|
register_func_with_env!(exports, store, effect_parameter_as_float, env);
|
|
|
|
register_func_with_env!(exports, store, effect_parameter_as_string, env);
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Logging function for WASM.
|
2022-07-18 08:16:47 +00:00
|
|
|
fn _print(env: &WebAssemblyEnv, p: u32, len: u32) {
|
|
|
|
unsafe {
|
2022-07-18 13:36:03 +00:00
|
|
|
let mem: *mut u8 = env.data().memory().data_ptr().offset(p as isize);
|
2022-07-18 08:16:47 +00:00
|
|
|
let s = String::from_raw_parts(mem, len as usize, len as usize);
|
|
|
|
println!("{}", s);
|
2022-07-18 13:36:03 +00:00
|
|
|
forget(s);
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Triggers when WASM panics.
|
2022-08-20 10:22:12 +00:00
|
|
|
#[track_caller]
|
2022-07-18 08:16:47 +00:00
|
|
|
fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_len: u32, line: u32, position: u32) {
|
|
|
|
unsafe {
|
2022-07-18 13:36:03 +00:00
|
|
|
let mem: *mut u8 = env.data().memory().data_ptr().offset(message as isize);
|
2022-08-20 10:22:12 +00:00
|
|
|
let message_str = String::from_raw_parts(mem, message_len as usize, message_len as usize);
|
2022-07-18 13:36:03 +00:00
|
|
|
let mem: *mut u8 = env.data().memory().data_ptr().offset(file as isize);
|
2022-08-20 10:22:12 +00:00
|
|
|
let file_str = String::from_raw_parts(mem, file_len as usize, file_len as usize);
|
|
|
|
panic!(
|
|
|
|
"Error: {} in file {}, line: {}:{}",
|
|
|
|
message_str, file_str, line, position
|
|
|
|
);
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Get a single item from an earlier passed VecExternRef
|
2022-08-20 10:22:12 +00:00
|
|
|
fn _vec_extern_ref_get_value(env: &WebAssemblyEnv, reference: u32, index: u32) -> u32 {
|
|
|
|
env.data().get_extern_vec_ref_extern_ref(reference, index)
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Gets the hash value of a StringKey.
|
2022-08-20 10:22:12 +00:00
|
|
|
fn string_key_get_hash(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) -> u32 {
|
2022-07-18 11:18:11 +00:00
|
|
|
string_key.value(env).unwrap().hash()
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Get a null-terminated C string from a StringKey. Note that this involves a copy into WASM
|
|
|
|
/// memory, so this is relatively heavy.
|
2022-08-20 10:22:12 +00:00
|
|
|
fn string_key_get_str(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) -> u32 {
|
2022-07-18 11:18:11 +00:00
|
|
|
let string_key = string_key.value(env).unwrap().str();
|
2022-07-18 08:16:47 +00:00
|
|
|
let wasm_string_ptr = env
|
2022-07-18 13:36:03 +00:00
|
|
|
.data()
|
|
|
|
.allocate_mem((string_key.len() + 1) as u32, align_of::<CString>() as u32);
|
|
|
|
let mut wasm_string: Vec<u8> =
|
|
|
|
unsafe { Vec::from_raw_parts(wasm_string_ptr.0, string_key.len() + 1, string_key.len() + 1) };
|
|
|
|
wasm_string.resize(string_key.len() + 1, 0);
|
|
|
|
string_key.as_bytes().clone_into(&mut wasm_string);
|
2022-08-26 16:23:35 +00:00
|
|
|
wasm_string.insert(string_key.len(), 0_u8);
|
2022-07-18 13:36:03 +00:00
|
|
|
forget(wasm_string);
|
2022-07-18 08:16:47 +00:00
|
|
|
wasm_string_ptr.1
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Gets the type of an EffectParameter
|
2022-08-20 10:22:12 +00:00
|
|
|
fn effect_parameter_get_type(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> u8 {
|
|
|
|
let v = parameter.value(env).unwrap();
|
|
|
|
match v {
|
|
|
|
EffectParameter::Bool(_) => 1,
|
|
|
|
EffectParameter::Int(_) => 2,
|
|
|
|
EffectParameter::Float(_) => 3,
|
|
|
|
EffectParameter::String(_) => 4,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Gets the inner bool data of an EffectParameter. Panics if it's not a bool.
|
2022-08-20 10:22:12 +00:00
|
|
|
fn effect_parameter_as_bool(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> u8 {
|
|
|
|
let v = parameter.value(env).unwrap();
|
|
|
|
match v {
|
|
|
|
EffectParameter::Bool(b) => {
|
|
|
|
if *b {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => panic!("Unexpected parameter type!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Gets the inner int data of an EffectParameter. Panics if it's not an int.
|
2022-08-20 10:22:12 +00:00
|
|
|
fn effect_parameter_as_int(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> i64 {
|
|
|
|
let v = parameter.value(env).unwrap();
|
|
|
|
match v {
|
|
|
|
EffectParameter::Int(i) => *i,
|
|
|
|
_ => panic!("Unexpected parameter type!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Gets the inner float data of an EffectParameter. Panics if it's not a float.
|
2022-08-20 10:22:12 +00:00
|
|
|
fn effect_parameter_as_float(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> f32 {
|
|
|
|
let v = parameter.value(env).unwrap();
|
|
|
|
match v {
|
|
|
|
EffectParameter::Float(f) => *f,
|
|
|
|
_ => panic!("Unexpected parameter type!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
/// Gets the inner string data of an EffectParameter. Panics if it's not a string.
|
2022-08-20 10:22:12 +00:00
|
|
|
fn effect_parameter_as_string(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> ExternRef<StringKey> {
|
|
|
|
let v = parameter.value(env).unwrap();
|
|
|
|
match v {
|
|
|
|
EffectParameter::String(s) => ExternRef::new(env.data().as_ref(), s),
|
|
|
|
_ => panic!("Unexpected parameter type!"),
|
|
|
|
}
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|