diff --git a/src/dynamic_data/script_handling/script.rs b/src/dynamic_data/script_handling/script.rs index 3890cdd..2f2a7b7 100755 --- a/src/dynamic_data/script_handling/script.rs +++ b/src/dynamic_data/script_handling/script.rs @@ -573,6 +573,11 @@ impl ScriptContainer { &self.script } + /// Whether or not the script is set. + pub fn is_any(&self) -> bool { + self.script.read().is_some() + } + /// Get the underlying script as the downcasted value. pub fn get_as(&self) -> Result> { let r = RwLockReadGuard::try_map(self.script.read(), |a| unsafe { diff --git a/src/ffi/dynamic_data/libraries/script_resolver.rs b/src/ffi/dynamic_data/libraries/script_resolver.rs index b40968b..5d1fc32 100644 --- a/src/ffi/dynamic_data/libraries/script_resolver.rs +++ b/src/ffi/dynamic_data/libraries/script_resolver.rs @@ -23,7 +23,7 @@ extern "C" fn script_resolver_drop(ptr: OwnedPtr>) { #[cfg(feature = "wasm")] mod web_assembly_script_resolver { use crate::dynamic_data::ScriptResolver; - use crate::ffi::{ExternPointer, IdentifiablePointer}; + use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver; /// Instantiates a new WebAssemblyScriptResolver. @@ -41,13 +41,19 @@ mod web_assembly_script_resolver { mut ptr: ExternPointer>, arr: *const u8, len: usize, - ) { - unsafe { ptr.as_mut().load_wasm_from_bytes(std::slice::from_raw_parts(arr, len)) } + ) -> NativeResult<()> { + unsafe { + ptr.as_mut() + .load_wasm_from_bytes(std::slice::from_raw_parts(arr, len)) + .into() + } } /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. #[no_mangle] - extern "C" fn webassembly_script_resolver_finalize(mut ptr: ExternPointer>) { - ptr.as_mut().finalize(); + extern "C" fn webassembly_script_resolver_finalize( + mut ptr: ExternPointer>, + ) -> NativeResult<()> { + ptr.as_mut().finalize().into() } } diff --git a/src/lib.rs b/src/lib.rs index 6a43893..2898c70 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ #![feature(unboxed_closures)] #![feature(trait_upcasting)] #![feature(lazy_cell)] +#![feature(try_trait_v2)] //! PkmnLib //! PkmnLib is a full featured implementation of Pokemon. while currently focused on implementing diff --git a/src/script_implementations/mod.rs b/src/script_implementations/mod.rs index 36f74fa..dfcd6ab 100755 --- a/src/script_implementations/mod.rs +++ b/src/script_implementations/mod.rs @@ -1,10 +1,3 @@ /// The WASM module handles loading dynamic scripts through WebAssembly. #[cfg(feature = "wasm")] -// FIXME: allow these for now until we have a good result interface defined. -#[allow(clippy::unwrap_used)] -#[allow(clippy::expect_used)] -#[allow(clippy::indexing_slicing)] -#[allow(clippy::string_slice)] -#[allow(clippy::exit)] -#[allow(clippy::panic)] pub mod wasm; diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs b/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs index 3f923fc..5905cb8 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs @@ -1,7 +1,7 @@ use crate::dynamic_data::{ Battle, BattleParty, BattleRandom, BattleResult, BattleSide, ChoiceQueue, DynamicLibrary, Pokemon, PokemonParty, }; -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::StringKey; @@ -11,141 +11,141 @@ register! { fn battle_get_pokemon_per_side( env: FunctionEnvMut, battle: ExternRef, - ) -> u8 { - battle.value_func(&env).unwrap().pokemon_per_side() + ) -> WasmResult { + Ok(battle.value_func(&env)?.pokemon_per_side()).into() } fn battle_get_parties( env: FunctionEnvMut, battle: ExternRef, - ) -> VecExternRef { - VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env).unwrap().parties()) + ) -> WasmResult> { + Ok(VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env)?.parties())).into() } fn battle_get_choice_queue( env: FunctionEnvMut, battle: ExternRef, - ) -> ExternRef { - let queue = battle.value_func(&env).unwrap().current_turn_queue().read(); - if let Some(queue) = queue.as_ref() { + ) -> WasmResult> { + let queue = battle.value_func(&env)?.current_turn_queue().read(); + Ok(if let Some(queue) = queue.as_ref() { ExternRef::func_new(&env, queue) } else { ExternRef::null() - } + }).into() } fn battle_get_library( env: FunctionEnvMut, battle: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, &battle.value_func_arc(&env).unwrap().library().clone()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, &battle.value_func(&env)?.library().clone())).into() } fn battle_get_sides( env: FunctionEnvMut, battle: ExternRef, - ) -> VecExternRef { - VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env).unwrap().sides()) + ) -> WasmResult> { + Ok(VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env)?.sides())).into() } fn battle_get_random( env: FunctionEnvMut, battle: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, battle.value_func(&env).unwrap().random()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, battle.value_func(&env)?.random())).into() } fn battle_get_weather_name( env: FunctionEnvMut, battle: ExternRef, - ) -> ExternRef { - let weather = battle.value_func(&env).unwrap().weather_name().unwrap(); - if let Some(weather) = weather { + ) -> WasmResult> { + let weather = battle.value_func(&env)?.weather_name()?; + Ok(if let Some(weather) = weather { ExternRef::func_new(&env, &weather) } else { ExternRef::null() - } + }).into() } fn battle_find_party_for_pokemon( env: FunctionEnvMut, battle: ExternRef, pokemon: ExternRef - ) -> ExternRef { - let battle = battle.value_func(&env).unwrap(); - let pokemon = pokemon.value_func(&env).unwrap(); + ) -> WasmResult> { + let battle = battle.value_func(&env)?; + let pokemon = pokemon.value_func(&env)?; for party in battle.parties() { if party.party().has_pokemon(pokemon) { - return ExternRef::func_new(&env, party); + return Ok(ExternRef::func_new(&env, party)).into(); } } - ExternRef::null() + Ok(ExternRef::null()).into() } fn battle_get_pokemon( env: FunctionEnvMut, battle: ExternRef, side: u8, index: u8 - ) -> ExternRef { - let battle = battle.value_func(&env).unwrap(); + ) -> WasmResult> { + let battle = battle.value_func(&env)?; let pokemon = battle.get_pokemon(side, index); - if let Some(pokemon) = pokemon { + Ok(if let Some(pokemon) = pokemon { ExternRef::func_new(&env, &pokemon) } else { ExternRef::null() - } + }).into() } fn battle_get_can_flee( env: FunctionEnvMut, battle: ExternRef, - ) -> u8 { - if battle.value_func(&env).unwrap().can_flee() { 1 } else { 0 } + ) -> WasmResult { + Ok(if battle.value_func(&env)?.can_flee() { 1 } else { 0 }).into() } fn battle_get_number_of_sides( env: FunctionEnvMut, battle: ExternRef, - ) -> u8 { - battle.value_func(&env).unwrap().number_of_sides() + ) -> WasmResult { + Ok(battle.value_func(&env)?.number_of_sides()).into() } fn battle_get_has_ended( env: FunctionEnvMut, battle: ExternRef, - ) -> u8 { - if battle.value_func(&env).unwrap().has_ended() { 1 } else { 0 } + ) -> WasmResult { + Ok(if battle.value_func(&env)?.has_ended() { 1 } else { 0 }).into() } fn battle_get_has_ended_conclusively( env: FunctionEnvMut, battle: ExternRef, - ) -> u8 { - if battle.value_func(&env).unwrap().result().is_conclusive() { 1 } else { 0 } + ) -> WasmResult { + Ok(if battle.value_func(&env)?.result().is_conclusive() { 1 } else { 0 }).into() } fn battle_get_winning_side( env: FunctionEnvMut, battle: ExternRef, - ) -> u8 { - if let BattleResult::Conclusive(result) = battle.value_func(&env).unwrap().result() { + ) -> WasmResult { + Ok(if let BattleResult::Conclusive(result) = battle.value_func(&env)?.result() { result } else { 0 - } + }).into() } fn battle_get_current_turn( env: FunctionEnvMut, battle: ExternRef, - ) -> u32 { - battle.value_func(&env).unwrap().current_turn() + ) -> WasmResult { + Ok(battle.value_func(&env)?.current_turn()).into() } fn battle_party_get_party( env: FunctionEnvMut, battle_party: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, battle_party.value_func(&env).unwrap().party().as_ref()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, battle_party.value_func(&env)?.party().as_ref())).into() } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs b/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs index 477c692..077dd7c 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs @@ -1,5 +1,5 @@ use crate::dynamic_data::BattleRandom; -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use wasmer::FunctionEnvMut; @@ -9,22 +9,22 @@ register! { fn battle_random_get( env: FunctionEnvMut, battle_random: ExternRef, - ) -> i32 { - battle_random.value_func(&env).unwrap().get().unwrap() + ) -> WasmResult { + battle_random.value_func(&env)?.get().into() } fn battle_random_get_max( env: FunctionEnvMut, battle_random: ExternRef, max: i32 - ) -> i32 { - battle_random.value_func(&env).unwrap().get_max(max).unwrap() + ) -> WasmResult { + battle_random.value_func(&env)?.get_max(max).into() } fn battle_random_get_between( env: FunctionEnvMut, battle_random: ExternRef, min: i32, max: i32 - ) -> i32 { - battle_random.value_func(&env).unwrap().get_between(min, max).unwrap() + ) -> WasmResult { + battle_random.value_func(&env)?.get_between(min, max).into() } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs b/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs index c52fc1b..7e90ab3 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs @@ -1,9 +1,10 @@ use crate::dynamic_data::{Battle, BattleSide, Pokemon, VolatileScriptsOwner}; -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::ScriptCategory; +use anyhow::anyhow; use std::ffi::CStr; use wasmer::FunctionEnvMut; @@ -11,78 +12,78 @@ register! { fn battleside_has_fled_battle( env: FunctionEnvMut, side: ExternRef, - ) -> u8 { - u8::from(side.value_func(&env).unwrap().has_fled_battle()) + ) -> WasmResult { + Ok(u8::from(side.value_func(&env)?.has_fled_battle())).into() } fn battleside_is_defeated( env: FunctionEnvMut, side: ExternRef, - ) -> u8 { - u8::from(side.value_func(&env).unwrap().is_defeated()) + ) -> WasmResult { + Ok(u8::from(side.value_func(&env)?.is_defeated())).into() } fn battleside_get_side_index( env: FunctionEnvMut, side: ExternRef, - ) -> u8 { - side.value_func(&env).unwrap().index() + ) -> WasmResult { + Ok(side.value_func(&env)?.index()).into() } fn battleside_get_pokemon_per_side( env: FunctionEnvMut, side: ExternRef, - ) -> u8 { - side.value_func(&env).unwrap().pokemon_per_side() + ) -> WasmResult { + Ok(side.value_func(&env)?.pokemon_per_side()).into() } fn battleside_get_battle( env: FunctionEnvMut, side: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, side.value_func(&env).unwrap().battle().unwrap()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, side.value_func(&env)?.battle()?)).into() } fn battleside_get_pokemon( env: FunctionEnvMut, side: ExternRef, index: u32 - ) -> ExternRef { - if let Some(Some(p)) = side.value_func(&env).unwrap().pokemon().get(index as usize) { + ) -> WasmResult> { + Ok(if let Some(Some(p)) = side.value_func(&env)?.pokemon().get(index as usize) { ExternRef::func_new(&env, p.as_ref()) } else { ExternRef::null() - } + }).into() } fn battle_side_get_has_fled_battle( env: FunctionEnvMut, side: ExternRef, - ) -> u8 { - if side.value_func(&env).unwrap().has_fled_battle() { 1 } else { 0 } + ) -> WasmResult { + Ok(if side.value_func(&env)?.has_fled_battle() { 1 } else { 0 }).into() } fn battle_side_get_is_defeated( env: FunctionEnvMut, side: ExternRef, - ) -> u8 { - if side.value_func(&env).unwrap().is_defeated() { 1 } else { 0 } + ) -> WasmResult { + Ok(if side.value_func(&env)?.is_defeated() { 1 } else { 0 }).into() } fn battleside_add_volatile_by_name( env: FunctionEnvMut, side: ExternRef, name_ptr: u32 - ) -> u32 { + ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - let script = side.value_func(&env).unwrap().add_volatile_script(&c_name.as_ref().into()).unwrap(); - if let Some(script) = script { - let script = script.get_as::().unwrap(); + let script = side.value_func(&env)?.add_volatile_script(&c_name.as_ref().into())?; + Ok(if let Some(script) = script { + let script = script.get_as::()?; script.get_wasm_pointer() } else { 0 - } + }).into() } } @@ -90,22 +91,28 @@ register! { env: FunctionEnvMut, side: ExternRef, script_ptr: u32 - ) -> u32 { - let side : &BattleSide = side.value_func(&env).unwrap(); - unsafe{ + ) -> WasmResult { + let side : &BattleSide = side.value_func(&env)?; + unsafe { let env = env.data().data(); - let name_ptr = env.script_function_cache().script_get_name(&env).unwrap().call(&mut env.store_mut(), script_ptr).unwrap(); + let name_ptr = match env + .script_function_cache() + .script_get_name(&env)? + .call(&mut env.store_mut(), script_ptr) { + Ok(name_ptr) => Ok(name_ptr), + Err(e) => Err(e.into()) + }?; let c_name: &CStr = CStr::from_ptr(env.get_raw_pointer(name_ptr)); - let script = env.setup_script(script_ptr, ScriptCategory::Side, &c_name.as_ref().into(), side.into()).unwrap(); - env.script_function_cache().dealloc_cstring(&env).unwrap().call(&mut env.store_mut(), name_ptr).unwrap(); + let script = env.setup_script(script_ptr, ScriptCategory::Side, &c_name.as_ref().into(), side.into())?; + env.script_function_cache().dealloc_cstring(&env, name_ptr)?; - if let Some(script) = script { - let script = side.add_volatile_script_with_script(script); - let s = script.as_ref().unwrap().as_ref().unwrap().get_as::().unwrap(); + Ok(if let Some(script) = script { + let script = side.add_volatile_script_with_script(script)?; + let s = script.as_ref().ok_or(anyhow!("Couldn't get script"))?.get_as::()?; s.get_wasm_pointer() } else { 0 - } + }).into() } } @@ -113,10 +120,10 @@ register! { env: FunctionEnvMut, side: ExternRef, name_ptr: u32 - ) -> u8 { + ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - u8::from(side.value_func(&env).unwrap().has_volatile_script(&c_name.as_ref().into())) + Ok(u8::from(side.value_func(&env)?.has_volatile_script(&c_name.as_ref().into()))).into() } } @@ -124,16 +131,16 @@ register! { env: FunctionEnvMut, side: ExternRef, name_ptr: u32 - ) -> u32 { + ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - let script = side.value_func(&env).unwrap().get_volatile_script(&c_name.as_ref().into()); - if let Some(script) = script { - let script = script.get_as::().unwrap(); + let script = side.value_func(&env)?.get_volatile_script(&c_name.as_ref().into()); + Ok(if let Some(script) = script { + let script = script.get_as::()?; script.get_wasm_pointer() } else { 0 - } + }).into() } } @@ -141,10 +148,10 @@ register! { env: FunctionEnvMut, side: ExternRef, name_ptr: u32 - ) { + ) -> WasmResult<()> { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - side.value_func(&env).unwrap().remove_volatile_script(&c_name.as_ref().into()).unwrap(); + side.value_func(&env)?.remove_volatile_script(&c_name.as_ref().into()).into() } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs b/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs index 55c5e6b..c1f8c56 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs @@ -1,5 +1,5 @@ use crate::dynamic_data::{ChoiceQueue, Pokemon}; -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use wasmer::FunctionEnvMut; @@ -9,7 +9,7 @@ register! { env: FunctionEnvMut, battle_random: ExternRef, pokemon: ExternRef - ) -> u8 { - u8::from(battle_random.value_func(&env).unwrap().move_pokemon_choice_next(pokemon.value_func(&env).unwrap()).unwrap()) + ) -> WasmResult { + Ok(u8::from(battle_random.value_func(&env)?.move_pokemon_choice_next(pokemon.value_func(&env)?)?)).into() } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs b/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs index 37d4a8a..6b59213 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs @@ -1,5 +1,5 @@ use crate::dynamic_data::{ExecutingMove, HitData, LearnedMove, Pokemon}; -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; @@ -10,29 +10,29 @@ register! { fn executing_move_get_user( env: FunctionEnvMut, executing_move: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().user().as_ref()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, executing_move.value_func(&env)?.user().as_ref())).into() } fn executing_move_get_use_move( env: FunctionEnvMut, executing_move: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().use_move()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, executing_move.value_func(&env)?.use_move())).into() } fn executing_move_get_chosen_move( env: FunctionEnvMut, executing_move: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, executing_move.value_func_arc(&env).unwrap().chosen_move().as_ref()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, executing_move.value_func(&env)?.chosen_move().as_ref())).into() } fn executing_move_get_number_of_hits( env: FunctionEnvMut, executing_move: ExternRef, - ) -> u8 { - executing_move.value_func(&env).unwrap().number_of_hits() + ) -> WasmResult { + Ok(executing_move.value_func(&env)?.number_of_hits()).into() } fn executing_move_get_hit_data( @@ -40,24 +40,24 @@ register! { executing_move: ExternRef, target: ExternRef, hit: u8 - ) -> ExternRef { - ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().get_hit_data(target.value_func(&env).unwrap(), hit).unwrap()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, executing_move.value_func(&env)?.get_hit_data(target.value_func(&env)?, hit)?)).into() } fn executing_move_get_number_of_targets( env: FunctionEnvMut, executing_move: ExternRef, - ) -> u32 { - executing_move.value_func(&env).unwrap().target_count() as u32 + ) -> WasmResult { + Ok(executing_move.value_func(&env)?.target_count() as u32).into() } fn executing_move_is_pokemon_target( env: FunctionEnvMut, executing_move: ExternRef, pokemon: ExternRef - ) -> u8 { - let pokemon = pokemon.value_func_arc(&env).unwrap(); - if executing_move.value_func(&env).unwrap().is_pokemon_target(&pokemon) { 1 } else { 0 } + ) -> WasmResult { + let pokemon = pokemon.value_func_arc(&env)?; + Ok(if executing_move.value_func(&env)?.is_pokemon_target(&pokemon) { 1 } else { 0 }).into() } @@ -65,16 +65,14 @@ register! { fn executing_move_get_script( env: FunctionEnvMut, executing_move: ExternRef, - ) -> (u32 , u32) { - let executing_move = executing_move.value_func(&env).unwrap(); - if let Some(script) = executing_move.script().get() { - let read_lock = script.read(); - if let Some(script) = read_lock.as_ref() { - let s = script.as_any().downcast_ref::().unwrap().get_wasm_pointer(); - return (s, s + 4) - } + ) -> WasmResult<(u32 , u32)> { + let executing_move = executing_move.value_func(&env)?; + let script = executing_move.script(); + if script.is_any() { + let s = script.get_as::()?.get_wasm_pointer(); + return Ok((s, s + 4)).into() } - (0, 0) + Ok((0, 0)).into() } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs index 47e153d..6f069b1 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs @@ -2,13 +2,14 @@ use std::mem::transmute; use crate::defines::LevelInt; use crate::dynamic_data::{Battle, DynamicLibrary, LearnedMove, Pokemon, VolatileScriptsOwner}; -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::{Ability, ClampedStatisticSet, Form, Nature, Species}; use crate::static_data::{Item, StatisticSet}; -use crate::ScriptCategory; +use crate::{ScriptCategory, VecExt}; +use anyhow::anyhow; use std::ffi::{c_char, CStr, CString}; use wasmer::FunctionEnvMut; @@ -16,88 +17,89 @@ register! { fn pokemon_get_library( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - let lib = pokemon.value_func(&env).unwrap().library().clone(); - ExternRef::func_new(&env, &lib) + ) -> WasmResult> { + let lib = pokemon.value_func(&env)?.library().clone(); + Ok(ExternRef::func_new(&env, &lib)).into() } fn pokemon_get_boosted_stats( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef> { - let statistic_set = pokemon.value_func(&env).unwrap().boosted_stats(); - ExternRef::func_new(&env, statistic_set) + ) -> WasmResult>> { + let statistic_set = pokemon.value_func(&env)?.boosted_stats(); + Ok(ExternRef::func_new(&env, statistic_set)).into() } fn pokemon_get_flat_stats( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef> { - let statistic_set = pokemon.value_func(&env).unwrap().flat_stats(); - ExternRef::func_new(&env, statistic_set) + ) -> WasmResult>> { + let statistic_set = pokemon.value_func(&env)?.flat_stats(); + Ok(ExternRef::func_new(&env, statistic_set)).into() } fn pokemon_get_stat_boosts( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef> { - let statistic_set = pokemon.value_func(&env).unwrap().stat_boosts(); - ExternRef::func_new(&env, statistic_set) + ) -> WasmResult>> { + let statistic_set = pokemon.value_func(&env)?.stat_boosts(); + Ok(ExternRef::func_new(&env, statistic_set)).into() } fn pokemon_get_individual_values( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef> { - let statistic_set = pokemon.value_func(&env).unwrap().individual_values(); - ExternRef::func_new(&env, statistic_set) + ) -> WasmResult>> { + let statistic_set = pokemon.value_func(&env)?.individual_values(); + Ok(ExternRef::func_new(&env, statistic_set)).into() } fn pokemon_get_effort_values( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef> { - let statistic_set = pokemon.value_func(&env).unwrap().effort_values(); - ExternRef::func_new(&env, statistic_set) + ) -> WasmResult>> { + let statistic_set = pokemon.value_func(&env)?.effort_values(); + Ok(ExternRef::func_new(&env, statistic_set)).into() } fn pokemon_get_species( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - let species = pokemon.value_func(&env).unwrap().species(); - ExternRef::func_new(&env, &species) + ) -> WasmResult> { + let species = pokemon.value_func(&env)?.species(); + Ok(ExternRef::func_new(&env, &species)).into() } fn pokemon_get_weight( env: FunctionEnvMut, pokemon: ExternRef, - ) -> f32 { - pokemon.value_func(&env).unwrap().weight() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.weight()).into() } fn pokemon_set_weight( env: FunctionEnvMut, pokemon: ExternRef, weight: f32, - ) { - pokemon.value_func(&env).unwrap().set_weight(weight) + ) -> WasmResult<()> { + pokemon.value_func(&env)?.set_weight(weight); + Ok(()).into() } fn pokemon_get_height( env: FunctionEnvMut, pokemon: ExternRef, - ) -> f32 { - pokemon.value_func(&env).unwrap().height() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.height()).into() } fn pokemon_get_gender( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { + ) -> WasmResult { unsafe { - transmute(pokemon.value_func(&env).unwrap().gender()) + Ok(transmute(pokemon.value_func(&env)?.gender())).into() } } @@ -106,9 +108,10 @@ register! { pokemon: ExternRef, damage: u32, source: u8 - ) { + ) -> WasmResult<()> { unsafe{ - pokemon.value_func(&env).unwrap().damage(damage, transmute(source)).unwrap(); + pokemon.value_func(&env)?.damage(damage, transmute(source))?; + WasmResult::ok(()) } } @@ -116,15 +119,15 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, index: u32 - ) -> ExternRef { - let read_lock = pokemon.value_func(&env).unwrap().learned_moves().read(); + ) -> WasmResult> { + let read_lock = pokemon.value_func(&env)?.learned_moves().read(); let mv = read_lock.get(index as usize); - if let Some(Some(mv)) = mv { + Ok(if let Some(Some(mv)) = mv { ExternRef::func_new(&env, mv) } else{ ExternRef::null() - } + }).into() } fn pokemon_change_stat_boost( @@ -133,65 +136,65 @@ register! { stat: u8, amount: i8, self_inflicted: u8 - ) -> u8 { + ) -> WasmResult { unsafe{ - u8::from(pokemon.value_func(&env).unwrap().change_stat_boost(transmute(stat), amount, self_inflicted == 1).unwrap()) + Ok(u8::from(pokemon.value_func(&env)?.change_stat_boost(transmute(stat), amount, self_inflicted == 1)?)).into() } } fn pokemon_get_battle( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - if let Some(battle) = pokemon.value_func(&env).unwrap().get_battle() { + ) -> WasmResult> { + Ok(if let Some(battle) = pokemon.value_func(&env)?.get_battle() { ExternRef::func_new(&env, battle) } else { ExternRef::null() - } + }).into() } fn pokemon_get_battle_index( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - if let Some(i) = pokemon.value_func(&env).unwrap().get_battle_index() { + ) -> WasmResult { + Ok(if let Some(i) = pokemon.value_func(&env)?.get_battle_index() { i } else { 255 - } + }).into() } fn pokemon_get_battle_side_index( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - if let Some(i) = pokemon.value_func(&env).unwrap().get_battle_side_index() { + ) -> WasmResult { + Ok(if let Some(i) = pokemon.value_func(&env)?.get_battle_side_index() { i } else { 255 - } + }).into() } fn pokemon_get_held_item( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - let read_lock = pokemon.value_func(&env).unwrap().held_item().read(); - if let Some(item) = read_lock.as_ref() { + ) -> WasmResult> { + let read_lock = pokemon.value_func(&env)?.held_item().read(); + Ok(if let Some(item) = read_lock.as_ref() { ExternRef::func_new(&env, item.as_ref()) } else { ExternRef::null() - } + }).into() } fn pokemon_has_held_item( env: FunctionEnvMut, pokemon: ExternRef, name: u32 - ) -> u8 { + ) -> WasmResult { let name : *mut c_char = env.data().data().get_raw_pointer(name); let name = unsafe { CStr::from_ptr(name) }; - u8::from(pokemon.value_func(&env).unwrap().has_held_item(&name.into())) + Ok(u8::from(pokemon.value_func(&env)?.has_held_item(&name.into()))).into() } fn pokemon_heal( @@ -199,51 +202,52 @@ register! { pokemon: ExternRef, amount: u32, allow_revive: u8 - ) -> u8 { - u8::from(pokemon.value_func(&env).unwrap().heal(amount, allow_revive == 1)) + ) -> WasmResult { + Ok(u8::from(pokemon.value_func(&env)?.heal(amount, allow_revive == 1))).into() } fn pokemon_clear_status( env: FunctionEnvMut, pokemon: ExternRef, - ) { - pokemon.value_func(&env).unwrap().clear_status() + ) -> WasmResult<()> { + pokemon.value_func(&env)?.clear_status(); + WasmResult::ok(()) } fn pokemon_get_active_ability( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, &pokemon.value_func(&env).unwrap().active_ability()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, &pokemon.value_func(&env)?.active_ability())).into() } fn pokemon_get_real_ability( env: FunctionEnvMut, pokemon: ExternRef, - ) -> (u8, u8) { - let index = &pokemon.value_func(&env).unwrap().real_ability(); - (if index.hidden { 1 } else { 0 }, index.index) + ) -> WasmResult<(u8, u8)> { + let index = &pokemon.value_func(&env)?.real_ability(); + WasmResult::ok((if index.hidden { 1 } else { 0 }, index.index)) } fn pokemon_get_is_ability_overriden( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - if pokemon.value_func(&env).unwrap().is_ability_overriden() { 1 } else { 0 } + ) -> WasmResult { + Ok(if pokemon.value_func(&env)?.is_ability_overriden() { 1 } else { 0 }).into() } fn pokemon_get_allowed_experience_gain( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - if pokemon.value_func(&env).unwrap().allowed_experience_gain() { 1 } else { 0 } + ) -> WasmResult { + Ok(if pokemon.value_func(&env)?.allowed_experience_gain() { 1 } else { 0 }).into() } fn pokemon_get_is_usable( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - if pokemon.value_func(&env).unwrap().is_usable() { 1 } else { 0 } + ) -> WasmResult { + Ok(if pokemon.value_func(&env)?.is_usable() { 1 } else { 0 }).into() } @@ -251,56 +255,56 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, item: ExternRef - ) -> ExternRef { - let item = item.value_func_arc(&env).unwrap(); - let old_item = pokemon.value_func(&env).unwrap().set_held_item(&item); - if let Some(old_item) = old_item { + ) -> WasmResult> { + let item = item.value_func_arc(&env)?; + let old_item = pokemon.value_func(&env)?.set_held_item(&item); + Ok(if let Some(old_item) = old_item { ExternRef::func_new(&env, &old_item) } else { ExternRef::null() - } + }).into() } fn pokemon_remove_held_item( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - let old_item = pokemon.value_func(&env).unwrap().remove_held_item(); - if let Some(old_item) = old_item { + ) -> WasmResult> { + let old_item = pokemon.value_func(&env)?.remove_held_item(); + Ok(if let Some(old_item) = old_item { ExternRef::func_new(&env, &old_item) } else { ExternRef::null() - } + }).into() } fn pokemon_consume_held_item( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - if pokemon.value_func(&env).unwrap().consume_held_item().unwrap() { 1 } else { 0 } + ) -> WasmResult { + Ok(if pokemon.value_func(&env)?.consume_held_item()? { 1 } else { 0 }).into() } fn pokemon_get_types_length( env: FunctionEnvMut, pokemon: ExternRef - ) -> u32 { - pokemon.value_func(&env).unwrap().types().len() as u32 + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.types().len() as u32).into() } fn pokemon_get_type( env: FunctionEnvMut, pokemon: ExternRef, index: u32 - ) -> u8 { - (*pokemon.value_func(&env).unwrap().types().get(index as usize).unwrap()).into() + ) -> WasmResult { + Ok((*pokemon.value_func(&env)?.types().get_res(index as usize)?).into()).into() } fn pokemon_has_type( env: FunctionEnvMut, pokemon: ExternRef, t: u8 - ) -> u8 { - if pokemon.value_func(&env).unwrap().types().contains(&t.into()) { 1 } else { 0 } + ) -> WasmResult { + Ok(if pokemon.value_func(&env)?.types().contains(&t.into()) { 1 } else { 0 }).into() } fn pokemon_change_species( @@ -308,97 +312,102 @@ register! { pokemon: ExternRef, species: ExternRef, form: ExternRef, - ) { - pokemon.value_func(&env).unwrap().change_species( - species.value_func_arc(&env).unwrap(), - form.value_func_arc(&env).unwrap(), - ).unwrap(); + ) -> WasmResult<()> { + pokemon.value_func(&env)?.change_species( + species.value_func_arc(&env)?, + form.value_func_arc(&env)?, + )?; + WasmResult::ok(()) } fn pokemon_change_form( env: FunctionEnvMut, pokemon: ExternRef, form: ExternRef, - ) { - pokemon.value_func(&env).unwrap().change_form( - &form.value_func_arc(&env).unwrap(), - ).unwrap(); + ) -> WasmResult<()> { + pokemon.value_func(&env)?.change_form( + &form.value_func_arc(&env)?, + )?; + WasmResult::ok(()) } fn pokemon_get_current_health( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u32 { - pokemon.value_func(&env).unwrap().current_health() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.current_health()).into() } fn pokemon_get_nature( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, pokemon.value_func(&env).unwrap().nature()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, pokemon.value_func(&env)?.nature())).into() } fn pokemon_get_form( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, &pokemon.value_func(&env).unwrap().form()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, &pokemon.value_func(&env)?.form())).into() } fn pokemon_get_display_species( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, &pokemon.value_func(&env).unwrap().display_species()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, &pokemon.value_func(&env)?.display_species())).into() } fn pokemon_get_display_form( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, &pokemon.value_func(&env).unwrap().display_form()) + ) -> WasmResult> { + Ok(ExternRef::func_new(&env, &pokemon.value_func(&env)?.display_form())).into() } fn pokemon_get_level( env: FunctionEnvMut, pokemon: ExternRef, - ) -> LevelInt { - pokemon.value_func(&env).unwrap().level() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.level()).into() } fn pokemon_get_experience( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u32 { - pokemon.value_func(&env).unwrap().experience() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.experience()).into() } fn pokemon_get_unique_identifier( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u32 { - pokemon.value_func(&env).unwrap().unique_identifier() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.unique_identifier()).into() } fn pokemon_get_coloring( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u8 { - pokemon.value_func(&env).unwrap().coloring() + ) -> WasmResult { + Ok(pokemon.value_func(&env)?.coloring()).into() } fn pokemon_get_nickname( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u32 { - let pokemon = pokemon.value_func(&env).unwrap(); + ) -> WasmResult { + let pokemon = pokemon.value_func(&env)?; let nickname = pokemon.nickname(); if let Some(nickname) = nickname { - let nickname: CString = CString::new(nickname.as_str()).unwrap(); - env.data().data().copy_value_vec_to_wasm(nickname.as_bytes()) + let nickname: CString = match CString::new(nickname.as_str()) { + Ok(nickname) => nickname, + Err(e) => return WasmResult::err(e.into()), + }; + env.data().data().copy_value_vec_to_wasm(nickname.as_bytes()).into() } else { - 0 + Ok(0).into() } } @@ -408,15 +417,15 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, name_ptr: u32 - ) -> u32 { + ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - let script = pokemon.value_func(&env).unwrap().add_volatile_script(&c_name.as_ref().into()).unwrap(); + let script = pokemon.value_func(&env)?.add_volatile_script(&c_name.as_ref().into())?; if let Some(script) = script { - let script = script.get_as::().unwrap(); - script.get_wasm_pointer() + let script = script.get_as::()?; + Ok(script.get_wasm_pointer()).into() } else { - 0 + Ok(0).into() } } } @@ -425,21 +434,24 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, script_ptr: u32 - ) -> u32 { - let pokemon : &Pokemon = pokemon.value_func(&env).unwrap(); + ) -> WasmResult { + let pokemon : &Pokemon = pokemon.value_func(&env)?; unsafe{ let env = env.data().data(); - let name_ptr = env.script_function_cache().script_get_name(&env).unwrap().call(&mut env.store_mut(), script_ptr).unwrap(); + let name_ptr = match env.script_function_cache().script_get_name(&env)?.call(&mut env.store_mut(), script_ptr){ + Ok(name_ptr) => name_ptr, + Err(e) => return WasmResult::err(e.into()) + }; let c_name: &CStr = CStr::from_ptr(env.get_raw_pointer(name_ptr)); - let script = env.setup_script(script_ptr, ScriptCategory::Pokemon, &c_name.as_ref().into(), pokemon.into()).unwrap(); - env.script_function_cache().dealloc_cstring(&env).unwrap().call(&mut env.store_mut(), name_ptr).unwrap(); + let script = env.setup_script(script_ptr, ScriptCategory::Pokemon, &c_name.as_ref().into(), pokemon.into())?; + env.script_function_cache().dealloc_cstring(&env, name_ptr)?; if let Some(script) = script { - let script = pokemon.add_volatile_script_with_script(script); - let s = script.as_ref().unwrap().as_ref().unwrap().get_as::().unwrap(); - s.get_wasm_pointer() + let script = pokemon.add_volatile_script_with_script(script)?; + let s = script.as_ref().ok_or(anyhow!("Unable to get script"))?.get_as::()?; + WasmResult::ok(s.get_wasm_pointer()) } else { - 0 + WasmResult::ok(0) } } } @@ -448,10 +460,10 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, name_ptr: u32 - ) -> u8 { + ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - u8::from(pokemon.value_func(&env).unwrap().has_volatile_script(&c_name.as_ref().into())) + Ok(u8::from(pokemon.value_func(&env)?.has_volatile_script(&c_name.as_ref().into()))).into() } } @@ -459,16 +471,16 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, name_ptr: u32 - ) -> u32 { + ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - let script = pokemon.value_func(&env).unwrap().get_volatile_script(&c_name.as_ref().into()); - if let Some(script) = script { - let script = script.get_as::().unwrap(); + let script = pokemon.value_func(&env)?.get_volatile_script(&c_name.as_ref().into()); + Ok(if let Some(script) = script { + let script = script.get_as::()?; script.get_wasm_pointer() } else { 0 - } + }).into() } } @@ -476,25 +488,24 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, name_ptr: u32 - ) { + ) -> WasmResult<()> { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - pokemon.value_func(&env).unwrap().remove_volatile_script(&c_name.as_ref().into()).unwrap(); + pokemon.value_func(&env)?.remove_volatile_script(&c_name.as_ref().into())?; + WasmResult::ok(()) } } fn pokemon_get_ability_script( env: FunctionEnvMut, pokemon: ExternRef, - ) -> u32 { - let pokemon = pokemon.value_func(&env).unwrap(); - if let Some(script) = pokemon.ability_script().get() { - let read_lock = script.read(); - if let Some(script) = read_lock.as_ref() { - return script.as_any().downcast_ref::().unwrap().get_wasm_pointer() - } + ) -> WasmResult { + let pokemon = pokemon.value_func(&env)?; + let script = pokemon.ability_script(); + if script.is_any() { + return Ok(script.get_as::()?.get_wasm_pointer()).into(); } - 0 + WasmResult::ok(0) } } diff --git a/src/script_implementations/wasm/export_registry/mod.rs b/src/script_implementations/wasm/export_registry/mod.rs index e86fade..9302096 100755 --- a/src/script_implementations/wasm/export_registry/mod.rs +++ b/src/script_implementations/wasm/export_registry/mod.rs @@ -1,7 +1,11 @@ +use anyhow_ext::anyhow; +use anyhow_ext::Result; +use num_traits::{NumCast, PrimInt}; use std::ffi::{c_char, CStr, CString}; use std::mem::{align_of, forget}; +use std::ops::{ControlFlow, FromResidual, Try}; -use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut}; +use wasmer::{FromToNativeWasmType, FunctionEnv, FunctionEnvMut, Imports, NativeWasmTypeInto, StoreMut}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; @@ -108,80 +112,147 @@ fn _error(env: FunctionEnvMut, message: u32, file: u32, line: u3 } /// Get a single item from an earlier passed VecExternRef -fn _vec_extern_ref_get_value(env: FunctionEnvMut, reference: u32, index: u32) -> u32 { - env.data() +fn _vec_extern_ref_get_value(env: FunctionEnvMut, reference: u32, index: u32) -> WasmResult { + let res = env .data() - .get_extern_vec_ref_extern_ref(reference as usize, index as usize) as u32 + .data() + .get_extern_vec_ref_extern_ref(reference as usize, index as usize)?; + Ok(res as u32).into() } /// Gets the hash value of a StringKey. -fn string_key_get_hash(env: FunctionEnvMut, string_key: ExternRef) -> u32 { - string_key.value_func(&env).unwrap().hash() +fn string_key_get_hash(env: FunctionEnvMut, string_key: ExternRef) -> WasmResult { + Ok(string_key.value_func(&env)?.hash()).into() } /// Get a null-terminated C string from a StringKey. Note that this involves a copy into WASM /// memory, so this is relatively heavy. -fn string_key_get_str(env: FunctionEnvMut, string_key: ExternRef) -> u32 { - let string_key = string_key.value_func(&env).unwrap().str(); +fn string_key_get_str(env: FunctionEnvMut, string_key: ExternRef) -> WasmResult { + let string_key = string_key.value_func(&env)?.str(); let wasm_string_ptr = env .data() .data() - .allocate_mem((string_key.len() + 1) as u32, align_of::() as u32); + .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_u8); forget(wasm_string); - wasm_string_ptr.1 + Ok(wasm_string_ptr.1).into() } /// Gets the type of an EffectParameter -fn effect_parameter_get_type(env: FunctionEnvMut, parameter: ExternRef) -> u8 { - let v = parameter.value_func(&env).unwrap(); - match v { +fn effect_parameter_get_type( + env: FunctionEnvMut, + parameter: ExternRef, +) -> WasmResult { + let v = parameter.value_func(&env)?; + Ok(match v { EffectParameter::Bool(_, _) => 1, EffectParameter::Int(_, _) => 2, EffectParameter::Float(_, _) => 3, EffectParameter::String(_, _) => 4, - } + }) + .into() } /// Gets the inner bool data of an EffectParameter. Panics if it's not a bool. -fn effect_parameter_as_bool(env: FunctionEnvMut, parameter: ExternRef) -> u8 { - let v = parameter.value_func(&env).unwrap(); +fn effect_parameter_as_bool( + env: FunctionEnvMut, + parameter: ExternRef, +) -> WasmResult { + let v = parameter.value_func(&env)?; match v { - EffectParameter::Bool(_, b) => u8::from(*b), - _ => panic!("Unexpected parameter type!"), + EffectParameter::Bool(_, b) => Ok(>::from(*b)), + _ => Err(anyhow!("Unexpected parameter type. Expected bool, got {}", v)), } + .into() } /// Gets the inner int data of an EffectParameter. Panics if it's not an int. -fn effect_parameter_as_int(env: FunctionEnvMut, parameter: ExternRef) -> i64 { - let v = parameter.value_func(&env).unwrap(); +fn effect_parameter_as_int( + env: FunctionEnvMut, + parameter: ExternRef, +) -> WasmResult { + let v = parameter.value_func(&env)?; match v { - EffectParameter::Int(_, i) => *i, - _ => panic!("Unexpected parameter type!"), + EffectParameter::Int(_, i) => Ok(*i), + _ => Err(anyhow!("Unexpected parameter type. Expected int, got {}", v)), } + .into() } /// Gets the inner float data of an EffectParameter. Panics if it's not a float. -fn effect_parameter_as_float(env: FunctionEnvMut, parameter: ExternRef) -> f32 { - let v = parameter.value_func(&env).unwrap(); +fn effect_parameter_as_float( + env: FunctionEnvMut, + parameter: ExternRef, +) -> WasmResult { + let v = parameter.value_func(&env)?; match v { - EffectParameter::Float(_, f) => *f, - _ => panic!("Unexpected parameter type!"), + EffectParameter::Float(_, f) => Ok(*f), + _ => Err(anyhow!("Unexpected parameter type. Expected float, got {}", v)), } + .into() } /// Gets the inner string data of an EffectParameter. Panics if it's not a string. fn effect_parameter_as_string( env: FunctionEnvMut, parameter: ExternRef, -) -> ExternRef { - let v = parameter.value_func(&env).unwrap(); +) -> WasmResult> { + let v = parameter.value_func(&env)?; match v { - EffectParameter::String(_, s) => ExternRef::func_new(&env, s), - _ => panic!("Unexpected parameter type!"), + EffectParameter::String(_, s) => Ok(ExternRef::func_new(&env, s)), + _ => Err(anyhow!("Unexpected parameter type. Expected string, got {}", v)), + } + .into() +} + +/// A result type that can be given to, or returned from WASM. +struct WasmResult(Result); + +impl WasmResult { + /// Create a new WasmResult with an OK value. + pub fn ok(value: T) -> Self { + Self(Ok(value)) + } + + /// Create a new WasmResult with an Err value. + pub fn err(value: anyhow_ext::Error) -> Self { + Self(Err(value)) + } +} + +impl From> for WasmResult { + fn from(value: Result) -> Self { + Self(value) + } +} + +impl FromResidual for WasmResult { + fn from_residual(residual: ::Residual) -> Self { + match residual { + Ok(_) => { + unimplemented!() + } + Err(e) => WasmResult(Err(e)), + } + } +} + +impl Try for WasmResult { + type Output = T; + type Residual = as Try>::Residual; + + fn from_output(output: Self::Output) -> Self { + Self(Ok(output)) + } + + fn branch(self) -> ControlFlow { + match self.0 { + Ok(v) => ControlFlow::Continue(v), + Err(e) => ControlFlow::Break(Err(e)), + } } } diff --git a/src/script_implementations/wasm/export_registry/static_data/form.rs b/src/script_implementations/wasm/export_registry/static_data/form.rs index d592df2..93ac351 100644 --- a/src/script_implementations/wasm/export_registry/static_data/form.rs +++ b/src/script_implementations/wasm/export_registry/static_data/form.rs @@ -1,5 +1,5 @@ -use crate::script_implementations::wasm::export_registry::register; use crate::script_implementations::wasm::export_registry::FunctionEnvMut; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::{Form, StatisticSet}; @@ -18,11 +18,11 @@ fn form_get_name( fn form_get_types( env: FunctionEnvMut, form: ExternRef -) -> (u32, u32) { +) -> WasmResult<(u32, u32)> { let form = form.value_func_arc(&env).unwrap(); let vec = form.types(); - let wasm_ptr = env.data().data().copy_value_vec_to_wasm(vec); - (wasm_ptr, vec.len() as u32) + let wasm_ptr = env.data().data().copy_value_vec_to_wasm(vec)?; + Ok((wasm_ptr, vec.len() as u32)).into() } fn form_get_height( diff --git a/src/script_implementations/wasm/extern_ref.rs b/src/script_implementations/wasm/extern_ref.rs index 4412449..603dfbf 100755 --- a/src/script_implementations/wasm/extern_ref.rs +++ b/src/script_implementations/wasm/extern_ref.rs @@ -1,4 +1,5 @@ -use crate::ValueIdentifiable; +use crate::{PkmnError, ValueIdentifiable}; +use anyhow_ext::Result; use std::any::Any; use std::marker::PhantomData; use std::mem::transmute; @@ -68,25 +69,26 @@ impl ExternRef { /// 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) -> Option<&'a T> + pub fn value_func<'a>(&self, env: &'a FunctionEnvMut) -> Result<&'a T> where T: Sized + 'static, { - self.value(&env.data().data()) + 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) -> Option> + pub fn value_func_arc(&self, env: &FunctionEnvMut) -> Result> where T: 'static, { - self.value_arc(&env.data().data()) + 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) -> Option<&Box> + pub fn value_func_box(&self, env: &FunctionEnvMut) -> Result<&Box> where T: 'static, { @@ -95,31 +97,34 @@ impl ExternRef { /// 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) -> Option<&'a T> + pub fn value<'a>(&self, env: &Arc) -> Result> where T: Sized + 'static, { - env.get_extern_ref_value::(self.index).downcast_ref::() + Ok(env.get_extern_ref_value::(self.index)?.downcast_ref::()) } /// 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) -> Option> + pub fn value_arc(&self, env: &Arc) -> Result>> where T: 'static, { - env.get_extern_ref_value::(self.index) + Ok(env + .get_extern_ref_value::(self.index)? .downcast_ref::>() - .cloned() + .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) -> Option<&Box> + pub fn value_box(&self, env: &Arc) -> Result<&Box> where T: 'static, { - env.get_extern_ref_value::(self.index).downcast_ref::>() + env.get_extern_ref_value::(self.index)? + .downcast_ref::>() + .ok_or(PkmnError::NullReference.into()) } } diff --git a/src/script_implementations/wasm/script.rs b/src/script_implementations/wasm/script.rs index 9204bd6..f78c62e 100755 --- a/src/script_implementations/wasm/script.rs +++ b/src/script_implementations/wasm/script.rs @@ -1,4 +1,4 @@ -use anyhow_ext::Result; +use anyhow_ext::{anyhow, Result}; use std::any::Any; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::Arc; @@ -189,7 +189,11 @@ impl Script for WebAssemblyScript { let move_ref = ex_ref!(env, move_name); let ptr = env.allocate_temp::>(move_ref); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); - *move_name = ptr.value().value(env).unwrap().clone(); + *move_name = ptr + .value() + .value(env)? + .ok_or(anyhow!("Unable to get move name"))? + .clone(); } Ok(()) } diff --git a/src/script_implementations/wasm/script_function_cache.rs b/src/script_implementations/wasm/script_function_cache.rs index e7eb05a..2f55da6 100755 --- a/src/script_implementations/wasm/script_function_cache.rs +++ b/src/script_implementations/wasm/script_function_cache.rs @@ -1,6 +1,8 @@ +use anyhow::anyhow; use std::marker::PhantomData; use std::sync::Arc; +use anyhow_ext::Result; use parking_lot::RwLock; use paste::paste; @@ -177,40 +179,50 @@ script_function_cache! { impl ScriptFunctionCache { /// Get the name of a script. - pub(crate) fn script_get_name(&self, env: &Arc) -> Option> { + pub(crate) fn script_get_name(&self, env: &Arc) -> Result> { { let read_lock = self.script_get_name.read(); if let Some(f) = read_lock.as_ref() { - return Some(f.clone()); + return Ok(f.clone()); } } { let exported = env.exported_functions(); let f = exported.get::(&"script_get_name".into()); if let Some(f) = f { - let func: TypedFunction = f.typed(&env.store_ref()).unwrap(); + let func: TypedFunction = f.typed(&env.store_ref())?; let _ = self.script_get_name.write().insert(func); } } - self.script_get_name.read().as_ref().cloned() + Ok(self + .script_get_name + .read() + .as_ref() + .ok_or(anyhow!("Couldn't find script function `script_get_name`"))? + .clone()) } /// Drop the memory of a CString inside the WASM memory. - pub(crate) fn dealloc_cstring(&self, env: &Arc) -> Option> { + pub(crate) fn dealloc_cstring(&self, env: &Arc, ptr: u32) -> Result<()> { { let read_lock = self.dealloc_cstring.read(); - if let Some(f) = read_lock.as_ref() { - return Some(f.clone()); + if read_lock.is_none() { + drop(read_lock); + let exported = env.exported_functions(); + let f = exported.get::(&"dealloc_cstring".into()); + if let Some(f) = f { + let func: TypedFunction = f.typed(&env.store_ref())?; + let _ = self.dealloc_cstring.write().insert(func); + } } - } - { - let exported = env.exported_functions(); - let f = exported.get::(&"dealloc_cstring".into()); - if let Some(f) = f { - let func: TypedFunction = f.typed(&env.store_ref()).unwrap(); - let _ = self.dealloc_cstring.write().insert(func); - } - } - self.dealloc_cstring.read().as_ref().cloned() + }; + let func = self + .dealloc_cstring + .read() + .as_ref() + .ok_or(anyhow!("Couldn't find script function `dealloc_cstring`"))? + .clone(); + func.call(&mut env.store_mut(), ptr)?; + Ok(()) } } diff --git a/src/script_implementations/wasm/script_resolver.rs b/src/script_implementations/wasm/script_resolver.rs index 37bb11e..13d99f2 100755 --- a/src/script_implementations/wasm/script_resolver.rs +++ b/src/script_implementations/wasm/script_resolver.rs @@ -21,7 +21,7 @@ use crate::script_implementations::wasm::script_function_cache::ScriptFunctionCa use crate::script_implementations::wasm::temp_wasm_allocator::{AllocatedObject, TempWasmAllocator}; use crate::script_implementations::wasm::WebAssemblyScriptCapabilities; use crate::static_data::Item; -use crate::{ScriptCategory, StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::{ScriptCategory, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; /// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly. pub struct WebAssemblyScriptResolver { @@ -80,23 +80,30 @@ impl WebAssemblyScriptResolver { /// Get an immutable reference to the current WASM Store. fn store_ref(&self) -> StoreRef<'_> { - unsafe { self._store.as_ref().unwrap().as_store_ref() } + #[allow(clippy::unwrap_used)] // We know this is valid. + unsafe { + self._store.as_ref().unwrap().as_store_ref() + } } /// Get a mutable reference to the current WASM Store. fn store_mut(&self) -> StoreMut<'_> { - unsafe { self._store.as_mut().unwrap().as_store_mut() } + #[allow(clippy::unwrap_used)] // We know this is valid. + unsafe { + self._store.as_mut().unwrap().as_store_mut() + } } /// Load a compiled WASM module. - pub fn load_wasm_from_bytes(&mut self, bytes: &[u8]) { + pub fn load_wasm_from_bytes(&mut self, bytes: &[u8]) -> Result<()> { // FIXME: Error handling - let module = Module::new(&self.store_ref(), bytes).unwrap(); + let module = Module::new(&self.store_ref(), bytes)?; self.modules.push(module); + Ok(()) } /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. - pub fn finalize(&mut self) { + pub fn finalize(&mut self) -> Result<()> { let mut imports = Imports::new(); let env = FunctionEnv::new( @@ -115,12 +122,12 @@ impl WebAssemblyScriptResolver { } } - let instance = Instance::new(&mut self.store_mut(), module, &imports).unwrap(); + let instance = Instance::new(&mut self.store_mut(), module, &imports)?; let exports = &instance.exports; let init_fn = exports.get_extern("_init"); if let Some(Extern::Function(init_fn)) = init_fn { - init_fn.call(&mut self.store_mut(), &[]).unwrap(); + init_fn.call(&mut self.store_mut(), &[])?; } let mut exported_functions = self.environment_data.exported_functions.write(); @@ -136,19 +143,19 @@ impl WebAssemblyScriptResolver { } } if let Some(m) = &self.environment_data.memory.read().as_ref() { - m.grow(&mut self.store_mut(), 32).unwrap(); + m.grow(&mut self.store_mut(), 32)?; } if let Some(f) = exported_functions.get::(&"load_script".into()) { - self.load_script_fn = Some(f.typed(&self.store_ref()).unwrap()) + self.load_script_fn = Some(f.typed(&self.store_ref())?) } if let Some(f) = exported_functions.get::(&"allocate_mem".into()) { let _ = self .environment_data .allocate_mem_fn .write() - .insert(f.typed(&self.store_ref()).unwrap()); + .insert(f.typed(&self.store_ref())?); - let temp_memory_slab = self.environment_data.allocate_mem(128, 1); + let temp_memory_slab = self.environment_data.allocate_mem(128, 1)?; let _ = self .environment_data .temp_allocator @@ -157,6 +164,7 @@ impl WebAssemblyScriptResolver { } self.instances.push(instance); } + Ok(()) } /// Gets the data passed to every function as environment data. @@ -289,11 +297,13 @@ impl WebAssemblyEnvironmentData { /// This returns the memory of the WASM container. pub fn memory(&self) -> *mut u8 { + #[allow(clippy::unwrap_used)] // We know this is valid. self.memory.read().as_ref().unwrap().view(&self.store_ref()).data_ptr() } /// Return a pointer to something inside the WASM memory. pub fn get_raw_pointer(&self, offset: u32) -> *mut T { + #[allow(clippy::unwrap_used)] // We know this is valid. unsafe { self.memory .read() @@ -319,57 +329,55 @@ impl WebAssemblyEnvironmentData { /// owned by WASM, and is how we can pass memory references that the host allocated to WASM. /// The return is a tuple containing both the actual pointer to the memory (usable by the host), /// and the WASM offset to the memory (usable by the client). - pub fn allocate_mem(&self, size: u32, align: u32) -> (*mut u8, u32) { + pub fn allocate_mem(&self, size: u32, align: u32) -> Result<(*mut u8, u32)> { let wasm_ptr = self .allocate_mem_fn .read() .as_ref() - .unwrap() - .call(&mut self.store_mut(), size, align) - .unwrap(); - unsafe { (self.memory().offset(wasm_ptr as isize), wasm_ptr) } + .ok_or(anyhow!("allocate_mem_fn not set"))? + .call(&mut self.store_mut(), size, align)?; + unsafe { Ok((self.memory().offset(wasm_ptr as isize), wasm_ptr)) } } /// Allocates memory inside the WASM container with a given size and alignment. This memory is /// owned by WASM, and is how we can pass memory references that the host allocated to WASM. /// The return is a tuple containing both the actual pointer to the memory (usable by the host), /// and the WASM offset to the memory (usable by the client). - pub fn allocate_mem_typed(&self) -> (*mut u8, u32) { + pub fn allocate_mem_typed(&self) -> Result<(*mut u8, u32)> { let wasm_ptr = self .allocate_mem_fn .read() .as_ref() - .unwrap() - .call(&mut self.store_mut(), size_of::() as u32, align_of::() as u32) - .unwrap(); - unsafe { (self.memory().offset(wasm_ptr as isize), wasm_ptr) } + .ok_or(anyhow!("allocate_mem_fn not set"))? + .call(&mut self.store_mut(), size_of::() as u32, align_of::() as u32)?; + unsafe { Ok((self.memory().offset(wasm_ptr as isize), wasm_ptr)) } } /// Allocates a raw array in wasm, and copy the values from a given slice to it. Returns the /// pointer in wasm memory. - pub fn copy_value_vec_to_wasm(&self, v: &[T]) -> u32 { + pub fn copy_value_vec_to_wasm(&self, v: &[T]) -> Result { let wasm_ptr = self .allocate_mem_fn .read() .as_ref() - .unwrap() + .ok_or(anyhow!("allocate_mem_fn not set"))? .call( &mut self.store_mut(), (std::mem::size_of_val(v)) as u32, align_of::() as u32, - ) - .unwrap(); + )?; unsafe { let raw = self.memory().offset(wasm_ptr as isize) as *mut T; v.as_ptr().copy_to(raw, v.len()); } - wasm_ptr + Ok(wasm_ptr) } /// Allocate a piece of memory inside WASM with a very short lifespan. This is mainly used for /// rapid allocation of script function parameters, where WASM needs to write to a specific /// pointer. pub(super) fn allocate_temp(&self, value: T) -> AllocatedObject { + #[allow(clippy::unwrap_used)] // We know this is valid. self.temp_allocator.read().as_ref().unwrap().alloc::(value) } @@ -401,10 +409,10 @@ impl WebAssemblyEnvironmentData { } /// Get an extern ref belonging to a vector we have passed to WASM. - pub fn get_extern_vec_ref_extern_ref(&self, extern_vec_ref: usize, index: usize) -> usize { + pub fn get_extern_vec_ref_extern_ref(&self, extern_vec_ref: usize, index: usize) -> Result { let r = self.extern_vec_ref_lookup.read(); - let v = r.get(&extern_vec_ref).unwrap(); - v[index] + let v = r.get(&extern_vec_ref).ok_or(anyhow!("Invalid extern vec ref"))?; + Ok(*v.get_res(index)?) } /// Gets the extern ref index belonging to a specific pointer. If none exists, this will create @@ -438,9 +446,9 @@ impl WebAssemblyEnvironmentData { /// Gets a value from the extern ref lookup. This turns an earlier registered index back into /// its proper value, validates its type, and returns the value. - pub fn get_extern_ref_value<'a, T: ?Sized>(&self, index: usize) -> &'a dyn Any { + pub fn get_extern_ref_value<'a, T: ?Sized>(&self, index: usize) -> Result<&'a dyn Any> { let read_guard = self.extern_ref_pointers.read(); - let ptr = read_guard.get(index - 1).unwrap(); + let ptr = read_guard.get_res(index - 1)?; if self .extern_ref_type_lookup .read() @@ -450,13 +458,16 @@ impl WebAssemblyEnvironmentData { }) .is_none() { - panic!( - "Extern ref was accessed with wrong type. Requested type {}, but this was not the type the extern ref was stored with.", - std::any::type_name::() - ); + #[allow(clippy::panic)] // Allow panic here, as this is a security error. + { + panic!( + "Extern ref was accessed with wrong type. Requested type {}, but this was not the type the extern ref was stored with.", + std::any::type_name::() + ); + } } - unsafe { ptr.as_ref().unwrap() } + unsafe { Ok(ptr.as_ref().unwrap()) } } /// The WASM store. diff --git a/src/script_implementations/wasm/temp_wasm_allocator.rs b/src/script_implementations/wasm/temp_wasm_allocator.rs index e8806ec..3a2276b 100755 --- a/src/script_implementations/wasm/temp_wasm_allocator.rs +++ b/src/script_implementations/wasm/temp_wasm_allocator.rs @@ -75,6 +75,7 @@ impl AllocatedObject { impl Drop for AllocatedObject { fn drop(&mut self) { + #[allow(clippy::unwrap_used)] // We know this is valid. unsafe { self.allocator.as_ref().unwrap().drop::(); } diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index fd50925..fa060ac 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -364,8 +364,8 @@ fn load_script_resolver(path: &String) -> Box { let mut reader = BufReader::new(file); let mut buffer = Vec::new(); reader.read_to_end(&mut buffer).unwrap(); - resolver.load_wasm_from_bytes(&buffer); - resolver.finalize(); + resolver.load_wasm_from_bytes(&buffer).unwrap(); + resolver.finalize().unwrap(); resolver }