use std::ffi::CString; use std::mem::{align_of, forget}; use wasmer::{Exports, Store}; use crate::dynamic_data::DynamicLibrary; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::{EffectParameter, StaticData}; use crate::StringKey; mod dynamic_data; mod static_data; #[allow(unused_macros)] macro_rules! register_func { ($exports: ident, $store: ident, $func: ident) => { $exports.insert(stringify!($func), Function::new_native($store, $func)); }; } macro_rules! register_func_with_env { ($exports: ident, $store: ident, $func: ident, $env: expr) => { $exports.insert( stringify!($func), wasmer::Function::new_native_with_env($store, $env.clone(), $func), ); }; } macro_rules! register { ( $( fn $name:ident($($par:ident: $par_type:ty),*$(,)?) $(-> $return:ty)? $block:block )* ) => { 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) { $( fn $name( $( $par: $par_type, )* ) $(-> $return)* $block crate::script_implementations::wasm::export_registry::register_func_with_env!(exports, store, $name, env); )* } }; } pub(crate) use register; pub(crate) use register_func_with_env; 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); 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, dynamic_library_get_static_data, 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); } fn _print(env: &WebAssemblyEnv, p: u32, len: u32) { unsafe { let mem: *mut u8 = env.data().memory().data_ptr().offset(p as isize); let s = String::from_raw_parts(mem, len as usize, len as usize); println!("{}", s); forget(s); } } #[track_caller] fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_len: u32, line: u32, position: u32) { unsafe { let mem: *mut u8 = env.data().memory().data_ptr().offset(message as isize); let message_str = String::from_raw_parts(mem, message_len as usize, message_len as usize); let mem: *mut u8 = env.data().memory().data_ptr().offset(file as isize); 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 ); } } fn _vec_extern_ref_get_value(env: &WebAssemblyEnv, reference: u32, index: u32) -> u32 { env.data().get_extern_vec_ref_extern_ref(reference, index) } fn string_key_get_hash(env: &WebAssemblyEnv, string_key: ExternRef) -> u32 { string_key.value(env).unwrap().hash() } fn string_key_get_str(env: &WebAssemblyEnv, string_key: ExternRef) -> u32 { let string_key = string_key.value(env).unwrap().str(); let wasm_string_ptr = env .data() .allocate_mem((string_key.len() + 1) as u32, align_of::() as u32); let mut wasm_string: Vec = 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); wasm_string.insert(string_key.len(), 0 as u8); forget(wasm_string); wasm_string_ptr.1 } fn dynamic_library_get_static_data( env: &WebAssemblyEnv, dynamic_lib: ExternRef, ) -> ExternRef { ExternRef::new(env.data().as_ref(), dynamic_lib.value(env).unwrap().static_data()) } fn effect_parameter_get_type(env: &WebAssemblyEnv, parameter: ExternRef) -> u8 { let v = parameter.value(env).unwrap(); match v { EffectParameter::Bool(_) => 1, EffectParameter::Int(_) => 2, EffectParameter::Float(_) => 3, EffectParameter::String(_) => 4, } } fn effect_parameter_as_bool(env: &WebAssemblyEnv, parameter: ExternRef) -> u8 { let v = parameter.value(env).unwrap(); match v { EffectParameter::Bool(b) => { if *b { 1 } else { 0 } } _ => panic!("Unexpected parameter type!"), } } fn effect_parameter_as_int(env: &WebAssemblyEnv, parameter: ExternRef) -> i64 { let v = parameter.value(env).unwrap(); match v { EffectParameter::Int(i) => *i, _ => panic!("Unexpected parameter type!"), } } fn effect_parameter_as_float(env: &WebAssemblyEnv, parameter: ExternRef) -> f32 { let v = parameter.value(env).unwrap(); match v { EffectParameter::Float(f) => *f, _ => panic!("Unexpected parameter type!"), } } fn effect_parameter_as_string(env: &WebAssemblyEnv, parameter: ExternRef) -> ExternRef { let v = parameter.value(env).unwrap(); match v { EffectParameter::String(s) => ExternRef::new(env.data().as_ref(), s), _ => panic!("Unexpected parameter type!"), } }