use core::ffi::c_char; use std::borrow::Cow; use std::ffi::CString; use std::mem::{align_of, size_of}; use wasmer::wasmparser::Data; use wasmer::{Exports, Function, 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::{DataLibrary, MoveData, MoveLibrary, StaticData}; use crate::StringKey; 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), Function::new_native_with_env($store, $env.clone(), $func), ); }; } 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, move_library_get_move_by_hash, env); register_func_with_env!(exports, store, move_data_get_name, env); register_func_with_env!(exports, store, move_data_get_base_power, env); register_func_with_env!(exports, store, const_string_get_hash, env); register_func_with_env!(exports, store, const_string_get_str, env); register_func_with_env!(exports, store, battle_library_get_data_library, env); register_func_with_env!(exports, store, data_library_get_move_library, env); } fn _print(env: &WebAssemblyEnv, p: u32, len: u32) { unsafe { let mem: *mut u8 = env.resolver().memory().data_ptr().offset(p as isize); let s = String::from_raw_parts(mem, len as usize, len as usize); println!("{}", s); } } fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_len: u32, line: u32, position: u32) { unsafe { let mem: *mut u8 = env.resolver().memory().data_ptr().offset(message as isize); let message = String::from_raw_parts(mem, message_len as usize, message_len as usize); let mem: *mut u8 = env.resolver().memory().data_ptr().offset(file as isize); let file = String::from_raw_parts(mem, file_len as usize, file_len as usize); println!("Error: {} in file {}, line: {}:{}", message, file, line, position); } } fn move_library_get_move_by_hash(env: &WebAssemblyEnv, lib: ExternRef, hash: u32) -> ExternRef { let lib = lib.value(env); let m = lib.get_by_hash(hash); if let Some(v) = m { ExternRef::new(env, v) } else { ExternRef::null() } } fn move_data_get_name(env: &WebAssemblyEnv, move_data: ExternRef) -> ExternRef { let move_data = move_data.value(env); ExternRef::new(env, move_data.name()) } fn move_data_get_base_power(env: &WebAssemblyEnv, move_data: ExternRef) -> u8 { move_data.value(env).base_power() } fn const_string_get_hash(env: &WebAssemblyEnv, string_key: ExternRef) -> u32 { string_key.value(env).hash() } fn const_string_get_str(env: &WebAssemblyEnv, string_key: ExternRef) -> u32 { let string_key = string_key.value(env).str(); let mut s: CString = CString::new(string_key.as_bytes()).unwrap(); let wasm_string_ptr = env .resolver() .allocate_mem(string_key.len() as u32, align_of::() as u32); let mut wasm_string = unsafe { CString::from_raw(wasm_string_ptr.0 as *mut c_char) }; s.clone_into(&mut wasm_string); wasm_string_ptr.1 } fn battle_library_get_data_library( env: &WebAssemblyEnv, dynamic_lib: ExternRef, ) -> ExternRef { ExternRef::new(env, dynamic_lib.value(env).static_data()) } fn data_library_get_move_library(env: &WebAssemblyEnv, data_library: ExternRef) -> ExternRef { ExternRef::new(env, data_library.value(env).moves()) }