diff --git a/src/dynamic_data/flow/choice_queue.rs b/src/dynamic_data/flow/choice_queue.rs index 16d3724..67e2700 100755 --- a/src/dynamic_data/flow/choice_queue.rs +++ b/src/dynamic_data/flow/choice_queue.rs @@ -160,6 +160,7 @@ impl ValueIdentifiable for ChoiceQueue { #[cfg(test)] #[allow(clippy::unwrap_used)] +#[allow(clippy::indexing_slicing)] mod tests { use super::*; use crate::defines::LevelInt; diff --git a/src/dynamic_data/flow/turn_runner.rs b/src/dynamic_data/flow/turn_runner.rs index ae1c4ee..010f503 100755 --- a/src/dynamic_data/flow/turn_runner.rs +++ b/src/dynamic_data/flow/turn_runner.rs @@ -213,7 +213,7 @@ impl Battle { .library() .static_data() .types() - .get_effectiveness(hit_type, &target.types()); + .get_effectiveness(hit_type, &target.types())?; script_hook!( change_effectiveness, executing_move, diff --git a/src/dynamic_data/libraries/battle_stat_calculator.rs b/src/dynamic_data/libraries/battle_stat_calculator.rs index af1f227..9990078 100755 --- a/src/dynamic_data/libraries/battle_stat_calculator.rs +++ b/src/dynamic_data/libraries/battle_stat_calculator.rs @@ -147,6 +147,7 @@ impl ValueIdentifiable for Gen7BattleStatCalculator { } } #[cfg(test)] +#[allow(clippy::indexing_slicing)] pub mod tests { use super::*; diff --git a/src/dynamic_data/libraries/dynamic_library.rs b/src/dynamic_data/libraries/dynamic_library.rs index 9762e9b..828b0f0 100755 --- a/src/dynamic_data/libraries/dynamic_library.rs +++ b/src/dynamic_data/libraries/dynamic_library.rs @@ -127,6 +127,7 @@ impl ValueIdentifiable for DynamicLibraryImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] pub mod test { use super::*; use crate::dynamic_data::libraries::battle_stat_calculator::Gen7BattleStatCalculator; diff --git a/src/dynamic_data/models/learned_move.rs b/src/dynamic_data/models/learned_move.rs index 01513dc..0c6e844 100755 --- a/src/dynamic_data/models/learned_move.rs +++ b/src/dynamic_data/models/learned_move.rs @@ -101,6 +101,7 @@ impl ValueIdentifiable for LearnedMove { } #[cfg(test)] +#[allow(clippy::unwrap_used)] mod tests { use super::*; use crate::static_data::tests::MockMoveData; diff --git a/src/dynamic_data/models/pokemon.rs b/src/dynamic_data/models/pokemon.rs index 3133259..6fb7eea 100755 --- a/src/dynamic_data/models/pokemon.rs +++ b/src/dynamic_data/models/pokemon.rs @@ -421,7 +421,7 @@ impl Pokemon { } let form = self.form(); - let ability = form.get_ability(self.ability_index); + let ability = form.get_ability(self.ability_index)?; Ok(self .library .static_data() diff --git a/src/dynamic_data/models/pokemon_builder.rs b/src/dynamic_data/models/pokemon_builder.rs index e4e09ea..f43ddb4 100755 --- a/src/dynamic_data/models/pokemon_builder.rs +++ b/src/dynamic_data/models/pokemon_builder.rs @@ -53,7 +53,7 @@ impl PokemonBuilder { .species() .get(&self.species) .ok_or(PkmnError::InvalidSpeciesName { species: self.species })?; - let form = species.get_default_form(); + let form = species.get_default_form()?; let p = Pokemon::new( self.library, species, diff --git a/src/dynamic_data/script_handling/script.rs b/src/dynamic_data/script_handling/script.rs index 33f6ab9..df296e1 100755 --- a/src/dynamic_data/script_handling/script.rs +++ b/src/dynamic_data/script_handling/script.rs @@ -388,6 +388,8 @@ impl Clone for ScriptContainer { } #[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::indexing_slicing)] mod tests { use std::sync::atomic::{AtomicBool, AtomicPtr}; diff --git a/src/ffi/static_data/learnable_moves.rs b/src/ffi/static_data/learnable_moves.rs index 881bf7b..57ac9ac 100644 --- a/src/ffi/static_data/learnable_moves.rs +++ b/src/ffi/static_data/learnable_moves.rs @@ -1,5 +1,5 @@ use crate::defines::LevelInt; -use crate::ffi::{BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{BorrowedPtr, ExternPointer, NativeResult, OwnedPtr}; use crate::static_data::{LearnableMoves, LearnableMovesImpl}; use std::ffi::{c_char, CStr}; use std::ptr::drop_in_place; @@ -22,6 +22,8 @@ unsafe extern "C" fn learnable_moves_add_level_move( mut ptr: ExternPointer>, level: LevelInt, move_name: BorrowedPtr, -) { - ptr.as_mut().add_level_move(level, &CStr::from_ptr(move_name).into()) +) -> NativeResult<()> { + ptr.as_mut() + .add_level_move(level, &CStr::from_ptr(move_name).into()) + .into() } diff --git a/src/ffi/static_data/libraries/growth_rate_library.rs b/src/ffi/static_data/libraries/growth_rate_library.rs index 155f948..020ed0d 100644 --- a/src/ffi/static_data/libraries/growth_rate_library.rs +++ b/src/ffi/static_data/libraries/growth_rate_library.rs @@ -23,9 +23,10 @@ unsafe extern "C" fn growth_rate_library_calculate_level( ptr: ExternPointer>, growth_rate: BorrowedPtr, experience: u32, -) -> LevelInt { +) -> NativeResult { ptr.as_ref() .calculate_level(&CStr::from_ptr(growth_rate).into(), experience) + .into() } /// Calculates the experience for a given growth key name and a certain level. diff --git a/src/ffi/static_data/libraries/nature_library.rs b/src/ffi/static_data/libraries/nature_library.rs index 1c25a99..47f0a78 100644 --- a/src/ffi/static_data/libraries/nature_library.rs +++ b/src/ffi/static_data/libraries/nature_library.rs @@ -54,9 +54,12 @@ unsafe extern "C" fn nature_library_get_nature( unsafe extern "C" fn nature_library_get_random_nature( ptr: ExternPointer>, seed: u64, -) -> IdentifiablePointer> { +) -> NativeResult>> { let mut rand = Random::new(seed as u128); - ptr.as_ref().get_random_nature(&mut rand).into() + match ptr.as_ref().get_random_nature(&mut rand) { + Ok(nature) => NativeResult::ok(nature.into()), + Err(e) => NativeResult::err(e), + } } /// Finds a nature name by nature. @@ -68,9 +71,12 @@ unsafe extern "C" fn nature_library_get_nature_name( match nature.as_ref() { Some(nature) => { let name = ptr.as_ref().get_nature_name(nature); - match CString::new(name.str()) { - Ok(cstr) => NativeResult::ok(cstr.into_raw()), - Err(_) => NativeResult::err(anyhow!("Failed to convert nature name to C string")), + match name { + Ok(name) => match CString::new(name.str()) { + Ok(cstr) => NativeResult::ok(cstr.into_raw()), + Err(_) => NativeResult::err(anyhow!("Failed to convert nature name to C string")), + }, + Err(e) => NativeResult::err(e), } } None => NativeResult::err(PkmnError::NullReference.into()), diff --git a/src/ffi/static_data/libraries/type_library.rs b/src/ffi/static_data/libraries/type_library.rs index bf83a7e..c023864 100644 --- a/src/ffi/static_data/libraries/type_library.rs +++ b/src/ffi/static_data/libraries/type_library.rs @@ -58,8 +58,8 @@ extern "C" fn type_library_get_single_effectiveness( ptr: ExternPointer>, attacking: TypeIdentifier, defending: TypeIdentifier, -) -> f32 { - ptr.as_ref().get_single_effectiveness(attacking, defending) +) -> NativeResult { + ptr.as_ref().get_single_effectiveness(attacking, defending).into() } /// Gets the effectiveness for a single attacking type against an amount of defending types. @@ -71,9 +71,9 @@ unsafe extern "C" fn type_library_get_effectiveness( attacking: TypeIdentifier, defending: OwnedPtr, defending_length: usize, -) -> f32 { +) -> NativeResult { let v = std::slice::from_raw_parts(defending, defending_length); - ptr.as_ref().get_effectiveness(attacking, v) + ptr.as_ref().get_effectiveness(attacking, v).into() } /// Registers a new type in the library. @@ -92,6 +92,8 @@ unsafe extern "C" fn type_library_set_effectiveness( attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32, -) { - ptr.as_mut().set_effectiveness(attacking, defending, effectiveness); +) -> NativeResult<()> { + ptr.as_mut() + .set_effectiveness(attacking, defending, effectiveness) + .into() } diff --git a/src/lib.rs b/src/lib.rs index 63cc987..2038c75 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,12 +8,12 @@ #![deny(clippy::missing_docs_in_private_items)] // Linter rules to prevent panics // Currently still a WIP to fix all of these -// #![deny(clippy::unwrap_used)] -// #![deny(clippy::expect_used)] -// #![deny(clippy::indexing_slicing)] -// #![deny(clippy::string_slice)] -// #![deny(clippy::exit)] -// #![deny(clippy::panic)] +#![deny(clippy::unwrap_used)] +#![deny(clippy::expect_used)] +#![deny(clippy::indexing_slicing)] +#![deny(clippy::string_slice)] +#![deny(clippy::exit)] +#![deny(clippy::panic)] // Features #![feature(test)] #![feature(const_option)] @@ -58,6 +58,7 @@ pub mod static_data; /// The utils module includes misc utils that are used within PkmnLib pub mod utils; +use crate::static_data::TypeIdentifier; use thiserror::Error; /// The PkmnError enum is the error type for PkmnLib. It is used to return common errors from functions @@ -103,6 +104,12 @@ pub enum PkmnError { /// The species that was requested species: StringKey, }, + /// Unable to get type + #[error("Unable to get type {type_id}")] + InvalidTypeIdentifier { + /// The type that was requested + type_id: TypeIdentifier, + }, /// The given pointer is not a valid CString #[error("The given pointer is not a valid CString")] InvalidCString, diff --git a/src/script_implementations/wasm/export_registry/static_data/types.rs b/src/script_implementations/wasm/export_registry/static_data/types.rs index 81ac68f..7e0cc9d 100644 --- a/src/script_implementations/wasm/export_registry/static_data/types.rs +++ b/src/script_implementations/wasm/export_registry/static_data/types.rs @@ -29,7 +29,7 @@ register! { defending: u8 ) -> f32 { let lib = lib.value_func_arc(&env).unwrap(); - lib.get_single_effectiveness(attacking.into(), defending.into()) + lib.get_single_effectiveness(attacking.into(), defending.into()).unwrap() } } diff --git a/src/static_data/growth_rates.rs b/src/static_data/growth_rates.rs index c24d8c9..ffa242e 100755 --- a/src/static_data/growth_rates.rs +++ b/src/static_data/growth_rates.rs @@ -49,6 +49,7 @@ impl GrowthRate for LookupGrowthRate { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] pub(crate) mod tests { use super::*; diff --git a/src/static_data/items.rs b/src/static_data/items.rs index b900b83..b7698ba 100755 --- a/src/static_data/items.rs +++ b/src/static_data/items.rs @@ -135,6 +135,7 @@ impl ValueIdentifiable for ItemImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] pub(crate) mod tests { use super::*; diff --git a/src/static_data/libraries/ability_library.rs b/src/static_data/libraries/ability_library.rs index 3e1fce6..3f5a01f 100755 --- a/src/static_data/libraries/ability_library.rs +++ b/src/static_data/libraries/ability_library.rs @@ -47,6 +47,8 @@ impl ValueIdentifiable for AbilityLibraryImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub mod tests { use crate::static_data::libraries::ability_library::AbilityLibraryImpl; use crate::static_data::AbilityImpl; diff --git a/src/static_data/libraries/growth_rate_library.rs b/src/static_data/libraries/growth_rate_library.rs index 3e7f810..e002911 100755 --- a/src/static_data/libraries/growth_rate_library.rs +++ b/src/static_data/libraries/growth_rate_library.rs @@ -11,7 +11,7 @@ use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A library to store all growth rates. pub trait GrowthRateLibrary: Debug + ValueIdentifiable { /// Calculates the level for a given growth key name and a certain experience. - fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> LevelInt; + fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result; /// Calculates the experience for a given growth key name and a certain level. fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result; /// Adds a new growth rate with a name and value. @@ -38,12 +38,19 @@ impl GrowthRateLibraryImpl { impl GrowthRateLibrary for GrowthRateLibraryImpl { /// Calculates the level for a given growth key name and a certain experience. - fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> LevelInt { - self.growth_rates[growth_rate].calculate_level(experience) + fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result { + Ok(self + .growth_rates + .get(growth_rate) + .ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))? + .calculate_level(experience)) } /// Calculates the experience for a given growth key name and a certain level. fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result { - self.growth_rates[growth_rate].calculate_experience(level) + self.growth_rates + .get(growth_rate) + .ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))? + .calculate_experience(level) } /// Adds a new growth rate with a name and value. @@ -65,6 +72,8 @@ impl Debug for GrowthRateLibraryImpl { } #[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::indexing_slicing)] pub mod tests { use super::*; use crate::static_data::growth_rates::LookupGrowthRate; @@ -89,7 +98,7 @@ pub mod tests { #[derive(Debug)] pub GrowthRateLibrary{} impl GrowthRateLibrary for GrowthRateLibrary { - fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> LevelInt; + fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result; fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result; fn add_growth_rate(&mut self, key: &StringKey, value: Box); } @@ -103,8 +112,8 @@ pub mod tests { #[test] fn add_growth_rate_to_library_and_calculate_level() { let lib = build(); - assert_eq!(lib.calculate_level(&"test_growthrate".into(), 3), 1); - assert_eq!(lib.calculate_level(&"test_growthrate".into(), 50), 3); + assert_eq!(lib.calculate_level(&"test_growthrate".into(), 3).unwrap(), 1); + assert_eq!(lib.calculate_level(&"test_growthrate".into(), 50).unwrap(), 3); } #[test] diff --git a/src/static_data/libraries/nature_library.rs b/src/static_data/libraries/nature_library.rs index 9701547..8268b63 100644 --- a/src/static_data/libraries/nature_library.rs +++ b/src/static_data/libraries/nature_library.rs @@ -1,5 +1,7 @@ use crate::static_data::Nature; use crate::{Random, StringKey, ValueIdentifiable, ValueIdentifier}; +use anyhow::bail; +use anyhow_ext::{ensure, Result}; use indexmap::IndexMap; use std::fmt::Debug; use std::sync::Arc; @@ -11,9 +13,9 @@ pub trait NatureLibrary: Debug + ValueIdentifiable { /// Gets a nature by name. fn get_nature(&self, key: &StringKey) -> Option>; /// Gets a random nature. - fn get_random_nature(&self, rand: &mut Random) -> Arc; + fn get_random_nature(&self, rand: &mut Random) -> Result>; /// Finds a nature name by nature. - fn get_nature_name(&self, nature: &Arc) -> StringKey; + fn get_nature_name(&self, nature: &Arc) -> Result; } /// A library of all natures that can be used, stored by their names. @@ -46,21 +48,28 @@ impl NatureLibrary for NatureLibraryImpl { self.map.get(key).cloned() } - fn get_random_nature(&self, rand: &mut Random) -> Arc { + fn get_random_nature(&self, rand: &mut Random) -> Result> { + ensure!(!self.map.is_empty(), "No natures were loaded into the library."); let i = rand.get_between(0, self.map.len() as i32); - return self.map.get_index(i as usize).unwrap().1.clone(); + Ok(self + .map + .get_index(i as usize) + // this should never happen, but we'll check anyway. + .ok_or(anyhow_ext::anyhow!("Failed to get a random nature from the library."))? + .1 + .clone()) } /// Finds a nature name by nature. - fn get_nature_name(&self, nature: &Arc) -> StringKey { + fn get_nature_name(&self, nature: &Arc) -> Result { for kv in &self.map { // As natures can't be copied, and should always be the same reference as the value // in the map, we just compare by reference. if kv.1.value_identifier() == nature.value_identifier() { - return kv.0.clone(); + return Ok(kv.0.clone()); } } - panic!("No name was found for the given nature. This should never happen."); + bail!("No name was found for the given nature. The nature may not be in the library."); } } @@ -71,6 +80,9 @@ impl ValueIdentifiable for NatureLibraryImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::expect_used)] pub mod tests { use super::*; use crate::static_data::statistics::Statistic; @@ -93,8 +105,8 @@ pub mod tests { impl NatureLibrary for NatureLibrary { fn load_nature(&mut self, name: StringKey, nature: Arc); fn get_nature(&self, key: &StringKey) -> Option>; - fn get_nature_name(&self, nature: &Arc) -> StringKey; - fn get_random_nature(&self, rand: &mut Random) -> Arc; + fn get_nature_name(&self, nature: &Arc) -> Result; + fn get_random_nature(&self, rand: &mut Random) -> Result>; } impl ValueIdentifiable for NatureLibrary { fn value_identifier(&self) -> ValueIdentifier{ @@ -134,10 +146,10 @@ pub mod tests { ); let n1 = lib.get_nature(&"foo".into()).expect("Nature was not found"); - let name = lib.get_nature_name(&n1); + let name = lib.get_nature_name(&n1).unwrap(); assert_eq!(name, "foo".into()); let n2 = lib.get_nature(&"bar".into()).expect("Nature was not found"); - let name2 = lib.get_nature_name(&n2); + let name2 = lib.get_nature_name(&n2).unwrap(); assert_eq!(name2, "bar".into()); } @@ -148,7 +160,7 @@ pub mod tests { "foo".into(), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), ); - let n1 = lib.get_random_nature(&mut Random::new(0)); + let n1 = lib.get_random_nature(&mut Random::new(0)).unwrap(); assert_eq!(n1.increased_stat(), Statistic::HP); assert_eq!(n1.decreased_stat(), Statistic::Attack); assert_eq!(n1.get_stat_modifier(n1.increased_stat()), 1.1); diff --git a/src/static_data/libraries/species_library.rs b/src/static_data/libraries/species_library.rs index 7ec367d..c050bd6 100755 --- a/src/static_data/libraries/species_library.rs +++ b/src/static_data/libraries/species_library.rs @@ -47,6 +47,8 @@ impl ValueIdentifiable for SpeciesLibraryImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub mod tests { use super::*; use crate::static_data::{FormImpl, LearnableMovesImpl, SpeciesImpl, StaticStatisticSet}; diff --git a/src/static_data/libraries/static_data.rs b/src/static_data/libraries/static_data.rs index b1aa2af..d83a829 100755 --- a/src/static_data/libraries/static_data.rs +++ b/src/static_data/libraries/static_data.rs @@ -164,6 +164,8 @@ impl ValueIdentifiable for StaticDataImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub mod test { use super::*; use crate::static_data::LibrarySettingsImpl; diff --git a/src/static_data/libraries/type_library.rs b/src/static_data/libraries/type_library.rs index cc97ed3..8bd2ab3 100755 --- a/src/static_data/libraries/type_library.rs +++ b/src/static_data/libraries/type_library.rs @@ -1,8 +1,9 @@ +use anyhow_ext::Result; use atomig::Atom; use hashbrown::HashMap; -use std::fmt::Debug; +use std::fmt::{Debug, Display}; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::{PkmnError, StringKey, ValueIdentifiable, ValueIdentifier}; /// A unique key that can be used to store a reference to a type. Opaque reference to a byte /// internally. @@ -25,6 +26,12 @@ impl From for u8 { } } +impl Display for TypeIdentifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "TypeId({})", self.val) + } +} + /// All data related to types and effectiveness. pub trait TypeLibrary: Debug + ValueIdentifiable { /// Gets the type identifier for a type with a name. @@ -34,18 +41,23 @@ pub trait TypeLibrary: Debug + ValueIdentifiable { fn get_type_name(&self, t: TypeIdentifier) -> Option; /// Gets the effectiveness for a single attacking type against a single defending type. - fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> f32; + fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> Result; /// Gets the effectiveness for a single attacking type against an amount of defending types. /// This is equivalent to running [`get_single_effectiveness`] on each defending type, and /// multiplying the results with each other. - fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> f32; + fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result; /// Registers a new type in the library. fn register_type(&mut self, name: &StringKey) -> TypeIdentifier; /// Sets the effectiveness for an attacking type against a defending type. - fn set_effectiveness(&mut self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32); + fn set_effectiveness( + &mut self, + attacking: TypeIdentifier, + defending: TypeIdentifier, + effectiveness: f32, + ) -> Result<()>; } /// All data related to types and effectiveness. @@ -87,19 +99,24 @@ impl TypeLibrary for TypeLibraryImpl { } /// Gets the effectiveness for a single attacking type against a single defending type. - fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> f32 { - self.effectiveness[(attacking.val - 1) as usize][(defending.val - 1) as usize] + fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> Result { + Ok(*self + .effectiveness + .get((attacking.val - 1) as usize) + .ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })? + .get((defending.val - 1) as usize) + .ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })?) } /// Gets the effectiveness for a single attacking type against an amount of defending types. /// This is equivalent to running [`get_single_effectiveness`] on each defending type, and /// multiplying the results with each other. - fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> f32 { + fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result { let mut e = 1.0; for def in defending { - e *= self.get_single_effectiveness(attacking, *def); + e *= self.get_single_effectiveness(attacking, *def)?; } - e + Ok(e) } /// Registers a new type in the library. @@ -116,8 +133,19 @@ impl TypeLibrary for TypeLibraryImpl { } /// Sets the effectiveness for an attacking type against a defending type. - fn set_effectiveness(&mut self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32) { - self.effectiveness[(attacking.val - 1) as usize][(defending.val - 1) as usize] = effectiveness; + fn set_effectiveness( + &mut self, + attacking: TypeIdentifier, + defending: TypeIdentifier, + effectiveness: f32, + ) -> Result<()> { + *self + .effectiveness + .get_mut((attacking.val - 1) as usize) + .ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })? + .get_mut((defending.val - 1) as usize) + .ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })? = effectiveness; + Ok(()) } } @@ -128,6 +156,8 @@ impl ValueIdentifiable for TypeLibraryImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub mod tests { use assert_approx_eq::assert_approx_eq; @@ -143,8 +173,8 @@ pub mod tests { let t1 = w.register_type(&"bar".into()); // Drops borrow as mut - w.set_effectiveness(t0, t1, 0.5); - w.set_effectiveness(t1, t0, 2.0); + w.set_effectiveness(t0, t1, 0.5).unwrap(); + w.set_effectiveness(t1, t0, 2.0).unwrap(); lib } @@ -173,14 +203,14 @@ pub mod tests { let w = &mut lib; let t0 = w.register_type(&"foo".into()); let t1 = w.register_type(&"bar".into()); - w.set_effectiveness(t0, t1, 0.5); - w.set_effectiveness(t1, t0, 2.0); + w.set_effectiveness(t0, t1, 0.5).unwrap(); + w.set_effectiveness(t1, t0, 2.0).unwrap(); // Drops borrow as mut // Borrow as read so we can read let r = &lib; - assert_approx_eq!(r.get_single_effectiveness(t0, t1), 0.5); - assert_approx_eq!(r.get_single_effectiveness(t1, t0), 2.0); + assert_approx_eq!(r.get_single_effectiveness(t0, t1).unwrap(), 0.5); + assert_approx_eq!(r.get_single_effectiveness(t1, t0).unwrap(), 2.0); } #[test] @@ -191,14 +221,14 @@ pub mod tests { let w = &mut lib; let t0 = w.register_type(&"foo".into()); let t1 = w.register_type(&"bar".into()); - w.set_effectiveness(t0, t1, 0.5); - w.set_effectiveness(t1, t0, 2.0); + w.set_effectiveness(t0, t1, 0.5).unwrap(); + w.set_effectiveness(t1, t0, 2.0).unwrap(); // Drops borrow as mut // Borrow as read so we can read let r = &lib; - assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]), 0.25); - assert_approx_eq!(r.get_effectiveness(t1, &[t0, t0]), 4.0); + assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]).unwrap(), 0.25); + assert_approx_eq!(r.get_effectiveness(t1, &[t0, t0]).unwrap(), 4.0); } #[test] diff --git a/src/static_data/moves/move_data.rs b/src/static_data/moves/move_data.rs index 6aba0d5..448a380 100755 --- a/src/static_data/moves/move_data.rs +++ b/src/static_data/moves/move_data.rs @@ -208,6 +208,8 @@ impl ValueIdentifiable for MoveDataImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; diff --git a/src/static_data/moves/secondary_effect.rs b/src/static_data/moves/secondary_effect.rs index c3f0add..a1bd59c 100755 --- a/src/static_data/moves/secondary_effect.rs +++ b/src/static_data/moves/secondary_effect.rs @@ -59,6 +59,8 @@ impl ValueIdentifiable for SecondaryEffectImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; use assert_approx_eq::assert_approx_eq; diff --git a/src/static_data/natures.rs b/src/static_data/natures.rs index d8382c8..7b273df 100755 --- a/src/static_data/natures.rs +++ b/src/static_data/natures.rs @@ -96,6 +96,8 @@ impl ValueIdentifiable for NatureImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; diff --git a/src/static_data/species_data/ability.rs b/src/static_data/species_data/ability.rs index 2251b4a..61e31db 100755 --- a/src/static_data/species_data/ability.rs +++ b/src/static_data/species_data/ability.rs @@ -70,6 +70,8 @@ pub struct AbilityIndex { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; diff --git a/src/static_data/species_data/form.rs b/src/static_data/species_data/form.rs index cb5df3a..71fbe8b 100755 --- a/src/static_data/species_data/form.rs +++ b/src/static_data/species_data/form.rs @@ -1,3 +1,4 @@ +use anyhow_ext::{ensure, Result}; use hashbrown::HashSet; use std::fmt::Debug; @@ -5,8 +6,8 @@ use crate::static_data::Statistic; use crate::static_data::TypeIdentifier; use crate::static_data::{Ability, StaticStatisticSet}; use crate::static_data::{AbilityIndex, LearnableMoves}; -use crate::StringKey; use crate::{Random, ValueIdentifiable, ValueIdentifier}; +use crate::{StringKey, VecExt}; /// A form is a variant of a specific species. A species always has at least one form, but can have /// many more. @@ -34,7 +35,7 @@ pub trait Form: ValueIdentifiable + Debug { fn flags(&self) -> &HashSet; /// Get a type of the move at a certain index. - fn get_type(&self, index: usize) -> TypeIdentifier; + fn get_type(&self, index: usize) -> Result; /// Gets a single base stat value. fn get_base_stat(&self, stat: Statistic) -> u16; @@ -42,12 +43,12 @@ pub trait Form: ValueIdentifiable + Debug { fn find_ability_index(&self, ability: &dyn Ability) -> Option; /// Gets an ability from the form. - fn get_ability(&self, index: AbilityIndex) -> &StringKey; + fn get_ability(&self, index: AbilityIndex) -> Result<&StringKey>; /// Gets a random ability from the form. - fn get_random_ability(&self, rand: &mut Random) -> &StringKey; + fn get_random_ability(&self, rand: &mut Random) -> Result<&StringKey>; /// Gets a random hidden ability from the form. - fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey; + fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<&StringKey>; /// Check if the form has a specific flag set. fn has_flag(&self, key: &StringKey) -> bool; @@ -158,8 +159,8 @@ impl Form for FormImpl { } /// Get a type of the move at a certain index. - fn get_type(&self, index: usize) -> TypeIdentifier { - self.types[index] + fn get_type(&self, index: usize) -> Result { + Ok(*self.types.get_res(index)?) } /// Gets a single base stat value. @@ -189,21 +190,25 @@ impl Form for FormImpl { } /// Gets an ability from the form. - fn get_ability(&self, index: AbilityIndex) -> &StringKey { + fn get_ability(&self, index: AbilityIndex) -> Result<&StringKey> { if index.hidden { - &self.hidden_abilities[index.index as usize] + Ok(self.hidden_abilities.get_res(index.index as usize)?) } else { - &self.abilities[index.index as usize] + Ok(self.abilities.get_res(index.index as usize)?) } } /// Gets a random ability from the form. - fn get_random_ability(&self, rand: &mut Random) -> &StringKey { - &self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize] + fn get_random_ability(&self, rand: &mut Random) -> Result<&StringKey> { + ensure!(!self.abilities.is_empty(), "No abilities on form"); + self.abilities + .get_res(rand.get_between_unsigned(0, self.abilities.len() as u32) as usize) } /// Gets a random hidden ability from the form. - fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey { - &self.hidden_abilities[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize] + fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<&StringKey> { + ensure!(!self.hidden_abilities.is_empty(), "No hidden abilities on form"); + self.hidden_abilities + .get_res(rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize) } /// Check if the form has a specific flag set. @@ -223,6 +228,8 @@ impl ValueIdentifiable for FormImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; @@ -240,12 +247,12 @@ pub(crate) mod tests { fn hidden_abilities(&self) -> &Vec; fn moves(&self) -> &Box; fn flags(&self) -> &HashSet; - fn get_type(&self, index: usize) -> TypeIdentifier; + fn get_type(&self, index: usize) -> Result; fn get_base_stat(&self, stat: Statistic) -> u16; fn find_ability_index(&self, ability: &dyn Ability) -> Option; - fn get_ability(&self, index: AbilityIndex) -> &StringKey; - fn get_random_ability(&self, rand: &mut Random) -> &StringKey; - fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey; + fn get_ability<'a>(&'a self, index: AbilityIndex) -> Result<&'a StringKey>; + fn get_random_ability<'a>(&'a self, rand: &mut Random) -> Result<&'a StringKey>; + fn get_random_hidden_ability<'a>(&'a self, rand: &mut Random) -> Result<&'a StringKey>; fn has_flag(&self, key: &StringKey) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool; } diff --git a/src/static_data/species_data/learnable_moves.rs b/src/static_data/species_data/learnable_moves.rs index b4ee6c0..63e05e2 100755 --- a/src/static_data/species_data/learnable_moves.rs +++ b/src/static_data/species_data/learnable_moves.rs @@ -1,13 +1,14 @@ +use anyhow_ext::Result; use indexmap::IndexSet; use std::fmt::Debug; use crate::defines::LevelInt; -use crate::StringKey; +use crate::{StringKey, VecExt}; /// The storage of the moves a Pokemon can learn. pub trait LearnableMoves: Debug { /// Adds a new level move the Pokemon can learn. - fn add_level_move(&mut self, level: LevelInt, m: &StringKey); + fn add_level_move(&mut self, level: LevelInt, m: &StringKey) -> Result<()>; /// Gets all moves a Pokemon can learn when leveling up to a specific level. fn get_learned_by_level(&self, level: LevelInt) -> Option<&Vec>; /// Gets the distinct moves a Pokemon can learn through leveling up. @@ -35,9 +36,10 @@ impl LearnableMovesImpl { impl LearnableMoves for LearnableMovesImpl { /// Adds a new level move the Pokemon can learn. - fn add_level_move(&mut self, level: LevelInt, m: &StringKey) { - self.learned_by_level.get_mut(level as usize).unwrap().push(m.clone()); + fn add_level_move(&mut self, level: LevelInt, m: &StringKey) -> Result<()> { + self.learned_by_level.get_mut_res(level as usize)?.push(m.clone()); self.distinct_level_moves.insert(m.clone()); + Ok(()) } /// Gets all moves a Pokemon can learn when leveling up to a specific level. @@ -52,14 +54,16 @@ impl LearnableMoves for LearnableMovesImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; #[test] fn adds_level_moves() { let mut moves = LearnableMovesImpl::new(100); - moves.add_level_move(1, &"foo".into()); - moves.add_level_move(1, &"bar".into()); + moves.add_level_move(1, &"foo".into()).unwrap(); + moves.add_level_move(1, &"bar".into()).unwrap(); let m = moves.get_learned_by_level(1u8).unwrap(); assert_eq!(m.len(), 2); @@ -71,8 +75,8 @@ pub(crate) mod tests { fn adds_two_same_moves_at_different_level() { let mut moves = LearnableMovesImpl::new(100); - moves.add_level_move(1, &"foo".into()); - moves.add_level_move(5, &"foo".into()); + moves.add_level_move(1, &"foo".into()).unwrap(); + moves.add_level_move(5, &"foo".into()).unwrap(); let m = moves.get_learned_by_level(1u8).unwrap(); assert_eq!(m.len(), 1); diff --git a/src/static_data/species_data/species.rs b/src/static_data/species_data/species.rs index 29bd86a..e920f5f 100755 --- a/src/static_data/species_data/species.rs +++ b/src/static_data/species_data/species.rs @@ -1,3 +1,4 @@ +use anyhow_ext::{anyhow, Result}; use std::fmt::Debug; use std::sync::{Arc, LazyLock}; @@ -34,7 +35,7 @@ pub trait Species: ValueIdentifiable + Debug { /// Gets a form by the hash of its name. fn get_form_by_hash(&self, name_hash: u32) -> Option>; /// Gets the form the Pokemon will have by default, if no other form is specified. - fn get_default_form(&self) -> Arc; + fn get_default_form(&self) -> Result>; /// Gets a random gender. fn get_random_gender(&self, rand: &mut Random) -> Gender; /// Check whether the Pokemon has a specific flag set. @@ -145,8 +146,13 @@ impl Species for SpeciesImpl { } /// Gets the form the Pokemon will have by default, if no other form is specified. - fn get_default_form(&self) -> Arc { - self.forms.read().get(&get_default_key()).unwrap().clone() + fn get_default_form(&self) -> Result> { + Ok(self + .forms + .read() + .get(&get_default_key()) + .ok_or(anyhow!("No default form for species"))? + .clone()) } /// Gets a random gender. @@ -177,6 +183,8 @@ impl ValueIdentifiable for SpeciesImpl { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] pub(crate) mod tests { use super::*; @@ -194,7 +202,7 @@ pub(crate) mod tests { fn add_form(&self, id: StringKey, form: Arc); fn get_form(&self, id: &StringKey) -> Option>; fn get_form_by_hash(&self, name_hash: u32) -> Option>; - fn get_default_form(&self) -> Arc; + fn get_default_form(&self) -> Result>; fn get_random_gender(&self, rand: &mut Random) -> Gender; fn has_flag(&self, key: &StringKey) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool; diff --git a/src/static_data/statistic_set.rs b/src/static_data/statistic_set.rs index 6bd32e7..d6bcb38 100755 --- a/src/static_data/statistic_set.rs +++ b/src/static_data/statistic_set.rs @@ -275,10 +275,12 @@ where T: PrimInt, { /// The lowest value a value on the set can have. + #[allow(clippy::unwrap_used)] // Should never fail pub fn min() -> T { ::from(MIN).unwrap() } /// The highest value a value on the set can have. + #[allow(clippy::unwrap_used)] // Should never fail pub fn max() -> T { ::from(MAX).unwrap() } diff --git a/src/utils/random.rs b/src/utils/random.rs index 3b7cb0f..37eb84c 100755 --- a/src/utils/random.rs +++ b/src/utils/random.rs @@ -91,6 +91,8 @@ impl Random { } #[cfg(test)] +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] mod tests { use std::hint::black_box; use test::Bencher; diff --git a/src/utils/string_key.rs b/src/utils/string_key.rs index d4d5820..158f555 100755 --- a/src/utils/string_key.rs +++ b/src/utils/string_key.rs @@ -29,6 +29,7 @@ static EMPTY: LazyLock = LazyLock::new(|| StringKey::new("")); impl StringKey { #[inline(always)] + #[allow(clippy::indexing_slicing)] // Should never fail. More efficient than using get. /// Gets the hash of a string. pub const fn get_hash(s: &str) -> u32 { let mut crc: u32 = 0xffffffff; @@ -119,6 +120,7 @@ impl Display for StringKey { } impl From<&CStr> for StringKey { + #[allow(clippy::unwrap_used)] // Fix later. fn from(s: &CStr) -> Self { StringKey::new(s.to_str().unwrap()) } diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index a511af2..fd50925 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -121,7 +121,9 @@ pub fn load_types(path: &String) -> Box { for (i, v) in record.iter().skip(1).enumerate() { let effectiveness = v.parse::().unwrap(); - type_library.set_effectiveness(offensive_type_id, ((i + 1) as u8).into(), effectiveness); + type_library + .set_effectiveness(offensive_type_id, ((i + 1) as u8).into(), effectiveness) + .unwrap(); } } type_library @@ -463,7 +465,7 @@ fn parse_moves(value: &Value, move_library: &Box) -> Box