diff --git a/src/dynamic_data/choices.rs b/src/dynamic_data/choices.rs index 2b42c3b..8a4037c 100755 --- a/src/dynamic_data/choices.rs +++ b/src/dynamic_data/choices.rs @@ -8,13 +8,10 @@ use crate::dynamic_data::Pokemon; use crate::dynamic_data::ScriptContainer; use crate::dynamic_data::{LearnedMove, ScriptWrapper}; use crate::dynamic_data::{ScriptSource, ScriptSourceData}; -use crate::{ValueIdentifiable, ValueIdentifier}; /// The data on a turn choice that should be contained in every turn choice, regardless of type. #[derive(Debug)] struct CommonChoiceData { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The user of the turn choice user: Pokemon, /// The speed of the user at the beginning of the turn. @@ -180,7 +177,6 @@ impl MoveChoice { script: Default::default(), priority: AtomicI8::new(0), choice_data: Box::new(CommonChoiceData { - identifier: Default::default(), user, speed: AtomicU32::new(speed), random_value: AtomicU32::new(0), @@ -253,7 +249,6 @@ impl ItemChoice { let speed = user.boosted_stats().speed(); Self { choice_data: Box::new(CommonChoiceData { - identifier: Default::default(), user, speed: AtomicU32::new(speed), random_value: AtomicU32::new(0), @@ -293,7 +288,6 @@ impl SwitchChoice { let speed = user.boosted_stats().speed(); Self { choice_data: Box::new(CommonChoiceData { - identifier: Default::default(), user, speed: AtomicU32::new(speed), random_value: AtomicU32::new(0), @@ -332,7 +326,6 @@ impl FleeChoice { pub fn new(user: Pokemon) -> Self { Self { choice_data: Box::new(CommonChoiceData { - identifier: Default::default(), user, speed: AtomicU32::new(0), random_value: AtomicU32::new(0), @@ -372,7 +365,6 @@ impl PassChoice { let speed = user.boosted_stats().speed(); Self { choice_data: Box::new(CommonChoiceData { - identifier: Default::default(), user, speed: AtomicU32::new(speed), random_value: AtomicU32::new(0), @@ -485,9 +477,3 @@ impl Ord for TurnChoice { } } } - -impl ValueIdentifiable for TurnChoice { - fn value_identifier(&self) -> ValueIdentifier { - self.choice_data().identifier - } -} diff --git a/src/dynamic_data/flow/choice_queue.rs b/src/dynamic_data/flow/choice_queue.rs index 54288fe..711499a 100755 --- a/src/dynamic_data/flow/choice_queue.rs +++ b/src/dynamic_data/flow/choice_queue.rs @@ -1,7 +1,7 @@ use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::Pokemon; -use crate::{script_hook, PkmnError, ValueIdentifiable, ValueIdentifier, VecExt}; +use crate::{script_hook, PkmnError, VecExt}; use anyhow::Result; use anyhow_ext::anyhow; use parking_lot::lock_api::MappedRwLockReadGuard; @@ -17,8 +17,6 @@ use std::sync::Arc; /// moves in Pokemon actively mess with this order. #[derive(Debug)] pub struct ChoiceQueue { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get /// executed. queue: RwLock>>>, @@ -31,7 +29,6 @@ impl ChoiceQueue { pub(crate) fn new(mut queue: Vec>>) -> Self { queue.sort_unstable_by(|a, b| b.cmp(a)); Self { - identifier: Default::default(), queue: RwLock::new(queue), current: AtomicUsize::new(0), } @@ -107,7 +104,7 @@ impl ChoiceQueue { // Find the index for the choice we want to move up. for index in self.current.load(Ordering::Relaxed)..queue_lock.len() { if let Some(Some(choice)) = &queue_lock.get(index) { - if pokemon.value_identifier() == choice.user().value_identifier() { + if pokemon.eq(choice.user()) { desired_index = Some(index); break; } @@ -158,12 +155,6 @@ impl ChoiceQueue { } } -impl ValueIdentifiable for ChoiceQueue { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::unwrap_used)] #[allow(clippy::indexing_slicing)] @@ -253,10 +244,7 @@ mod tests { Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), ]); let inner_queue = queue.get_queue().unwrap(); - assert_eq!( - inner_queue[0].as_ref().unwrap().user().value_identifier(), - user1.value_identifier() - ); + assert_eq!(inner_queue[0].as_ref().unwrap().user().clone(), user1); } #[test] @@ -283,15 +271,9 @@ mod tests { ]); user2.change_level_by(60).unwrap(); - assert_eq!( - user1.value_identifier(), - queue.peek().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),); queue.resort().unwrap(); - assert_eq!( - user2.value_identifier(), - queue.peek().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user2, queue.peek().unwrap().unwrap().user().clone(),); } #[test] @@ -303,20 +285,11 @@ mod tests { Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), ]); - assert_eq!( - user1.value_identifier(), - queue.peek().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),); assert!(queue.move_pokemon_choice_next(&user2).unwrap()); - assert_eq!( - user2.value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); - assert_eq!( - user1.value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user2, queue.dequeue().unwrap().unwrap().user().clone(),); + assert_eq!(user1, queue.dequeue().unwrap().unwrap().user().clone(),); } #[test] @@ -328,16 +301,10 @@ mod tests { Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), ]); - assert_eq!( - user2.value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user2, queue.dequeue().unwrap().unwrap().user().clone(),); assert!(!queue.move_pokemon_choice_next(&user2).unwrap()); - assert_eq!( - user1.value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user1, queue.dequeue().unwrap().unwrap().user().clone(),); assert!(queue.peek().unwrap().is_none()) } @@ -350,15 +317,9 @@ mod tests { Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), ]); - assert_eq!( - user1.value_identifier(), - queue.peek().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),); assert!(queue.move_pokemon_choice_next(&user1).unwrap()); - assert_eq!( - user1.value_identifier(), - queue.peek().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),); } #[test] @@ -382,27 +343,15 @@ mod tests { Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[5].clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[6].clone())))), ]); - assert_eq!( - users[0].value_identifier(), - queue.peek().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(users[0], queue.peek().unwrap().unwrap().user().clone(),); assert!(queue.move_pokemon_choice_next(&users[4]).unwrap()); - assert_eq!( - users[4].value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(users[4], queue.dequeue().unwrap().unwrap().user().clone(),); for index in 0..4 { - assert_eq!( - users[index].value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(users[index], queue.dequeue().unwrap().unwrap().user().clone(),); } for index in 5..7 { - assert_eq!( - users[index].value_identifier(), - queue.dequeue().unwrap().unwrap().user().value_identifier() - ); + assert_eq!(users[index], queue.dequeue().unwrap().unwrap().user().clone(),); } } } diff --git a/src/dynamic_data/libraries/battle_stat_calculator.rs b/src/dynamic_data/libraries/battle_stat_calculator.rs index 9990078..ef980e1 100755 --- a/src/dynamic_data/libraries/battle_stat_calculator.rs +++ b/src/dynamic_data/libraries/battle_stat_calculator.rs @@ -4,10 +4,9 @@ use std::fmt::Debug; use crate::dynamic_data::Pokemon; use crate::static_data::Statistic; use crate::static_data::StatisticSet; -use crate::{ValueIdentifiable, ValueIdentifier}; /// A battle stat calculator is used to calculate stats for a Pokemon. -pub trait BattleStatCalculator: Debug + ValueIdentifiable { +pub trait BattleStatCalculator: Debug { /// Calculate all the flat stats of a Pokemon, disregarding stat boosts. fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet) -> Result<()>; /// Calculate a single flat stat of a Pokemon, disregarding stat boost @@ -20,10 +19,7 @@ pub trait BattleStatCalculator: Debug + ValueIdentifiable { /// A basic implementation of the Gen 7 stat calculator. #[derive(Debug)] -pub struct Gen7BattleStatCalculator { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, -} +pub struct Gen7BattleStatCalculator {} impl Default for Gen7BattleStatCalculator { fn default() -> Self { @@ -34,9 +30,7 @@ impl Default for Gen7BattleStatCalculator { impl Gen7BattleStatCalculator { /// Creates a new Gen 7 battle stat calculator pub fn new() -> Self { - Self { - identifier: Default::default(), - } + Self {} } /// The calculation used for health points. @@ -141,11 +135,6 @@ impl BattleStatCalculator for Gen7BattleStatCalculator { } } -impl ValueIdentifiable for Gen7BattleStatCalculator { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} #[cfg(test)] #[allow(clippy::indexing_slicing)] pub mod tests { @@ -160,10 +149,5 @@ pub mod tests { fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet) -> Result<()>; fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> Result; } - impl ValueIdentifiable for BattleStatCalculator { - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } - } } } diff --git a/src/dynamic_data/libraries/damage_library.rs b/src/dynamic_data/libraries/damage_library.rs index 964e286..f190d1c 100755 --- a/src/dynamic_data/libraries/damage_library.rs +++ b/src/dynamic_data/libraries/damage_library.rs @@ -5,12 +5,12 @@ use std::sync::Arc; use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::{Battle, Pokemon}; use crate::dynamic_data::{ExecutingMove, HitData}; +use crate::script_hook; use crate::static_data::{MoveCategory, Statistic}; -use crate::{script_hook, ValueIdentifiable, ValueIdentifier}; /// A damage library holds the functions related to the calculation of damage. As this can change in /// different generations and implementations, this is handled through a trait. -pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { +pub trait DamageLibrary: std::fmt::Debug { /// Calculate the damage for a given hit on a Pokemon. fn get_damage( &self, @@ -42,8 +42,6 @@ pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { /// The implementation of a Damage Library for generation 7. #[derive(Debug)] pub struct Gen7DamageLibrary { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// Defines whether or not a random damage modifier is applied to damage (0.85 - 1.00). has_randomness: bool, } @@ -52,10 +50,7 @@ impl Gen7DamageLibrary { /// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage /// modifier (0.85x - 1.00x) is applied to the calculated damage. pub fn new(has_randomness: bool) -> Self { - Self { - identifier: Default::default(), - has_randomness, - } + Self { has_randomness } } /// Calculates the modifier applied to damage from the statistics of the relevant Pokemon. @@ -312,9 +307,3 @@ impl DamageLibrary for Gen7DamageLibrary { }) } } - -impl ValueIdentifiable for Gen7DamageLibrary { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/dynamic_data/libraries/dynamic_library.rs b/src/dynamic_data/libraries/dynamic_library.rs index bb386e0..149adc9 100755 --- a/src/dynamic_data/libraries/dynamic_library.rs +++ b/src/dynamic_data/libraries/dynamic_library.rs @@ -10,11 +10,11 @@ use crate::dynamic_data::{ItemScript, ScriptResolver}; use crate::dynamic_data::{Script, ScriptOwnerData}; use crate::static_data::Item; use crate::static_data::StaticData; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// The dynamic library stores a static data library, as well as holding different libraries and /// calculators that might be customized between different generations and implementations. -pub trait DynamicLibrary: Debug + ValueIdentifiable { +pub trait DynamicLibrary: Debug + Send + Sync { /// The static data is the immutable storage data for this library. fn static_data(&self) -> &Arc; /// The stat calculator deals with the calculation of flat and boosted stats, based on the @@ -39,13 +39,10 @@ pub trait DynamicLibrary: Debug + ValueIdentifiable { /// shared between all different usages. fn load_item_script(&self, _key: &Arc) -> Result>>; } - /// The dynamic library stores a static data library, as well as holding different libraries and /// calculators that might be customized between different generations and implementations. #[derive(Debug)] pub struct DynamicLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The static data is the immutable storage data for this library. static_data: Arc, /// The stat calculator deals with the calculation of flat and boosted stats, based on the @@ -58,9 +55,13 @@ pub struct DynamicLibraryImpl { misc_library: Arc, /// The script resolver deals with how to resolve the scripts from specific unique key combinations. - script_resolver: Box, + script_resolver: Arc, } +unsafe impl Send for DynamicLibraryImpl {} + +unsafe impl Sync for DynamicLibraryImpl {} + impl DynamicLibraryImpl { /// Instantiates a new DynamicLibrary with given parameters. pub fn new( @@ -68,10 +69,9 @@ impl DynamicLibraryImpl { stat_calculator: Arc, damage_calculator: Arc, misc_library: Arc, - script_resolver: Box, + script_resolver: Arc, ) -> Self { Self { - identifier: Default::default(), static_data, stat_calculator, damage_calculator, @@ -120,12 +120,6 @@ impl DynamicLibrary for DynamicLibraryImpl { } } -impl ValueIdentifiable for DynamicLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] pub mod test { @@ -138,6 +132,10 @@ pub mod test { mockall::mock! { #[derive(Debug)] pub DynamicLibrary{} + + unsafe impl Send for DynamicLibrary{} + unsafe impl Sync for DynamicLibrary{} + impl DynamicLibrary for DynamicLibrary { fn static_data(&self) -> &Arc; fn stat_calculator(&self) -> &Arc; @@ -151,23 +149,15 @@ pub mod test { ) -> Result>>; fn load_item_script(&self, _key: &Arc) -> Result>>; } - impl ValueIdentifiable for DynamicLibrary{ - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } - } } pub fn build() -> DynamicLibraryImpl { DynamicLibraryImpl { - identifier: Default::default(), static_data: Arc::new(crate::static_data::libraries::static_data::test::build()), stat_calculator: Arc::new(Gen7BattleStatCalculator::new()), damage_calculator: Arc::new(Gen7DamageLibrary::new(false)), misc_library: Arc::new(Gen7MiscLibrary::new()), - script_resolver: Box::new(EmptyScriptResolver { - identifier: Default::default(), - }), + script_resolver: Arc::new(EmptyScriptResolver {}), } } } diff --git a/src/dynamic_data/libraries/misc_library.rs b/src/dynamic_data/libraries/misc_library.rs index 8997ac8..48a6872 100755 --- a/src/dynamic_data/libraries/misc_library.rs +++ b/src/dynamic_data/libraries/misc_library.rs @@ -7,10 +7,10 @@ use crate::dynamic_data::choices::{MoveChoice, TurnChoice}; use crate::dynamic_data::Pokemon; use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; use crate::static_data::{MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffectImpl}; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// The misc library holds several misc functions required for the battle to run. -pub trait MiscLibrary: Debug + ValueIdentifiable { +pub trait MiscLibrary: Debug { /// Returns whether or not a Pokemon is allowed to flee or switch out. fn can_flee(&self, choice: &TurnChoice) -> bool; /// Returns the move we need to use if we can't use another move. Typically Struggle. @@ -22,8 +22,6 @@ pub trait MiscLibrary: Debug + ValueIdentifiable { /// A gen 7 implementation for the MiscLibrary. #[derive(Debug)] pub struct Gen7MiscLibrary { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The learned move data for struggle. struggle_learned_move: Arc, } @@ -40,7 +38,7 @@ impl Gen7MiscLibrary { 255, MoveTarget::Any, 0, - Some(Box::new(SecondaryEffectImpl::new( + Some(Arc::new(SecondaryEffectImpl::new( -1.0, StringKey::new("struggle"), vec![], @@ -48,10 +46,7 @@ impl Gen7MiscLibrary { HashSet::new(), )); let struggle_learned_move = Arc::new(LearnedMove::new(struggle_data, MoveLearnMethod::Unknown)); - Self { - identifier: Default::default(), - struggle_learned_move, - } + Self { struggle_learned_move } } } @@ -76,9 +71,3 @@ impl MiscLibrary for Gen7MiscLibrary { )) } } - -impl ValueIdentifiable for Gen7MiscLibrary { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/dynamic_data/libraries/script_resolver.rs b/src/dynamic_data/libraries/script_resolver.rs index f833736..44ff61a 100755 --- a/src/dynamic_data/libraries/script_resolver.rs +++ b/src/dynamic_data/libraries/script_resolver.rs @@ -1,15 +1,16 @@ use anyhow::Result; +use std::any::Any; use std::fmt::Debug; use std::sync::Arc; use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData}; use crate::static_data::Item; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// A script resolver deals with the resolving of scripts. These scripts are non-hardcoded /// implementations of different effects in Pokemon. This allows for things such as generational /// differences, and custom implementations. -pub trait ScriptResolver: Debug + ValueIdentifiable { +pub trait ScriptResolver: Debug { /// Loads a standard script with a given unique combination of category and key. If no script /// can be created with this combination, returns None. fn load_script( @@ -23,6 +24,8 @@ pub trait ScriptResolver: Debug + ValueIdentifiable { /// combinations, returns None. Note that ItemScripts are immutable, as their script should be /// shared between all different usages. fn load_item_script(&self, _key: &dyn Item) -> Result>>; + + fn as_any(&self) -> &dyn std::any::Any; } use std::fmt::Display; @@ -57,16 +60,7 @@ pub enum ScriptCategory { /// A basic empty script resolver, that always returns None. #[derive(Debug, Default)] -pub struct EmptyScriptResolver { - /// A unique identifier so we know what value this is. - pub identifier: ValueIdentifier, -} - -impl ValueIdentifiable for EmptyScriptResolver { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} +pub struct EmptyScriptResolver {} impl ScriptResolver for EmptyScriptResolver { fn load_script( @@ -81,4 +75,8 @@ impl ScriptResolver for EmptyScriptResolver { fn load_item_script(&self, _key: &dyn Item) -> Result>> { Ok(None) } + + fn as_any(&self) -> &dyn Any { + self + } } diff --git a/src/dynamic_data/models/battle.rs b/src/dynamic_data/models/battle.rs index b750b7f..86f714d 100755 --- a/src/dynamic_data/models/battle.rs +++ b/src/dynamic_data/models/battle.rs @@ -21,13 +21,11 @@ use crate::dynamic_data::VolatileScriptsOwner; use crate::dynamic_data::{is_valid_target, ScriptWrapper}; use crate::dynamic_data::{ChoiceQueue, ScriptContainer}; use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData}; -use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; +use crate::{script_hook, PkmnError, StringKey, VecExt}; /// The data of a battle. #[derive(Debug)] struct BattleData { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The library the battle uses for handling. library: Arc, /// A list of all different parties in the battle. @@ -99,7 +97,6 @@ impl Battle { } let battle = BattleData { - identifier: Default::default(), library, parties, can_flee, @@ -127,13 +124,6 @@ impl Battle { battle } - /// Returns a weak reference to the battle. - pub fn weak(&self) -> WeakBattleReference { - WeakBattleReference { - data: Arc::downgrade(&self.data), - } - } - /// The library the battle uses for handling. pub fn library(&self) -> &Arc { &self.data.library @@ -272,7 +262,7 @@ impl Battle { } /// Try and set the choice for the battle. If the choice is not valid, this returns false. - pub fn try_set_choice(&self, choice: TurnChoice) -> Result { + pub fn try_set_choice(&self, choice: Arc) -> Result { if !self.can_use(&choice) { return Ok(false); } @@ -380,6 +370,23 @@ impl Battle { Ok(None) } } + + /// Returns a weak reference to the battle. + pub fn weak(&self) -> WeakBattleReference { + WeakBattleReference { + data: Arc::downgrade(&self.data), + } + } + + pub fn as_ptr(&self) -> *const c_void { + Arc::as_ptr(&self.data) as *const c_void + } +} + +impl PartialEq for Battle { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.data, &other.data) + } } impl WeakBattleReference { @@ -437,12 +444,6 @@ impl ScriptSource for Battle { } } -impl ValueIdentifiable for Battle { - fn value_identifier(&self) -> ValueIdentifier { - self.data.identifier - } -} - /// The result of a battle. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum BattleResult { diff --git a/src/dynamic_data/models/battle_party.rs b/src/dynamic_data/models/battle_party.rs index d61c84c..37c6f4f 100755 --- a/src/dynamic_data/models/battle_party.rs +++ b/src/dynamic_data/models/battle_party.rs @@ -3,14 +3,11 @@ use std::sync::Arc; use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon_party::PokemonParty; -use crate::{ValueIdentifiable, ValueIdentifier}; /// A battle party is a wrapper around a party, with the indices for which the party is responsible /// on the field attached. #[derive(Debug)] pub struct BattleParty { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The party the BattleParty is holding. party: Arc, /// The indices for which the party is responsible, in the format (side, index) @@ -22,7 +19,6 @@ impl BattleParty { /// for. pub fn new(party: Arc, responsible_indices: Vec<(u8, u8)>) -> Result { Ok(Self { - identifier: Default::default(), party, responsible_indices, }) @@ -58,9 +54,3 @@ impl BattleParty { &self.party } } - -impl ValueIdentifiable for BattleParty { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/dynamic_data/models/battle_random.rs b/src/dynamic_data/models/battle_random.rs index 0d2c5dc..08d1c4e 100755 --- a/src/dynamic_data/models/battle_random.rs +++ b/src/dynamic_data/models/battle_random.rs @@ -6,13 +6,11 @@ use crate::dynamic_data::models::executing_move::ExecutingMove; use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::script_handling::ScriptSource; use crate::utils::Random; -use crate::{script_hook, PkmnError, ValueIdentifiable, ValueIdentifier}; +use crate::{script_hook, PkmnError}; /// The RNG for a battle. #[derive(Default)] pub struct BattleRandom { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The actual underlying RNG. This is in a mutex, so it is thread safe, and can be ran /// predictably, with guaranteed the same outputs. random: Mutex, @@ -22,7 +20,6 @@ impl BattleRandom { /// Initializes a new RNG with a given seed. pub fn new_with_seed(seed: u128) -> Self { BattleRandom { - identifier: Default::default(), random: Mutex::new(Random::new(seed)), } } @@ -104,8 +101,6 @@ impl Debug for BattleRandom { impl Clone for BattleRandom { fn clone(&self) -> Self { Self { - identifier: Default::default(), - // As cloning when we can't get a lock on the randomness is completely impossible, we // should unwrap here. #[allow(clippy::unwrap_used)] @@ -113,9 +108,3 @@ impl Clone for BattleRandom { } } } - -impl ValueIdentifiable for BattleRandom { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/dynamic_data/models/battle_side.rs b/src/dynamic_data/models/battle_side.rs index 635d2b3..208f7ca 100755 --- a/src/dynamic_data/models/battle_side.rs +++ b/src/dynamic_data/models/battle_side.rs @@ -15,13 +15,11 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip use crate::dynamic_data::ScriptSet; use crate::dynamic_data::VolatileScriptsOwner; use crate::dynamic_data::{Script, WeakBattleReference}; -use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; +use crate::{script_hook, StringKey, VecExt}; /// The data that is stored for a battle side. #[derive(Debug)] struct BattleSideData { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The index of the side on the battle. index: u8, /// The number of Pokemon that can be on the side. @@ -47,7 +45,7 @@ struct BattleSideData { } /// A side on a battle. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BattleSide { /// The data that is stored for this side. data: Arc, @@ -77,7 +75,6 @@ impl BattleSide { Self { data: Arc::new(BattleSideData { - identifier: Default::default(), index, pokemon_per_side, pokemon, @@ -171,11 +168,11 @@ impl BattleSide { } /// Sets a choice for a Pokemon on this side. - pub(crate) fn set_choice(&self, choice: TurnChoice) -> Result<()> { + pub(crate) fn set_choice(&self, choice: Arc) -> Result<()> { for (index, pokemon_slot) in self.data.pokemon.read().iter().enumerate() { if let Some(pokemon) = pokemon_slot { if Pokemon::eq(pokemon, choice.user()) { - self.data.choices.write().get_mut_res(index)?.replace(choice.into()); + self.data.choices.write().get_mut_res(index)?.replace(choice); self.data.choices_set.fetch_add(1, Ordering::SeqCst); return Ok(()); } @@ -337,7 +334,7 @@ impl BattleSide { None => return Ok(false), }; // Don't allow swapping if different parties are responsible for the indices. - if party_a.value_identifier() != party_b.value_identifier() { + if !Arc::ptr_eq(party_a, party_b) { return Ok(false); } @@ -356,6 +353,16 @@ impl BattleSide { data: Arc::downgrade(&self.data), } } + + pub fn as_ptr(&self) -> *const c_void { + Arc::as_ptr(&self.data) as *const c_void + } +} + +impl PartialEq for BattleSide { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.data, &other.data) + } } impl WeakBattleSideReference { @@ -411,9 +418,3 @@ impl ScriptSource for BattleSide { self.battle()?.collect_scripts(scripts) } } - -impl ValueIdentifiable for BattleSide { - fn value_identifier(&self) -> ValueIdentifier { - self.data.identifier - } -} diff --git a/src/dynamic_data/models/executing_move.rs b/src/dynamic_data/models/executing_move.rs index 47a7caa..b962995 100755 --- a/src/dynamic_data/models/executing_move.rs +++ b/src/dynamic_data/models/executing_move.rs @@ -12,13 +12,11 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip use crate::dynamic_data::ScriptContainer; use crate::dynamic_data::TargetList; use crate::static_data::{MoveData, TypeIdentifier}; -use crate::{PkmnError, ValueIdentifiable, ValueIdentifier}; +use crate::PkmnError; /// A hit data is the data for a single hit, on a single target. #[derive(Default, Debug)] pub struct HitData { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// Whether or not the hit is critical. critical: AtomicBool, /// The base power of the hit. @@ -89,8 +87,6 @@ impl HitData { #[derive(Debug)] pub struct ExecutingMove { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The number of hits this move has. number_of_hits: u8, /// A list of hits for this move. For multi target multi hit moves, this stores the hits linearly, @@ -126,7 +122,6 @@ impl ExecutingMove { hits.push(Arc::new(HitData::default())) } Self { - identifier: Default::default(), number_of_hits, hits, user, @@ -238,15 +233,3 @@ impl ScriptSource for ExecutingMove { Ok(()) } } - -impl ValueIdentifiable for ExecutingMove { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - -impl ValueIdentifiable for HitData { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/dynamic_data/models/learned_move.rs b/src/dynamic_data/models/learned_move.rs index e6bdf84..dd8f49c 100755 --- a/src/dynamic_data/models/learned_move.rs +++ b/src/dynamic_data/models/learned_move.rs @@ -2,14 +2,11 @@ use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::Arc; use crate::static_data::MoveData; -use crate::{ValueIdentifiable, ValueIdentifier}; /// A learned move is the data attached to a Pokemon for a move it has learned. It has information /// such as the remaining amount of users, how it has been learned, etc. #[derive(Debug)] pub struct LearnedMove { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The immutable move information of the move. move_data: Arc, /// The maximal power points for this move. @@ -36,7 +33,6 @@ impl LearnedMove { pub fn new(move_data: Arc, learn_method: MoveLearnMethod) -> Self { let max_pp = move_data.base_usages(); Self { - identifier: Default::default(), move_data, max_pp, remaining_pp: AtomicU8::new(max_pp), @@ -92,12 +88,6 @@ impl LearnedMove { } } -impl ValueIdentifiable for LearnedMove { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::unwrap_used)] mod tests { diff --git a/src/dynamic_data/models/pokemon.rs b/src/dynamic_data/models/pokemon.rs index 79751a9..d1fe708 100755 --- a/src/dynamic_data/models/pokemon.rs +++ b/src/dynamic_data/models/pokemon.rs @@ -26,13 +26,11 @@ use crate::static_data::TypeIdentifier; use crate::static_data::{Ability, Statistic}; use crate::static_data::{ClampedStatisticSet, StatisticSet}; use crate::utils::Random; -use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; +use crate::{script_hook, PkmnError, StringKey, VecExt}; use anyhow::{anyhow, bail, Result}; /// The data of a Pokemon. struct PokemonData { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The library data of the Pokemon. library: Arc, /// The species of the Pokemon. @@ -165,7 +163,6 @@ impl Pokemon { .get_nature(nature) .ok_or(PkmnError::InvalidNatureName { nature: nature.clone() })?; let pokemon_data = PokemonData { - identifier: Default::default(), library, species: RwLock::new(species), form: RwLock::new(form.clone()), @@ -546,7 +543,7 @@ impl Pokemon { /// Change the form of the Pokemon. pub fn change_form(&self, form: &Arc) -> Result<()> { - if self.form().value_identifier() == form.value_identifier() { + if Arc::ptr_eq(&self.form(), form) { return Ok(()); } *self.data.form.write() = form.clone(); @@ -818,6 +815,10 @@ impl Pokemon { data: Arc::downgrade(&self.data), } } + + pub fn as_ptr(&self) -> *const c_void { + Arc::as_ptr(&self.data) as *const c_void + } } impl PartialEq for Pokemon { @@ -938,12 +939,6 @@ impl VolatileScriptsOwner for Pokemon { } } -impl ValueIdentifiable for Pokemon { - fn value_identifier(&self) -> ValueIdentifier { - self.data.identifier - } -} - /// A source of damage. This should be as unique as possible. #[derive(Debug, Clone, Copy)] #[repr(u8)] diff --git a/src/dynamic_data/models/pokemon_party.rs b/src/dynamic_data/models/pokemon_party.rs index 98a7e6e..db4d2b7 100755 --- a/src/dynamic_data/models/pokemon_party.rs +++ b/src/dynamic_data/models/pokemon_party.rs @@ -3,13 +3,11 @@ use parking_lot::lock_api::RwLockReadGuard; use parking_lot::{RawRwLock, RwLock}; use crate::dynamic_data::models::pokemon::Pokemon; -use crate::{ValueIdentifiable, ValueIdentifier, VecExt}; +use crate::VecExt; /// A list of Pokemon belonging to a trainer. #[derive(Debug)] pub struct PokemonParty { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying list of Pokemon. pokemon: RwLock>>, } @@ -22,7 +20,6 @@ impl PokemonParty { pokemon.push(None); } Self { - identifier: Default::default(), pokemon: RwLock::new(pokemon), } } @@ -30,7 +27,6 @@ impl PokemonParty { /// Instantiates a party with a list. pub fn new_from_vec(pokemon: Vec>) -> Self { Self { - identifier: Default::default(), pokemon: RwLock::new(pokemon), } } @@ -118,9 +114,3 @@ impl PokemonParty { false } } - -impl ValueIdentifiable for PokemonParty { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/ffi/dynamic_data/choices.rs b/src/ffi/dynamic_data/choices.rs index 5a19a0c..b05cf2a 100644 --- a/src/ffi/dynamic_data/choices.rs +++ b/src/ffi/dynamic_data/choices.rs @@ -1,105 +1,102 @@ use crate::dynamic_data::{FleeChoice, LearnedMove, MoveChoice, PassChoice, Pokemon, TurnChoice}; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use anyhow::anyhow; -use std::ptr::drop_in_place; +use std::ops::Deref; use std::sync::Arc; -/// Disposes a turn choice. -#[no_mangle] -extern "C" fn turn_choice_drop(choice: OwnedPtr) { - unsafe { drop_in_place(choice) } -} - /// Get the user of the given choice. #[no_mangle] -extern "C" fn turn_choice_user(choice: ExternPointer) -> IdentifiablePointer { - choice.as_ref().user().clone().into() +extern "C" fn turn_choice_user(choice: FFIHandle>) -> FFIHandle { + FFIHandle::get_handle(choice.from_ffi_handle().user().clone().into()) } /// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon /// at the start of the turn! #[no_mangle] -extern "C" fn turn_choice_speed(choice: ExternPointer) -> u32 { - choice.as_ref().speed() +extern "C" fn turn_choice_speed(choice: FFIHandle>) -> u32 { + choice.from_ffi_handle().speed() } /// Gets whether or not the choice has failed. If we notice this when we execute the choice, we /// will not execute it. #[no_mangle] -extern "C" fn turn_choice_has_failed(choice: ExternPointer) -> u8 { - u8::from(choice.as_ref().has_failed()) +extern "C" fn turn_choice_has_failed(choice: FFIHandle>) -> u8 { + u8::from(choice.from_ffi_handle().has_failed()) } /// Fails the choice. This will prevent it from executing and run a specific fail handling during /// execution. Note that this can not be undone. #[no_mangle] -extern "C" fn turn_choice_fail(choice: ExternPointer) { - choice.as_ref().fail() +extern "C" fn turn_choice_fail(choice: FFIHandle>) { + choice.from_ffi_handle().fail() } /// Creates a new Turn Choice with a move to use. #[no_mangle] extern "C" fn turn_choice_move_new( - user: ExternPointer, - learned_move: ExternPointer>, + user: FFIHandle, + learned_move: FFIHandle>, target_side: u8, target_index: u8, -) -> IdentifiablePointer { - Box::new(TurnChoice::Move(MoveChoice::new( - user.as_ref().clone(), - learned_move.as_ref().clone(), - target_side, - target_index, - ))) - .into() +) -> FFIHandle> { + FFIHandle::get_handle( + Arc::new(TurnChoice::Move(MoveChoice::new( + user.from_ffi_handle(), + learned_move.from_ffi_handle(), + target_side, + target_index, + ))) + .into(), + ) } /// The actual learned move on the Pokemon we use for this choice. #[no_mangle] extern "C" fn turn_choice_move_learned_move( - choice: ExternPointer, -) -> NativeResult>> { - if let TurnChoice::Move(c) = choice.as_ref() { - return NativeResult::ok(c.used_move().clone().into()); + choice: FFIHandle>, +) -> FFIResult>> { + if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() { + return FFIResult::ok(FFIHandle::get_handle(c.used_move().clone().into())); } - NativeResult::err(anyhow!("Turn choice was not a learned move")) + FFIResult::err(anyhow!("Turn choice was not a learned move")) } /// The target side the move is aimed at. #[no_mangle] -extern "C" fn turn_choice_move_target_side(choice: ExternPointer) -> NativeResult { - if let TurnChoice::Move(c) = choice.as_ref() { - return NativeResult::ok(c.target_side()); +extern "C" fn turn_choice_move_target_side(choice: FFIHandle>) -> FFIResult { + if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() { + return FFIResult::ok(c.target_side()); } - NativeResult::err(anyhow!("Turn choice was not a learned move")) + FFIResult::err(anyhow!("Turn choice was not a learned move")) } /// The Pokemon index on the side we're aiming at. #[no_mangle] -extern "C" fn turn_choice_move_target_index(choice: ExternPointer) -> NativeResult { - if let TurnChoice::Move(c) = choice.as_ref() { - return NativeResult::ok(c.target_index()); +extern "C" fn turn_choice_move_target_index(choice: FFIHandle>) -> FFIResult { + if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() { + return FFIResult::ok(c.target_index()); } - NativeResult::err(anyhow!("Turn choice was not a learned move")) + FFIResult::err(anyhow!("Turn choice was not a learned move")) } /// The priority of the move choice at the beginning of the turn. #[no_mangle] -extern "C" fn turn_choice_move_priority(choice: ExternPointer) -> NativeResult { - if let TurnChoice::Move(c) = choice.as_ref() { - return NativeResult::ok(c.priority()); +extern "C" fn turn_choice_move_priority(choice: FFIHandle>) -> FFIResult { + if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() { + return FFIResult::ok(c.priority()); } - NativeResult::err(anyhow!("Turn choice was not a learned move")) + FFIResult::err(anyhow!("Turn choice was not a learned move")) } /// Creates a new Turn Choice for the user to flee. #[no_mangle] -extern "C" fn turn_choice_flee_new(user: ExternPointer) -> IdentifiablePointer { - Box::new(TurnChoice::Flee(FleeChoice::new(user.as_ref().clone()))).into() +extern "C" fn turn_choice_flee_new(user: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(Arc::new(TurnChoice::Flee(FleeChoice::new(user.from_ffi_handle()))).into()) } /// Creates a new Turn Choice for the user to pass the turn. #[no_mangle] -extern "C" fn turn_choice_pass_new(user: ExternPointer) -> IdentifiablePointer { - Box::new(TurnChoice::Pass(PassChoice::new(user.as_ref().clone()))).into() +extern "C" fn turn_choice_pass_new(user: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(Arc::new(TurnChoice::Pass(PassChoice::new(user.from_ffi_handle()))).into()) } diff --git a/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs b/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs index 16bd6e5..fad1571 100644 --- a/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs +++ b/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs @@ -1,63 +1,61 @@ use crate::dynamic_data::{BattleStatCalculator, Gen7BattleStatCalculator, Pokemon}; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{ExternPointer, FFIResult}; use crate::static_data::{Statistic, StatisticSet}; -use std::ptr::drop_in_place; +use std::ops::Deref; +use std::sync::Arc; /// Creates a new Gen 7 battle stat calculator #[no_mangle] -extern "C" fn gen_7_battle_stat_calculator_new() -> IdentifiablePointer> { - let v: Box = Box::new(Gen7BattleStatCalculator::new()); - let id = v.value_identifier(); - let ptr = Box::into_raw(Box::new(v)); - IdentifiablePointer::new(ptr, id) -} - -/// Drops a battle stat calculator. -#[no_mangle] -extern "C" fn battle_stat_calculator_drop(ptr: OwnedPtr>) { - unsafe { drop_in_place(ptr) }; +extern "C" fn gen_7_battle_stat_calculator_new() -> FFIHandle> { + let v: Arc = Arc::new(Gen7BattleStatCalculator::new()); + FFIHandle::get_handle(v.into()) } /// Calculate all the flat stats of a Pokemon, disregarding stat boosts. #[no_mangle] extern "C" fn battle_stat_calculator_calculate_flat_stats( - ptr: ExternPointer>, + ptr: FFIHandle>, pokemon: ExternPointer, - mut stats: ExternPointer>>, -) -> NativeResult<()> { - ptr.as_ref() - .calculate_flat_stats(pokemon.as_ref(), stats.as_mut()) + stats: FFIHandle>>, +) -> FFIResult<()> { + ptr.from_ffi_handle() + .calculate_flat_stats(pokemon.as_ref(), stats.from_ffi_handle().deref()) .into() } /// Calculate a single flat stat of a Pokemon, disregarding stat boost #[no_mangle] extern "C" fn battle_stat_calculator_calculate_flat_stat( - ptr: ExternPointer>, - pokemon: ExternPointer, + ptr: FFIHandle>, + pokemon: FFIHandle, stat: Statistic, -) -> NativeResult { - ptr.as_ref().calculate_flat_stat(pokemon.as_ref(), stat).into() +) -> FFIResult { + ptr.from_ffi_handle() + .calculate_flat_stat(&pokemon.from_ffi_handle(), stat) + .into() } /// Calculate all the boosted stats of a Pokemon, including stat boosts. #[no_mangle] extern "C" fn battle_stat_calculator_calculate_boosted_stats( - ptr: ExternPointer>, - pokemon: ExternPointer, - mut stats: ExternPointer>>, -) -> NativeResult<()> { - ptr.as_ref() - .calculate_boosted_stats(pokemon.as_ref(), stats.as_mut()) + ptr: FFIHandle>, + pokemon: FFIHandle, + stats: FFIHandle>>, +) -> FFIResult<()> { + ptr.from_ffi_handle() + .calculate_boosted_stats(&pokemon.from_ffi_handle(), stats.from_ffi_handle().deref()) .into() } /// Calculate a single boosted stat of a Pokemon, including stat boosts. #[no_mangle] extern "C" fn battle_stat_calculator_calculate_boosted_stat( - ptr: ExternPointer>, - pokemon: ExternPointer, + ptr: FFIHandle>, + pokemon: FFIHandle, stat: Statistic, -) -> NativeResult { - ptr.as_ref().calculate_boosted_stat(pokemon.as_ref(), stat).into() +) -> FFIResult { + ptr.from_ffi_handle() + .calculate_boosted_stat(&pokemon.from_ffi_handle(), stat) + .into() } diff --git a/src/ffi/dynamic_data/libraries/damage_library.rs b/src/ffi/dynamic_data/libraries/damage_library.rs index ac26f52..4199194 100644 --- a/src/ffi/dynamic_data/libraries/damage_library.rs +++ b/src/ffi/dynamic_data/libraries/damage_library.rs @@ -1,19 +1,11 @@ use crate::dynamic_data::{DamageLibrary, Gen7DamageLibrary}; -use crate::ffi::{IdentifiablePointer, OwnedPtr}; -use std::ptr::drop_in_place; +use crate::ffi::ffi_handle::FFIHandle; +use std::sync::Arc; /// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage /// modifier (0.85x - 1.00x) is applied to the calculated damage. #[no_mangle] -extern "C" fn gen_7_damage_library_new(has_randomness: u8) -> IdentifiablePointer> { - let v: Box = Box::new(Gen7DamageLibrary::new(has_randomness == 1)); - let id = v.value_identifier(); - let ptr = Box::into_raw(Box::new(v)); - IdentifiablePointer::new(ptr, id) -} - -/// Drops a DamageLibrary. -#[no_mangle] -extern "C" fn damage_library_drop(ptr: OwnedPtr>) { - unsafe { drop_in_place(ptr) }; +extern "C" fn gen_7_damage_library_new(has_randomness: u8) -> FFIHandle> { + let v: Arc = Arc::new(Gen7DamageLibrary::new(has_randomness == 1)); + FFIHandle::get_handle(v.into()) } diff --git a/src/ffi/dynamic_data/libraries/dynamic_library.rs b/src/ffi/dynamic_data/libraries/dynamic_library.rs index 5729101..b6fd483 100644 --- a/src/ffi/dynamic_data/libraries/dynamic_library.rs +++ b/src/ffi/dynamic_data/libraries/dynamic_library.rs @@ -1,68 +1,59 @@ use crate::dynamic_data::{ BattleStatCalculator, DamageLibrary, DynamicLibrary, DynamicLibraryImpl, MiscLibrary, ScriptResolver, }; -use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::static_data::StaticData; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new DynamicLibrary with given parameters. #[no_mangle] extern "C" fn dynamic_library_new( - static_data: OwnedPtr>, - stat_calculator: OwnedPtr>, - damage_library: OwnedPtr>, - misc_library: OwnedPtr>, - script_resolver: OwnedPtr>, -) -> IdentifiablePointer> { - unsafe { - let a: Arc = Arc::new(DynamicLibraryImpl::new( - static_data.read(), - stat_calculator.read(), - damage_library.read(), - misc_library.read(), - *Box::from_raw(script_resolver), - )); - a.into() - } -} - -/// Drops a dynamic library. -#[no_mangle] -extern "C" fn dynamic_library_drop(ptr: OwnedPtr>) { - unsafe { drop_in_place(ptr) }; + static_data: FFIHandle>, + stat_calculator: FFIHandle>, + damage_library: FFIHandle>, + misc_library: FFIHandle>, + script_resolver: FFIHandle>, +) -> FFIHandle> { + let a: Arc = Arc::new(DynamicLibraryImpl::new( + static_data.from_ffi_handle(), + stat_calculator.from_ffi_handle(), + damage_library.from_ffi_handle(), + misc_library.from_ffi_handle(), + script_resolver.from_ffi_handle(), + )); + FFIHandle::get_handle(a.into()) } /// The static data is the immutable storage data for this library. #[no_mangle] extern "C" fn dynamic_library_get_static_data( - ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().static_data().clone().into() + ptr: FFIHandle>, +) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().static_data().clone().into()) } /// The stat calculator deals with the calculation of flat and boosted stats, based on the /// Pokemons attributes. #[no_mangle] extern "C" fn dynamic_library_get_stat_calculator( - ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().stat_calculator().clone().into() + ptr: FFIHandle>, +) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().stat_calculator().clone().into()) } /// The damage calculator deals with the calculation of things relating to damage. #[no_mangle] extern "C" fn dynamic_library_get_damage_calculator( - ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().damage_calculator().clone().into() + ptr: FFIHandle>, +) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().damage_calculator().clone().into()) } /// The Misc Library holds minor functions that do not fall in any of the other libraries and /// calculators. #[no_mangle] extern "C" fn dynamic_library_get_misc_library( - ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().misc_library().clone().into() + ptr: FFIHandle>, +) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().misc_library().clone().into()) } diff --git a/src/ffi/dynamic_data/libraries/misc_library.rs b/src/ffi/dynamic_data/libraries/misc_library.rs index c339e6a..7f5a402 100644 --- a/src/ffi/dynamic_data/libraries/misc_library.rs +++ b/src/ffi/dynamic_data/libraries/misc_library.rs @@ -1,18 +1,10 @@ use crate::dynamic_data::{Gen7MiscLibrary, MiscLibrary}; -use crate::ffi::{IdentifiablePointer, OwnedPtr}; -use std::ptr::drop_in_place; +use crate::ffi::ffi_handle::FFIHandle; +use std::sync::Arc; /// Instantiates a new MiscLibrary. #[no_mangle] -extern "C" fn gen_7_misc_library_new() -> IdentifiablePointer> { - let v: Box = Box::new(Gen7MiscLibrary::new()); - let id = v.value_identifier(); - let ptr = Box::into_raw(Box::new(v)); - IdentifiablePointer::new(ptr, id) -} - -/// Drops a MiscLibrary. -#[no_mangle] -extern "C" fn misc_library_drop(ptr: OwnedPtr>) { - unsafe { drop_in_place(ptr) }; +extern "C" fn gen_7_misc_library_new() -> FFIHandle> { + let v: Arc = Arc::new(Gen7MiscLibrary::new()); + FFIHandle::get_handle(v.into()) } diff --git a/src/ffi/dynamic_data/libraries/script_resolver.rs b/src/ffi/dynamic_data/libraries/script_resolver.rs index 5d1fc32..7efbba0 100644 --- a/src/ffi/dynamic_data/libraries/script_resolver.rs +++ b/src/ffi/dynamic_data/libraries/script_resolver.rs @@ -1,49 +1,45 @@ use crate::dynamic_data::{EmptyScriptResolver, ScriptResolver}; -use crate::ffi::{IdentifiablePointer, OwnedPtr}; -use std::ptr::drop_in_place; +use crate::ffi::ffi_handle::FFIHandle; +use std::sync::Arc; /// Instantiates a basic empty script resolver, that always returns None. #[no_mangle] -extern "C" fn empty_script_resolver_new() -> IdentifiablePointer> { - let v: Box = Box::new(EmptyScriptResolver { - identifier: Default::default(), - }); - let id = v.value_identifier(); - let ptr = Box::into_raw(Box::new(v)); - IdentifiablePointer::new(ptr, id) -} - -/// Drops a script resolver. -#[no_mangle] -extern "C" fn script_resolver_drop(ptr: OwnedPtr>) { - unsafe { drop_in_place(ptr) }; +extern "C" fn empty_script_resolver_new() -> FFIHandle> { + let v: Arc = Arc::new(EmptyScriptResolver {}); + FFIHandle::get_handle(v.into()) } /// Foreign function interfaces for the Webassembly script resolver. #[cfg(feature = "wasm")] mod web_assembly_script_resolver { use crate::dynamic_data::ScriptResolver; - use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; + use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; + use crate::ffi::FFIResult; use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver; + use std::sync::Arc; /// Instantiates a new WebAssemblyScriptResolver. #[no_mangle] - extern "C" fn webassembly_script_resolver_new() -> IdentifiablePointer> { - let v: Box = WebAssemblyScriptResolver::new(); - let id = v.value_identifier(); - let ptr = Box::into_raw(Box::new(v)); - IdentifiablePointer::new(ptr, id) + extern "C" fn webassembly_script_resolver_new() -> FFIHandle> { + let v: Arc = WebAssemblyScriptResolver::new(); + FFIHandle::get_handle(v.into()) } /// Load a compiled WASM module. #[no_mangle] extern "C" fn webassembly_script_resolver_load_wasm_from_bytes( - mut ptr: ExternPointer>, + ptr: FFIHandle>, arr: *const u8, len: usize, - ) -> NativeResult<()> { + ) -> FFIResult<()> { + #[allow(clippy::unwrap_used)] // Unwrap used, but we know it cannot fail. unsafe { - ptr.as_mut() + let script_resolver = ptr.from_ffi_handle(); + let wasm_script_resolver = script_resolver + .as_any() + .downcast_ref::() + .unwrap(); + wasm_script_resolver .load_wasm_from_bytes(std::slice::from_raw_parts(arr, len)) .into() } @@ -51,9 +47,13 @@ mod web_assembly_script_resolver { /// 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>, - ) -> NativeResult<()> { - ptr.as_mut().finalize().into() + #[allow(clippy::unwrap_used)] // Unwrap used, but we know it cannot fail. + extern "C" fn webassembly_script_resolver_finalize(ptr: FFIHandle>) -> FFIResult<()> { + let script_resolver = ptr.from_ffi_handle(); + let wasm_script_resolver = script_resolver + .as_any() + .downcast_ref::() + .unwrap(); + wasm_script_resolver.finalize().into() } } diff --git a/src/ffi/dynamic_data/models/battle.rs b/src/ffi/dynamic_data/models/battle.rs index df22307..cae3390 100644 --- a/src/ffi/dynamic_data/models/battle.rs +++ b/src/ffi/dynamic_data/models/battle.rs @@ -2,16 +2,18 @@ use crate::dynamic_data::{ Battle, BattleParty, BattleRandom, BattleResult, BattleSide, DynamicLibrary, Pokemon, TurnChoice, }; use crate::ffi::dynamic_data::models::native_event_hook::NativeEventHook; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use anyhow::anyhow; use std::ffi::{c_char, CStr, CString}; +use std::ops::Deref; use std::sync::Arc; /// Initializes a new battle. #[no_mangle] extern "C" fn battle_new( - library: ExternPointer>, - parties: *const OwnedPtr>, + library: FFIHandle>, + parties: *const FFIHandle>, parties_length: usize, can_flee: u8, number_of_sides: u8, @@ -19,11 +21,11 @@ extern "C" fn battle_new( // NOTE: Split into two due to u128 not being ABI safe: https://github.com/rust-lang/rust/issues/54341 random_seed_1: u64, random_seed_2: u64, -) -> IdentifiablePointer { +) -> FFIHandle { let parties = unsafe { std::slice::from_raw_parts(parties, parties_length) .iter() - .map(|x| *Box::from_raw(*x)) + .map(|x| x.from_ffi_handle()) .collect() }; @@ -34,99 +36,98 @@ extern "C" fn battle_new( }; let random_seed = if random_seed == 0 { None } else { Some(random_seed) }; - Battle::new( - library.as_ref().clone(), - parties, - can_flee == 1, - number_of_sides, - pokemon_per_side, - random_seed, + FFIHandle::get_handle( + Battle::new( + library.from_ffi_handle(), + parties, + can_flee == 1, + number_of_sides, + pokemon_per_side, + random_seed, + ) + .into(), ) - .into() } /// The library the battle uses for handling. #[no_mangle] -extern "C" fn battle_library(ptr: ExternPointer>) -> IdentifiablePointer> { - ptr.as_ref().library().clone().into() +extern "C" fn battle_library(ptr: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().library().clone().into()) } /// The length of the list of all different parties in the battle. #[no_mangle] -extern "C" fn battle_parties_length(ptr: ExternPointer>) -> usize { - ptr.as_ref().parties().len() +extern "C" fn battle_parties_length(ptr: FFIHandle) -> usize { + ptr.from_ffi_handle().parties().len() } /// Get a party in the battle. #[no_mangle] -extern "C" fn battle_parties_get( - ptr: ExternPointer>, - index: usize, -) -> IdentifiablePointer> { - if let Some(v) = ptr.as_ref().parties().get(index) { - v.clone().into() +extern "C" fn battle_parties_get(ptr: FFIHandle, index: usize) -> FFIHandle> { + if let Some(v) = ptr.from_ffi_handle().parties().get(index) { + FFIHandle::get_handle(v.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Whether or not Pokemon can flee from the battle. #[no_mangle] -extern "C" fn battle_can_flee(ptr: ExternPointer>) -> u8 { - u8::from(ptr.as_ref().can_flee()) +extern "C" fn battle_can_flee(ptr: FFIHandle) -> u8 { + u8::from(ptr.from_ffi_handle().can_flee()) } /// The number of sides in the battle. Typically 2. #[no_mangle] -extern "C" fn battle_number_of_sides(ptr: ExternPointer>) -> u8 { - ptr.as_ref().number_of_sides() +extern "C" fn battle_number_of_sides(ptr: FFIHandle) -> u8 { + ptr.from_ffi_handle().number_of_sides() } /// The number of Pokemon that can be on each side. #[no_mangle] -extern "C" fn battle_pokemon_per_side(ptr: ExternPointer>) -> u8 { - ptr.as_ref().pokemon_per_side() +extern "C" fn battle_pokemon_per_side(ptr: FFIHandle) -> u8 { + ptr.from_ffi_handle().pokemon_per_side() } /// The length of the list of all different sides in the battle. #[no_mangle] -extern "C" fn battle_sides_length(ptr: ExternPointer>) -> usize { - ptr.as_ref().sides().len() +extern "C" fn battle_sides_length(ptr: FFIHandle) -> usize { + ptr.from_ffi_handle().sides().len() } /// Get a side in the battle. #[no_mangle] -extern "C" fn battle_sides_get(ptr: ExternPointer>, index: usize) -> IdentifiablePointer { - if let Some(v) = ptr.as_ref().sides().get(index) { - (v as *const BattleSide).into() +extern "C" fn battle_sides_get(ptr: FFIHandle, index: usize) -> FFIHandle { + if let Some(v) = ptr.from_ffi_handle().sides().get(index) { + FFIHandle::get_handle(v.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// The RNG used for the battle. #[no_mangle] -extern "C" fn battle_random(ptr: ExternPointer>) -> IdentifiablePointer> { - ptr.as_ref().random().clone().into() +extern "C" fn battle_random(ptr: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().random().clone().into()) } /// Whether or not the battle has ended. #[no_mangle] -extern "C" fn battle_has_ended(ptr: ExternPointer>) -> u8 { - u8::from(ptr.as_ref().has_ended()) +extern "C" fn battle_has_ended(ptr: FFIHandle) -> u8 { + u8::from(ptr.from_ffi_handle().has_ended()) } /// Whether or not we have a conclusive winner #[no_mangle] -extern "C" fn battle_has_conclusive_result(ptr: ExternPointer>) -> u8 { - u8::from(ptr.as_ref().result() != BattleResult::Inconclusive) +extern "C" fn battle_has_conclusive_result(ptr: FFIHandle) -> u8 { + u8::from(ptr.from_ffi_handle().result() != BattleResult::Inconclusive) } /// If we have a conclusive winner, the side that has won. If we don't have a conclusive winner, this /// always returns 0. #[no_mangle] -extern "C" fn battle_winning_side(ptr: ExternPointer>) -> u8 { - if let BattleResult::Conclusive(winner) = ptr.as_ref().result() { +extern "C" fn battle_winning_side(ptr: FFIHandle) -> u8 { + if let BattleResult::Conclusive(winner) = ptr.from_ffi_handle().result() { winner } else { 0 @@ -135,29 +136,29 @@ extern "C" fn battle_winning_side(ptr: ExternPointer>) -> u8 { /// Register a function to be triggered when an event in a battle occurs. #[no_mangle] -extern "C" fn battle_register_event_hook(ptr: ExternPointer>, f: NativeEventHook) { - ptr.as_ref().event_hook().register_listener(Box::new(f)) +extern "C" fn battle_register_event_hook(ptr: FFIHandle, f: NativeEventHook) { + ptr.from_ffi_handle().event_hook().register_listener(Box::new(f)) } /// The index of the current turn. 0 until all choices #[no_mangle] -extern "C" fn battle_current_turn(ptr: ExternPointer>) -> u32 { - ptr.as_ref().current_turn() +extern "C" fn battle_current_turn(ptr: FFIHandle) -> u32 { + ptr.from_ffi_handle().current_turn() } /// The time in nanoseconds the last turn took to run. Defaults to 0. #[no_mangle] -extern "C" fn battle_last_turn_time(ptr: ExternPointer>) -> u64 { - ptr.as_ref().last_turn_time() +extern "C" fn battle_last_turn_time(ptr: FFIHandle) -> u64 { + ptr.from_ffi_handle().last_turn_time() } /// Get a Pokemon on the battlefield, on a specific side and an index on that side. #[no_mangle] -extern "C" fn battle_get_pokemon(ptr: ExternPointer>, side: u8, index: u8) -> IdentifiablePointer { - if let Some(v) = ptr.as_ref().get_pokemon(side, index) { - v.into() +extern "C" fn battle_get_pokemon(ptr: FFIHandle, side: u8, index: u8) -> FFIHandle { + if let Some(v) = ptr.from_ffi_handle().get_pokemon(side, index) { + FFIHandle::get_handle(v.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } @@ -165,47 +166,51 @@ extern "C" fn battle_get_pokemon(ptr: ExternPointer>, side: u8, inde /// for that slot, or a party is responsible, but has no remaining Pokemon to throw out anymore, /// this returns false. #[no_mangle] -extern "C" fn battle_can_slot_be_filled(ptr: ExternPointer>, side: u8, index: u8) -> u8 { - u8::from(ptr.as_ref().can_slot_be_filled(side, index)) +extern "C" fn battle_can_slot_be_filled(ptr: FFIHandle, side: u8, index: u8) -> u8 { + u8::from(ptr.from_ffi_handle().can_slot_be_filled(side, index)) } /// Checks whether a choice is actually possible. #[no_mangle] -extern "C" fn battle_can_use(ptr: ExternPointer>, choice: ExternPointer) -> u8 { - u8::from(ptr.as_ref().can_use(choice.as_ref())) +extern "C" fn battle_can_use(ptr: FFIHandle, choice: FFIHandle>) -> u8 { + u8::from(ptr.from_ffi_handle().can_use(choice.from_ffi_handle().deref())) } /// Checks to see whether all Pokemon on the field have set their choices. If so, we then run /// the turn. #[no_mangle] -extern "C" fn battle_try_set_choice(ptr: ExternPointer>, choice: OwnedPtr) -> NativeResult { - let choice = unsafe { choice.read() }; - let result = ptr.as_ref().try_set_choice(choice); +extern "C" fn battle_try_set_choice(ptr: FFIHandle, choice: FFIHandle>) -> FFIResult { + let choice = choice.from_ffi_handle(); + let result = ptr.from_ffi_handle().try_set_choice(choice); match result { - Ok(b) => NativeResult::ok(u8::from(b)), - Err(e) => NativeResult::err(e), + Ok(b) => FFIResult::ok(u8::from(b)), + Err(e) => FFIResult::err(e), } } /// Sets the current weather for the battle. If nullptr is passed, this clears the weather. #[no_mangle] -extern "C" fn battle_set_weather(ptr: ExternPointer>, weather: *const c_char) -> NativeResult<()> { +extern "C" fn battle_set_weather(ptr: FFIHandle, weather: *const c_char) -> FFIResult<()> { if weather.is_null() { - ptr.as_ref().set_weather(None).into() + ptr.from_ffi_handle().set_weather(None).into() } else { - unsafe { ptr.as_ref().set_weather(Some(CStr::from_ptr(weather).into())).into() } + unsafe { + ptr.from_ffi_handle() + .set_weather(Some(CStr::from_ptr(weather).into())) + .into() + } } } /// Gets the current weather of the battle. If no weather is present, this returns nullptr. #[no_mangle] -extern "C" fn battle_weather_name(ptr: ExternPointer>) -> NativeResult<*mut c_char> { - match ptr.as_ref().weather_name() { +extern "C" fn battle_weather_name(ptr: FFIHandle) -> FFIResult<*mut c_char> { + match ptr.from_ffi_handle().weather_name() { Ok(Some(w)) => match CString::new(w.str()) { Ok(s) => s.into_raw().into(), - Err(e) => NativeResult::err(anyhow!("Failed to convert weather name to CString: {}", e)), + Err(e) => FFIResult::err(anyhow!("Failed to convert weather name to CString: {}", e)), }, Ok(None) => std::ptr::null_mut::().into(), - Err(e) => NativeResult::err(e), + Err(e) => FFIResult::err(e), } } diff --git a/src/ffi/dynamic_data/models/battle_party.rs b/src/ffi/dynamic_data/models/battle_party.rs index 750af6a..a9892c1 100644 --- a/src/ffi/dynamic_data/models/battle_party.rs +++ b/src/ffi/dynamic_data/models/battle_party.rs @@ -1,5 +1,6 @@ use crate::dynamic_data::{BattleParty, Pokemon, PokemonParty}; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use crate::VecExt; use anyhow::{anyhow, Result}; use std::sync::Arc; @@ -8,12 +9,12 @@ use std::sync::Arc; /// on the field attached. The indices are stored #[no_mangle] extern "C" fn battle_party_new( - party: ExternPointer>, + party: FFIHandle>, responsible_indices_ptr: *const u8, responsible_indices_length: usize, -) -> NativeResult>> { +) -> FFIResult>> { if responsible_indices_length % 2 != 0 { - return NativeResult::err(anyhow!("The length of responsible indices should be dividable by two")); + return FFIResult::err(anyhow!("The length of responsible indices should be dividable by two")); } let responsible_indices_slice = @@ -31,43 +32,40 @@ extern "C" fn battle_party_new( for i in 0..responsible_indices_length / 2 { match split(i) { Ok(_) => (), - Err(e) => return NativeResult::err(e), + Err(e) => return FFIResult::err(e), } } - match BattleParty::new(party.as_ref().clone(), responsible_indices) { - Ok(v) => NativeResult::ok(Arc::new(v).into()), - Err(e) => NativeResult::err(e), + match BattleParty::new(party.from_ffi_handle(), responsible_indices) { + Ok(v) => FFIResult::ok(FFIHandle::get_handle(Arc::new(v).into())), + Err(e) => FFIResult::err(e), } } /// Checks whether the party is responsible for the given index. #[no_mangle] -extern "C" fn battle_party_is_responsible_for_index(ptr: ExternPointer>, side: u8, index: u8) -> u8 { - u8::from(ptr.as_ref().is_responsible_for_index(side, index)) +extern "C" fn battle_party_is_responsible_for_index(ptr: FFIHandle>, side: u8, index: u8) -> u8 { + u8::from(ptr.from_ffi_handle().is_responsible_for_index(side, index)) } /// Whether or not the party has non fainted Pokemon that could be thrown out into the field. #[no_mangle] -extern "C" fn battle_party_has_pokemon_not_in_field(ptr: ExternPointer>) -> u8 { - u8::from(ptr.as_ref().has_pokemon_not_in_field()) +extern "C" fn battle_party_has_pokemon_not_in_field(ptr: FFIHandle>) -> u8 { + u8::from(ptr.from_ffi_handle().has_pokemon_not_in_field()) } /// Gets a Pokemon at an index. #[no_mangle] -extern "C" fn battle_party_get_pokemon( - ptr: ExternPointer>, - index: usize, -) -> IdentifiablePointer { - if let Some(v) = ptr.as_ref().get_pokemon(index) { - v.into() +extern "C" fn battle_party_get_pokemon(ptr: FFIHandle>, index: usize) -> FFIHandle { + if let Some(v) = ptr.from_ffi_handle().get_pokemon(index) { + FFIHandle::get_handle(v.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Gets the underlying Pokemon Party #[no_mangle] -extern "C" fn battle_party_party(ptr: ExternPointer>) -> IdentifiablePointer> { - ptr.as_ref().party().clone().into() +extern "C" fn battle_party_party(ptr: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().party().clone().into()) } diff --git a/src/ffi/dynamic_data/models/event.rs b/src/ffi/dynamic_data/models/event.rs index c266465..a98f482 100644 --- a/src/ffi/dynamic_data/models/event.rs +++ b/src/ffi/dynamic_data/models/event.rs @@ -1,5 +1,6 @@ use crate::dynamic_data::{Event, Pokemon}; -use crate::ffi::{ExternPointer, IdentifiablePointer}; +use crate::ffi::ExternPointer; +use crate::ffi::FFIHandle; /// The kind of the event. #[no_mangle] @@ -66,13 +67,18 @@ event_ffi!( /// The index of the Pokemon that got switched in/out on its side index: u8, /// The new Pokemon that will be on the spot. If none, the spot will be null. - pokemon: IdentifiablePointer, + pokemon: FFIHandle, }, { + let pokemon_handle = match pokemon { + Some(pokemon) => FFIHandle::get_handle(pokemon.clone().into()), + None => FFIHandle::none(), + }; + return SwitchData{ side_index: *side_index, index: *index, - pokemon: pokemon.clone().into(), + pokemon: pokemon_handle, } } ); diff --git a/src/ffi/dynamic_data/models/learned_move.rs b/src/ffi/dynamic_data/models/learned_move.rs index 6c3866d..4ca11bf 100644 --- a/src/ffi/dynamic_data/models/learned_move.rs +++ b/src/ffi/dynamic_data/models/learned_move.rs @@ -1,66 +1,58 @@ use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use crate::static_data::MoveData; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiate a new learned move. #[no_mangle] extern "C" fn learned_move_new( - move_data: ExternPointer>, + move_data: FFIHandle>, learn_method: MoveLearnMethod, -) -> IdentifiablePointer> { - Arc::new(LearnedMove::new(move_data.as_ref().clone(), learn_method)).into() -} - -/// Drops a learned move. -#[no_mangle] -extern "C" fn learned_move_drop(learned_move: OwnedPtr>) { - unsafe { drop_in_place(learned_move) } +) -> FFIHandle> { + FFIHandle::get_handle(Arc::new(LearnedMove::new(move_data.from_ffi_handle().clone(), learn_method)).into()) } /// The immutable move information of the move. #[no_mangle] -extern "C" fn learned_move_move_data( - learned_move: ExternPointer>, -) -> IdentifiablePointer> { - learned_move.as_ref().move_data().clone().into() +extern "C" fn learned_move_move_data(learned_move: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(learned_move.from_ffi_handle().move_data().clone().into()) } /// The maximal power points for this move. #[no_mangle] -extern "C" fn learned_move_max_pp(learned_move: ExternPointer>) -> u8 { - learned_move.as_ref().max_pp() +extern "C" fn learned_move_max_pp(learned_move: FFIHandle>) -> u8 { + learned_move.from_ffi_handle().max_pp() } /// The amount of remaining power points. If this is 0, we can not use the move anymore. #[no_mangle] -extern "C" fn learned_move_remaining_pp(learned_move: ExternPointer>) -> u8 { - learned_move.as_ref().remaining_pp() +extern "C" fn learned_move_remaining_pp(learned_move: FFIHandle>) -> u8 { + learned_move.from_ffi_handle().remaining_pp() } /// The way the move was learned. #[no_mangle] -extern "C" fn learned_move_learn_method(learned_move: ExternPointer>) -> MoveLearnMethod { - learned_move.as_ref().learn_method() +extern "C" fn learned_move_learn_method(learned_move: FFIHandle>) -> MoveLearnMethod { + learned_move.from_ffi_handle().learn_method() } /// Try and reduce the PP by a certain amount. If the amount is higher than the current uses, /// return 0. Otherwise, reduce the PP, and return 1. #[no_mangle] -extern "C" fn learned_move_try_use(learned_move: ExternPointer>, amount: u8) -> u8 { - u8::from(learned_move.as_ref().try_use(amount)) +extern "C" fn learned_move_try_use(learned_move: FFIHandle>, amount: u8) -> u8 { + u8::from(learned_move.from_ffi_handle().try_use(amount)) } /// Set the remaining PP to the max amount of PP. #[no_mangle] -extern "C" fn learned_move_restore_all_uses(learned_move: ExternPointer>) { - learned_move.as_ref().restore_all_uses(); +extern "C" fn learned_move_restore_all_uses(learned_move: FFIHandle>) { + learned_move.from_ffi_handle().restore_all_uses(); } /// Restore the remaining PP by a certain amount. Will prevent it from going above max PP. #[no_mangle] -extern "C" fn learned_move_restore_uses(learned_move: ExternPointer>, amount: u8) -> NativeResult<()> { - learned_move.as_ref().restore_uses(amount); - NativeResult::ok(()) +extern "C" fn learned_move_restore_uses(learned_move: FFIHandle>, amount: u8) -> FFIResult<()> { + learned_move.from_ffi_handle().restore_uses(amount); + FFIResult::ok(()) } diff --git a/src/ffi/dynamic_data/models/native_event_hook.rs b/src/ffi/dynamic_data/models/native_event_hook.rs index f3e7944..929302e 100644 --- a/src/ffi/dynamic_data/models/native_event_hook.rs +++ b/src/ffi/dynamic_data/models/native_event_hook.rs @@ -1,11 +1,10 @@ use crate::dynamic_data::Event; -use crate::ffi::BorrowedPtr; /// Wrapper class for easier use of an external function pointer. #[repr(C)] pub(super) struct NativeEventHook { /// The actual C function to be called. - f: extern "C" fn(BorrowedPtr), + f: extern "C" fn(*const Event<'_>), } impl NativeEventHook { diff --git a/src/ffi/dynamic_data/models/pokemon.rs b/src/ffi/dynamic_data/models/pokemon.rs index fb5454a..3b7b994 100644 --- a/src/ffi/dynamic_data/models/pokemon.rs +++ b/src/ffi/dynamic_data/models/pokemon.rs @@ -1,20 +1,21 @@ use crate::defines::LevelInt; use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, LearnedMove, MoveLearnMethod, Pokemon}; -use crate::ffi::{ffi_arc_getter, ffi_vec_value_getters, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use crate::static_data::{ Ability, AbilityIndex, Form, Gender, Item, Nature, Species, Statistic, StatisticSet, TypeIdentifier, }; +use crate::VecExt; use anyhow::anyhow; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new Pokemon. #[no_mangle] extern "C" fn pokemon_new( - library: ExternPointer>, - species: ExternPointer>, - form: ExternPointer>, + library: FFIHandle>, + species: FFIHandle>, + form: FFIHandle>, hidden_ability: u8, ability_index: u8, level: LevelInt, @@ -22,12 +23,12 @@ extern "C" fn pokemon_new( gender: Gender, coloring: u8, nature: *const c_char, -) -> NativeResult> { +) -> FFIResult> { let nature = unsafe { CStr::from_ptr(nature) }.into(); let pokemon = Pokemon::new( - library.as_ref().clone(), - species.as_ref().clone(), - form.as_ref(), + library.from_ffi_handle(), + species.from_ffi_handle(), + &form.from_ffi_handle(), AbilityIndex { hidden: hidden_ability == 1, index: ability_index, @@ -39,337 +40,373 @@ extern "C" fn pokemon_new( &nature, ); match pokemon { - Ok(pokemon) => NativeResult::ok(pokemon.into()), - Err(err) => NativeResult::err(err), + Ok(pokemon) => FFIResult::ok(FFIHandle::get_handle(pokemon.into())), + Err(err) => FFIResult::err(err), } } -/// Drops an Arc reference held by the FFI. -#[no_mangle] -unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr) { - drop_in_place(ptr); -} - /// The library data of the Pokemon. #[no_mangle] -extern "C" fn pokemon_library(ptr: ExternPointer) -> IdentifiablePointer> { - ptr.as_ref().library().clone().into() +extern "C" fn pokemon_library(handle: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(handle.from_ffi_handle().library().clone().into()) } /// The species of the Pokemon. #[no_mangle] -extern "C" fn pokemon_species(ptr: ExternPointer) -> IdentifiablePointer> { - ptr.as_ref().species().into() +extern "C" fn pokemon_species(handle: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(handle.from_ffi_handle().species().into()) } /// The form of the Pokemon. #[no_mangle] -extern "C" fn pokemon_form(ptr: ExternPointer) -> IdentifiablePointer> { - ptr.as_ref().form().into() +extern "C" fn pokemon_form(handle: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(handle.from_ffi_handle().form().into()) } /// The species that should be displayed to the user. This handles stuff like the Illusion ability. #[no_mangle] -extern "C" fn pokemon_display_species(ptr: ExternPointer) -> IdentifiablePointer> { - ptr.as_ref().display_species().into() +extern "C" fn pokemon_display_species(handle: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(handle.from_ffi_handle().display_species().into()) } /// The form that should be displayed to the user. This handles stuff like the Illusion ability. #[no_mangle] -extern "C" fn pokemon_display_form(ptr: ExternPointer) -> IdentifiablePointer> { - ptr.as_ref().display_form().into() +extern "C" fn pokemon_display_form(handle: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(handle.from_ffi_handle().display_form().into()) } -ffi_arc_getter!(Pokemon, level, LevelInt); -ffi_arc_getter!(Pokemon, experience, u32); -ffi_arc_getter!(Pokemon, unique_identifier, u32); -ffi_arc_getter!(Pokemon, gender, Gender); -ffi_arc_getter!(Pokemon, coloring, u8); +#[no_mangle] +extern "C" fn pokemon_level(handle: FFIHandle) -> LevelInt { + handle.from_ffi_handle().level() +} + +#[no_mangle] +extern "C" fn pokemon_experience(handle: FFIHandle) -> u32 { + handle.from_ffi_handle().experience() +} + +#[no_mangle] +extern "C" fn pokemon_unique_identifier(handle: FFIHandle) -> u32 { + handle.from_ffi_handle().unique_identifier() +} + +#[no_mangle] +extern "C" fn pokemon_gender(handle: FFIHandle) -> Gender { + handle.from_ffi_handle().gender() +} + +#[no_mangle] +extern "C" fn pokemon_coloring(handle: FFIHandle) -> u8 { + handle.from_ffi_handle().coloring() +} /// Gets the held item of a Pokemon #[no_mangle] -extern "C" fn pokemon_held_item(ptr: ExternPointer) -> IdentifiablePointer> { - if let Some(v) = ptr.as_ref().held_item().read().as_ref() { - v.clone().into() +extern "C" fn pokemon_held_item(handle: FFIHandle) -> FFIHandle> { + if let Some(v) = handle.from_ffi_handle().held_item().read().as_ref() { + FFIHandle::get_handle(v.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Checks whether the Pokemon is holding a specific item. #[no_mangle] -extern "C" fn pokemon_has_held_item(ptr: ExternPointer, name: *const c_char) -> u8 { +extern "C" fn pokemon_has_held_item(handle: FFIHandle, name: *const c_char) -> u8 { let name = unsafe { CStr::from_ptr(name) }.into(); - u8::from(ptr.as_ref().has_held_item(&name)) + u8::from(handle.from_ffi_handle().has_held_item(&name)) } /// Changes the held item of the Pokemon. Returns the previously held item. #[no_mangle] extern "C" fn pokemon_set_held_item( - ptr: ExternPointer, - item: ExternPointer>, -) -> IdentifiablePointer> { - if let Some(v) = ptr.as_ref().set_held_item(item.as_ref()) { - v.into() + handle: FFIHandle, + item: FFIHandle>, +) -> FFIHandle> { + if let Some(v) = handle.from_ffi_handle().set_held_item(&item.from_ffi_handle()) { + FFIHandle::get_handle(v.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Removes the held item from the Pokemon. Returns the previously held item. #[no_mangle] -extern "C" fn pokemon_remove_held_item(ptr: ExternPointer) -> IdentifiablePointer> { - if let Some(v) = ptr.as_ref().remove_held_item() { - v.into() +extern "C" fn pokemon_remove_held_item(handle: FFIHandle) -> FFIHandle> { + if let Some(v) = handle.from_ffi_handle().remove_held_item() { + FFIHandle::get_handle(v.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Makes the Pokemon uses its held item. #[no_mangle] -extern "C" fn pokemon_consume_held_item(ptr: ExternPointer) -> NativeResult { - match ptr.as_ref().consume_held_item() { - Ok(v) => NativeResult::ok(u8::from(v)), - Err(err) => NativeResult::err(err), +extern "C" fn pokemon_consume_held_item(handle: FFIHandle) -> FFIResult { + match handle.from_ffi_handle().consume_held_item() { + Ok(v) => FFIResult::ok(u8::from(v)), + Err(err) => FFIResult::err(err), } } -ffi_arc_getter!(Pokemon, current_health, u32); -ffi_arc_getter!(Pokemon, max_health, u32); -ffi_arc_getter!(Pokemon, weight, f32); -ffi_arc_getter!(Pokemon, height, f32); +#[no_mangle] +extern "C" fn pokemon_current_health(handle: FFIHandle) -> u32 { + handle.from_ffi_handle().current_health() +} + +#[no_mangle] +extern "C" fn pokemon_max_health(handle: FFIHandle) -> u32 { + handle.from_ffi_handle().max_health() +} + +#[no_mangle] +extern "C" fn pokemon_weight(handle: FFIHandle) -> f32 { + handle.from_ffi_handle().weight() +} + +#[no_mangle] +extern "C" fn pokemon_height(handle: FFIHandle) -> f32 { + handle.from_ffi_handle().height() +} /// An optional nickname of the Pokemon. #[no_mangle] -extern "C" fn pokemon_nickname(ptr: ExternPointer) -> NativeResult<*mut c_char> { - let name = ptr.as_ref().nickname(); +extern "C" fn pokemon_nickname(handle: FFIHandle) -> FFIResult<*mut c_char> { + let form = handle.from_ffi_handle(); + let name = form.nickname(); if let Some(v) = name { match CString::new(v.as_str()) { - Ok(v) => NativeResult::ok(v.into_raw()), - Err(err) => NativeResult::err(anyhow!("Could not convert nickname to CString: {}", err)), + Ok(v) => FFIResult::ok(v.into_raw()), + Err(err) => FFIResult::err(anyhow!("Could not convert nickname to CString: {}", err)), } } else { - NativeResult::ok(std::ptr::null_mut()) + FFIResult::ok(std::ptr::null_mut()) } } /// Whether the actual ability on the form is a hidden ability. #[no_mangle] -extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer) -> u8 { - u8::from(ptr.as_ref().real_ability().hidden) +extern "C" fn pokemon_real_ability_is_hidden(handle: FFIHandle) -> u8 { + u8::from(handle.from_ffi_handle().real_ability().hidden) } /// The index of the actual ability on the form. #[no_mangle] -extern "C" fn pokemon_real_ability_index(ptr: ExternPointer) -> u8 { - ptr.as_ref().real_ability().index +extern "C" fn pokemon_real_ability_index(handle: FFIHandle) -> u8 { + handle.from_ffi_handle().real_ability().index } -ffi_vec_value_getters!(Pokemon, Pokemon, types, TypeIdentifier); +#[no_mangle] +extern "C" fn pokemon_types_length(ptr: FFIHandle) -> usize { + ptr.from_ffi_handle().types().len() +} + +#[no_mangle] +extern "C" fn pokemon_types_get(ptr: FFIHandle, index: usize) -> FFIResult { + match ptr.from_ffi_handle().types().get_res(index) { + Ok(v) => FFIResult::ok(*v), + Err(err) => FFIResult::err(err), + } +} /// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get /// a null pointer otherwise. #[no_mangle] -extern "C" fn pokemon_learned_move_get( - ptr: ExternPointer, - index: usize, -) -> IdentifiablePointer> { - if let Some(Some(v)) = ptr.as_ref().learned_moves().read().get(index) { - v.clone().into() +extern "C" fn pokemon_learned_move_get(handle: FFIHandle, index: usize) -> FFIHandle> { + if let Some(Some(v)) = handle.from_ffi_handle().learned_moves().read().get(index) { + FFIHandle::get_handle(v.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// The stats of the Pokemon when disregarding any stat boosts. #[no_mangle] -extern "C" fn pokemon_flat_stats(ptr: ExternPointer) -> IdentifiablePointer>> { - ptr.as_ref().flat_stats().clone().into() +extern "C" fn pokemon_flat_stats(handle: FFIHandle) -> FFIHandle>> { + FFIHandle::get_handle(handle.from_ffi_handle().flat_stats().clone().into()) } /// The stats of the Pokemon including the stat boosts. #[no_mangle] -extern "C" fn pokemon_boosted_stats(ptr: ExternPointer) -> IdentifiablePointer>> { - ptr.as_ref().boosted_stats().clone().into() +extern "C" fn pokemon_boosted_stats(handle: FFIHandle) -> FFIHandle>> { + FFIHandle::get_handle(handle.from_ffi_handle().boosted_stats().clone().into()) } /// Get the stat boosts for a specific stat. #[no_mangle] -extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer, statistic: Statistic) -> i8 { - ptr.as_ref().stat_boost(statistic) +extern "C" fn pokemon_get_stat_boost(handle: FFIHandle, statistic: Statistic) -> i8 { + handle.from_ffi_handle().stat_boost(statistic) } /// Change a boosted stat by a certain amount. #[no_mangle] extern "C" fn pokemon_change_stat_boost( - ptr: ExternPointer, + handle: FFIHandle, stat: Statistic, diff_amount: i8, self_inflicted: u8, -) -> NativeResult { - match ptr.as_ref().change_stat_boost(stat, diff_amount, self_inflicted == 1) { - Ok(v) => NativeResult::ok(u8::from(v)), - Err(e) => NativeResult::err(e), +) -> FFIResult { + match handle + .from_ffi_handle() + .change_stat_boost(stat, diff_amount, self_inflicted == 1) + { + Ok(v) => FFIResult::ok(u8::from(v)), + Err(e) => FFIResult::err(e), } } /// Gets a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_get_individual_value(ptr: ExternPointer, stat: Statistic) -> u8 { - ptr.as_ref().individual_values().get_stat(stat) +extern "C" fn pokemon_get_individual_value(handle: FFIHandle, stat: Statistic) -> u8 { + handle.from_ffi_handle().individual_values().get_stat(stat) } /// Modifies a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_set_individual_value( - ptr: ExternPointer, - stat: Statistic, - value: u8, -) -> NativeResult<()> { - ptr.as_ref().individual_values().set_stat(stat, value); - ptr.as_ref().recalculate_flat_stats().into() +extern "C" fn pokemon_set_individual_value(handle: FFIHandle, stat: Statistic, value: u8) -> FFIResult<()> { + handle.from_ffi_handle().individual_values().set_stat(stat, value); + handle.from_ffi_handle().recalculate_flat_stats().into() } /// Gets a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_get_effort_value(ptr: ExternPointer, stat: Statistic) -> u8 { - ptr.as_ref().effort_values().get_stat(stat) +extern "C" fn pokemon_get_effort_value(handle: FFIHandle, stat: Statistic) -> u8 { + handle.from_ffi_handle().effort_values().get_stat(stat) } /// Modifies a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_set_effort_value(ptr: ExternPointer, stat: Statistic, value: u8) -> NativeResult<()> { - ptr.as_ref().effort_values().set_stat(stat, value); - ptr.as_ref().recalculate_flat_stats().into() +extern "C" fn pokemon_set_effort_value(handle: FFIHandle, stat: Statistic, value: u8) -> FFIResult<()> { + handle.from_ffi_handle().effort_values().set_stat(stat, value); + handle.from_ffi_handle().recalculate_flat_stats().into() } /// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this /// returns null. #[no_mangle] -extern "C" fn pokemon_get_battle(ptr: ExternPointer) -> IdentifiablePointer { - if let Some(v) = ptr.as_ref().get_battle() { - v.into() +extern "C" fn pokemon_get_battle(handle: FFIHandle) -> FFIHandle { + if let Some(v) = handle.from_ffi_handle().get_battle() { + FFIHandle::get_handle(v.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Get the index of the side of the battle the Pokemon is in. If the Pokemon /// is not on the battlefield, this always returns 0. #[no_mangle] -extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer) -> u8 { - ptr.as_ref().get_battle_side_index().unwrap_or_default() +extern "C" fn pokemon_get_battle_side_index(handle: FFIHandle) -> u8 { + handle.from_ffi_handle().get_battle_side_index().unwrap_or_default() } /// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon /// is not on the battlefield, this always returns 0. #[no_mangle] -extern "C" fn pokemon_get_battle_index(ptr: ExternPointer) -> u8 { - ptr.as_ref().get_battle_index().unwrap_or_default() +extern "C" fn pokemon_get_battle_index(handle: FFIHandle) -> u8 { + handle.from_ffi_handle().get_battle_index().unwrap_or_default() } /// Returns whether something overrides the ability. #[no_mangle] -extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer) -> u8 { - u8::from(ptr.as_ref().is_ability_overriden()) +extern "C" fn pokemon_is_ability_overriden(handle: FFIHandle) -> u8 { + u8::from(handle.from_ffi_handle().is_ability_overriden()) } /// Returns the currently active ability. #[no_mangle] -extern "C" fn pokemon_active_ability( - ptr: ExternPointer, -) -> NativeResult>> { - match ptr.as_ref().active_ability() { - Ok(v) => NativeResult::ok(v.clone().into()), - Err(e) => NativeResult::err(e), +extern "C" fn pokemon_active_ability(handle: FFIHandle) -> FFIResult>> { + match handle.from_ffi_handle().active_ability() { + Ok(v) => FFIResult::ok(FFIHandle::get_handle(v.clone().into())), + Err(e) => FFIResult::err(e), } } /// Whether or not the Pokemon is allowed to gain experience. #[no_mangle] -extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer) -> u8 { - u8::from(ptr.as_ref().allowed_experience_gain()) +extern "C" fn pokemon_allowed_experience_gain(handle: FFIHandle) -> u8 { + u8::from(handle.from_ffi_handle().allowed_experience_gain()) } /// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_nature(ptr: ExternPointer) -> IdentifiablePointer> { - ptr.as_ref().nature().clone().into() +extern "C" fn pokemon_nature(handle: FFIHandle) -> FFIHandle> { + FFIHandle::get_handle(handle.from_ffi_handle().nature().clone().into()) } /// Calculates the flat stats on the Pokemon. This should be called when for example the base /// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted /// stats, as those depend on the flat stats. #[no_mangle] -extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer) -> NativeResult<()> { - ptr.as_ref().recalculate_flat_stats().into() +extern "C" fn pokemon_recalculate_flat_stats(handle: FFIHandle) -> FFIResult<()> { + handle.from_ffi_handle().recalculate_flat_stats().into() } /// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes. #[no_mangle] -extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer) -> NativeResult<()> { - ptr.as_ref().recalculate_boosted_stats().into() +extern "C" fn pokemon_recalculate_boosted_stats(handle: FFIHandle) -> FFIResult<()> { + handle.from_ffi_handle().recalculate_boosted_stats().into() } /// Change the species of the Pokemon. #[no_mangle] extern "C" fn pokemon_change_species( - ptr: ExternPointer, - species: ExternPointer>, - form: ExternPointer>, -) -> NativeResult<()> { - ptr.as_ref() - .change_species(species.as_ref().clone(), form.as_ref().clone()) + handle: FFIHandle, + species: FFIHandle>, + form: FFIHandle>, +) -> FFIResult<()> { + handle + .from_ffi_handle() + .change_species(species.from_ffi_handle().clone(), form.from_ffi_handle().clone()) .into() } /// Change the form of the Pokemon. #[no_mangle] -extern "C" fn pokemon_change_form(ptr: ExternPointer, form: ExternPointer>) -> NativeResult<()> { - ptr.as_ref().change_form(form.as_ref()).into() +extern "C" fn pokemon_change_form(handle: FFIHandle, form: FFIHandle>) -> FFIResult<()> { + handle.from_ffi_handle().change_form(&form.from_ffi_handle()).into() } /// Whether or not the Pokemon is useable in a battle. #[no_mangle] -extern "C" fn pokemon_is_usable(ptr: ExternPointer) -> u8 { - u8::from(ptr.as_ref().is_usable()) +extern "C" fn pokemon_is_usable(handle: FFIHandle) -> u8 { + u8::from(handle.from_ffi_handle().is_usable()) } /// Returns whether the Pokemon is fainted. #[no_mangle] -extern "C" fn pokemon_is_fainted(ptr: ExternPointer) -> u8 { - u8::from(ptr.as_ref().is_fainted()) +extern "C" fn pokemon_is_fainted(handle: FFIHandle) -> u8 { + u8::from(handle.from_ffi_handle().is_fainted()) } /// Whether or not the Pokemon is on the battlefield. #[no_mangle] -extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer) -> u8 { - u8::from(ptr.as_ref().is_on_battlefield()) +extern "C" fn pokemon_is_on_battlefield(handle: FFIHandle) -> u8 { + u8::from(handle.from_ffi_handle().is_on_battlefield()) } /// Damages the Pokemon by a certain amount of damage, from a damage source. #[no_mangle] -extern "C" fn pokemon_damage(ptr: ExternPointer, damage: u32, source: DamageSource) -> NativeResult<()> { - ptr.as_ref().damage(damage, source).into() +extern "C" fn pokemon_damage(handle: FFIHandle, damage: u32, source: DamageSource) -> FFIResult<()> { + handle.from_ffi_handle().damage(damage, source).into() } /// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not /// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false. #[no_mangle] -extern "C" fn pokemon_heal(ptr: ExternPointer, amount: u32, allow_revive: u8) -> bool { - ptr.as_ref().heal(amount, allow_revive == 1) +extern "C" fn pokemon_heal(handle: FFIHandle, amount: u32, allow_revive: u8) -> bool { + handle.from_ffi_handle().heal(amount, allow_revive == 1) } /// Learn a move. #[no_mangle] extern "C" fn pokemon_learn_move( - ptr: ExternPointer, + handle: FFIHandle, move_name: *const c_char, learn_method: MoveLearnMethod, -) -> NativeResult<()> { +) -> FFIResult<()> { unsafe { - ptr.as_ref() + handle + .from_ffi_handle() .learn_move(&CStr::from_ptr(move_name).into(), learn_method) .into() } @@ -377,6 +414,6 @@ extern "C" fn pokemon_learn_move( /// Removes the current non-volatile status from the Pokemon. #[no_mangle] -extern "C" fn pokemon_clear_status(ptr: ExternPointer) { - ptr.as_ref().clear_status() +extern "C" fn pokemon_clear_status(handle: FFIHandle) { + handle.from_ffi_handle().clear_status() } diff --git a/src/ffi/dynamic_data/models/pokemon_party.rs b/src/ffi/dynamic_data/models/pokemon_party.rs index 723428a..4e63682 100644 --- a/src/ffi/dynamic_data/models/pokemon_party.rs +++ b/src/ffi/dynamic_data/models/pokemon_party.rs @@ -1,68 +1,69 @@ use crate::dynamic_data::{Pokemon, PokemonParty}; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use std::sync::Arc; /// Instantiates a party with a set size. #[no_mangle] -extern "C" fn pokemon_party_new(capacity: usize) -> IdentifiablePointer> { - Arc::new(PokemonParty::new(capacity)).into() +extern "C" fn pokemon_party_new(capacity: usize) -> FFIHandle> { + FFIHandle::get_handle(Arc::new(PokemonParty::new(capacity)).into()) } /// Gets a Pokemon at an index in the party. #[no_mangle] -extern "C" fn pokemon_party_at(ptr: ExternPointer>, index: usize) -> IdentifiablePointer { - if let Some(v) = ptr.as_ref().at(index) { - v.into() +extern "C" fn pokemon_party_at(ptr: FFIHandle>, index: usize) -> FFIHandle { + if let Some(v) = ptr.from_ffi_handle().at(index) { + FFIHandle::get_handle(v.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Gets a Pokemon at an index in the party. #[no_mangle] -extern "C" fn pokemon_party_switch(ptr: ExternPointer>, a: usize, b: usize) { - ptr.as_ref().switch(a, b); +extern "C" fn pokemon_party_switch(ptr: FFIHandle>, a: usize, b: usize) { + ptr.from_ffi_handle().switch(a, b); } /// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon. #[no_mangle] extern "C" fn pokemon_party_swap_into( - ptr: ExternPointer>, + ptr: FFIHandle>, index: usize, - pokemon: ExternPointer, -) -> NativeResult> { - let pokemon = if pokemon.ptr.is_null() { + pokemon: FFIHandle, +) -> FFIResult> { + let pokemon = if pokemon.is_none() { None } else { - Some(pokemon.as_ref().clone()) + Some(pokemon.from_ffi_handle()) }; - match ptr.as_ref().swap_into(index, pokemon) { - Ok(Some(v)) => NativeResult::ok(v.into()), - Ok(None) => NativeResult::ok(IdentifiablePointer::none()), - Err(e) => NativeResult::err(e), + match ptr.from_ffi_handle().swap_into(index, pokemon) { + Ok(Some(v)) => FFIResult::ok(FFIHandle::get_handle(v.into())), + Ok(None) => FFIResult::ok(FFIHandle::none()), + Err(e) => FFIResult::err(e), } } /// Whether or not the party still has Pokemon that can be used in battle. #[no_mangle] -extern "C" fn pokemon_party_has_usable_pokemon(ptr: ExternPointer>) -> u8 { - u8::from(ptr.as_ref().has_usable_pokemon()) +extern "C" fn pokemon_party_has_usable_pokemon(ptr: FFIHandle>) -> u8 { + u8::from(ptr.from_ffi_handle().has_usable_pokemon()) } /// Get the length of the underlying list of Pokemon. #[no_mangle] -extern "C" fn pokemon_party_length(ptr: ExternPointer>) -> usize { - ptr.as_ref().length() +extern "C" fn pokemon_party_length(ptr: FFIHandle>) -> usize { + ptr.from_ffi_handle().length() } /// Makes sure there are no empty spots in the party anymore, leaving the length the same. #[no_mangle] -extern "C" fn pokemon_party_pack_party(ptr: ExternPointer>) -> NativeResult<()> { - ptr.as_ref().pack_party().into() +extern "C" fn pokemon_party_pack_party(ptr: FFIHandle>) -> FFIResult<()> { + ptr.from_ffi_handle().pack_party().into() } /// Checks if the party contains a given pokemon. #[no_mangle] -extern "C" fn pokemon_party_has_pokemon(ptr: ExternPointer>, pokemon: ExternPointer) -> u8 { - u8::from(ptr.as_ref().has_pokemon(pokemon.as_ref())) +extern "C" fn pokemon_party_has_pokemon(ptr: FFIHandle>, pokemon: FFIHandle) -> u8 { + u8::from(ptr.from_ffi_handle().has_pokemon(&pokemon.from_ffi_handle())) } diff --git a/src/ffi/ffi_handle.rs b/src/ffi/ffi_handle.rs new file mode 100644 index 0000000..935a3bb --- /dev/null +++ b/src/ffi/ffi_handle.rs @@ -0,0 +1,296 @@ +use crate::static_data::{ + Ability, EffectParameter, Form, GrowthRate, Item, LearnableMoves, MoveData, Nature, SecondaryEffect, Species, + StaticStatisticSet, StatisticSet, +}; +use anyhow::anyhow; +use hashbrown::HashMap; +use parking_lot::RwLock; +use std::hash::Hash; +use std::sync::atomic::AtomicUsize; +use std::sync::{Arc, LazyLock}; + +#[repr(C)] +pub(super) struct FFIHandle { + handle: usize, + _marker: std::marker::PhantomData, +} + +impl Clone for FFIHandle { + fn clone(&self) -> Self { + Self { + handle: self.handle, + _marker: std::marker::PhantomData, + } + } +} + +impl Copy for FFIHandle {} + +#[derive(Clone)] +pub(super) enum FFIObject { + Ability(Arc), + EffectParameter(Arc), + StatisticSetU8(Arc>), + StatisticSetI8(Arc>), + StatisticSetU32(Arc>), + StaticStatisticSetU16(Arc>), + Form(Arc), + LearnableMoves(Arc), + GrowthRate(Arc), + Item(Arc), + SecondaryEffect(Arc), + MoveData(Arc), + Nature(Arc), + Species(Arc), + + SpeciesLibrary(Arc), + MoveLibrary(Arc), + AbilityLibrary(Arc), + ItemLibrary(Arc), + GrowthRateLibrary(Arc), + LibrarySettings(Arc), + NatureLibrary(Arc), + TypeLibrary(Arc), + StaticData(Arc), + + // DynamicData + TurnChoice(Arc), + Pokemon(crate::dynamic_data::Pokemon), + LearnedMove(Arc), + PokemonParty(Arc), + BattleParty(Arc), + Battle(crate::dynamic_data::Battle), + BattleSide(crate::dynamic_data::BattleSide), + BattleRandom(Arc), + + // DynamicLibrary + BattleStatCalculator(Arc), + DamageLibrary(Arc), + MiscLibrary(Arc), + ScriptResolver(Arc), + DynamicLibrary(Arc), +} + +unsafe impl Send for FFIObject {} + +unsafe impl Sync for FFIObject {} + +static NEXT_HANDLE: AtomicUsize = AtomicUsize::new(0); +static FFI_OBJECTS: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); +static FFI_OBJECTS_INVERSE: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); + +impl FFIHandle { + pub fn get_handle(o: FFIObject) -> Self { + if let Some(handle) = FFI_OBJECTS_INVERSE.read().get(&o) { + return Self { + handle: *handle, + _marker: std::marker::PhantomData, + }; + } + + let handle = NEXT_HANDLE.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + FFI_OBJECTS.write().insert(handle, o.clone()); + FFI_OBJECTS_INVERSE.write().insert(o, handle); + Self { + handle, + _marker: std::marker::PhantomData, + } + } + + pub fn none() -> Self { + Self { + handle: 0, + _marker: std::marker::PhantomData, + } + } + + #[allow(clippy::unwrap_used)] // Unwrap used, as it is a potential security bug if this fails + pub fn resolve(&self) -> FFIObject { + FFI_OBJECTS + .read() + .get(&self.handle) + .ok_or(anyhow!("Unable to get handle")) + .unwrap() + .clone() + } + + pub fn is_none(&self) -> bool { + self.handle == 0 + } +} + +#[allow(clippy::from_over_into)] +impl Into> for FFIHandle { + fn into(self) -> anyhow_ext::Result { + Ok(FFI_OBJECTS + .read() + .get(&self.handle) + .ok_or(anyhow!("Unable to get handle"))? + .clone()) + } +} + +impl Eq for FFIObject {} + +#[allow(clippy::wrong_self_convention)] +pub(super) trait FromFFIHandle { + fn from_ffi_handle(&self) -> T; + fn from_ffi_handle_opt(&self) -> Option; +} + +impl Hash for FFIObject { + fn hash(&self, state: &mut H) { + match self { + Self::Ability(a) => Arc::as_ptr(a).hash(state), + Self::EffectParameter(a) => Arc::as_ptr(a).hash(state), + Self::StatisticSetU8(a) => Arc::as_ptr(a).hash(state), + Self::StatisticSetI8(a) => Arc::as_ptr(a).hash(state), + Self::StatisticSetU32(a) => Arc::as_ptr(a).hash(state), + Self::StaticStatisticSetU16(a) => Arc::as_ptr(a).hash(state), + Self::Form(a) => Arc::as_ptr(a).hash(state), + Self::LearnableMoves(a) => Arc::as_ptr(a).hash(state), + Self::GrowthRate(a) => Arc::as_ptr(a).hash(state), + Self::Item(a) => Arc::as_ptr(a).hash(state), + Self::SecondaryEffect(a) => Arc::as_ptr(a).hash(state), + Self::MoveData(a) => Arc::as_ptr(a).hash(state), + Self::Nature(a) => Arc::as_ptr(a).hash(state), + Self::Species(a) => Arc::as_ptr(a).hash(state), + Self::SpeciesLibrary(a) => Arc::as_ptr(a).hash(state), + Self::MoveLibrary(a) => Arc::as_ptr(a).hash(state), + Self::AbilityLibrary(a) => Arc::as_ptr(a).hash(state), + Self::ItemLibrary(a) => Arc::as_ptr(a).hash(state), + Self::GrowthRateLibrary(a) => Arc::as_ptr(a).hash(state), + Self::LibrarySettings(a) => Arc::as_ptr(a).hash(state), + Self::NatureLibrary(a) => Arc::as_ptr(a).hash(state), + Self::TypeLibrary(a) => Arc::as_ptr(a).hash(state), + Self::StaticData(a) => Arc::as_ptr(a).hash(state), + Self::TurnChoice(a) => Arc::as_ptr(a).hash(state), + Self::Pokemon(a) => a.as_ptr().hash(state), + Self::LearnedMove(a) => Arc::as_ptr(a).hash(state), + Self::PokemonParty(a) => Arc::as_ptr(a).hash(state), + Self::BattleParty(a) => Arc::as_ptr(a).hash(state), + Self::Battle(a) => a.as_ptr().hash(state), + Self::BattleSide(a) => a.as_ptr().hash(state), + Self::BattleRandom(a) => Arc::as_ptr(a).hash(state), + Self::BattleStatCalculator(a) => Arc::as_ptr(a).hash(state), + Self::DamageLibrary(a) => Arc::as_ptr(a).hash(state), + Self::MiscLibrary(a) => Arc::as_ptr(a).hash(state), + Self::ScriptResolver(a) => Arc::as_ptr(a).hash(state), + Self::DynamicLibrary(a) => Arc::as_ptr(a).hash(state), + } + } +} + +impl PartialEq for FFIObject { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Ability(a), Self::Ability(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::EffectParameter(a), Self::EffectParameter(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::StatisticSetU8(a), Self::StatisticSetU8(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::StatisticSetI8(a), Self::StatisticSetI8(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::StatisticSetU32(a), Self::StatisticSetU32(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::StaticStatisticSetU16(a), Self::StaticStatisticSetU16(b)) => { + Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr() + } + (Self::Form(a), Self::Form(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::LearnableMoves(a), Self::LearnableMoves(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::GrowthRate(a), Self::GrowthRate(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::Item(a), Self::Item(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::SecondaryEffect(a), Self::SecondaryEffect(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::MoveData(a), Self::MoveData(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::Nature(a), Self::Nature(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::Species(a), Self::Species(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::SpeciesLibrary(a), Self::SpeciesLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::MoveLibrary(a), Self::MoveLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::AbilityLibrary(a), Self::AbilityLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::ItemLibrary(a), Self::ItemLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::GrowthRateLibrary(a), Self::GrowthRateLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::LibrarySettings(a), Self::LibrarySettings(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::NatureLibrary(a), Self::NatureLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::TypeLibrary(a), Self::TypeLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::StaticData(a), Self::StaticData(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::TurnChoice(a), Self::TurnChoice(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::Pokemon(a), Self::Pokemon(b)) => a.eq(b), + (Self::LearnedMove(a), Self::LearnedMove(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::PokemonParty(a), Self::PokemonParty(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::BattleParty(a), Self::BattleParty(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::Battle(a), Self::Battle(b)) => a.eq(b), + (Self::BattleSide(a), Self::BattleSide(b)) => a.eq(b), + (Self::BattleRandom(a), Self::BattleRandom(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::BattleStatCalculator(a), Self::BattleStatCalculator(b)) => { + Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr() + } + (Self::DamageLibrary(a), Self::DamageLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::MiscLibrary(a), Self::MiscLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::ScriptResolver(a), Self::ScriptResolver(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + (Self::DynamicLibrary(a), Self::DynamicLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), + _ => false, + } + } +} + +macro_rules! ffi_obj_conversions { + ($res_type:ty, $ffi_obj_name:ident) => { + impl From<$res_type> for FFIObject { + fn from(a: $res_type) -> Self { + Self::$ffi_obj_name(a) + } + } + + impl FromFFIHandle<$res_type> for FFIHandle<$res_type> { + fn from_ffi_handle(&self) -> $res_type { + match self.resolve() { + FFIObject::$ffi_obj_name(a) => a.clone(), + _ => panic!("Invalid handle"), + } + } + + fn from_ffi_handle_opt(&self) -> Option<$res_type> { + if (self.is_none()) { + return None; + } + match self.resolve() { + FFIObject::$ffi_obj_name(a) => Some(a.clone()), + _ => panic!("Invalid handle"), + } + } + } + }; +} + +ffi_obj_conversions!(Arc, Ability); +ffi_obj_conversions!(Arc, EffectParameter); +ffi_obj_conversions!(Arc>, StatisticSetI8); +ffi_obj_conversions!(Arc>, StatisticSetU8); +ffi_obj_conversions!(Arc>, StatisticSetU32); +ffi_obj_conversions!(Arc>, StaticStatisticSetU16); +ffi_obj_conversions!(Arc, Form); +ffi_obj_conversions!(Arc, LearnableMoves); +ffi_obj_conversions!(Arc, GrowthRate); +ffi_obj_conversions!(Arc, Item); +ffi_obj_conversions!(Arc, SecondaryEffect); +ffi_obj_conversions!(Arc, MoveData); +ffi_obj_conversions!(Arc, Nature); +ffi_obj_conversions!(Arc, Species); +ffi_obj_conversions!(Arc, SpeciesLibrary); +ffi_obj_conversions!(Arc, MoveLibrary); +ffi_obj_conversions!(Arc, AbilityLibrary); +ffi_obj_conversions!(Arc, ItemLibrary); +ffi_obj_conversions!(Arc, GrowthRateLibrary); +ffi_obj_conversions!(Arc, LibrarySettings); +ffi_obj_conversions!(Arc, NatureLibrary); +ffi_obj_conversions!(Arc, TypeLibrary); +ffi_obj_conversions!(Arc, StaticData); +ffi_obj_conversions!(Arc, TurnChoice); +ffi_obj_conversions!(crate::dynamic_data::Pokemon, Pokemon); +ffi_obj_conversions!(Arc, LearnedMove); +ffi_obj_conversions!(Arc, PokemonParty); +ffi_obj_conversions!(Arc, BattleParty); +ffi_obj_conversions!(crate::dynamic_data::Battle, Battle); +ffi_obj_conversions!(crate::dynamic_data::BattleSide, BattleSide); +ffi_obj_conversions!(Arc, BattleRandom); +ffi_obj_conversions!(Arc, BattleStatCalculator); +ffi_obj_conversions!(Arc, DamageLibrary); +ffi_obj_conversions!(Arc, MiscLibrary); +ffi_obj_conversions!(Arc, ScriptResolver); +ffi_obj_conversions!(Arc, DynamicLibrary); diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 5f4f45f..80c1bdc 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -1,68 +1,57 @@ /// The foreign function interfaces for the dynamic data mod dynamic_data; +mod ffi_handle; /// The foreign function interfaces for that static data mod static_data; +pub(self) use ffi_handle::*; + /// Helper type for clearer functions. -type OwnedPtr = *mut T; +type OwnedPtrString = *mut c_char; /// Helper type for clearer functions. -type BorrowedPtr = *const T; +type NonOwnedPtrString = *const c_char; /// Generates a basic getter foreign function interface. -macro_rules! ffi_arc_getter { +macro_rules! ffi_handle_arc_dyn_getter { ( $type:ty, $func:ident, $returns: ty ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer>) -> $returns { - ptr.as_ref().$func() - } - } - }; -} - -/// Generates a basic getter foreign function interface. -macro_rules! ffi_arc_dyn_getter { - ( - $type:ty, $func:ident, $returns: ty - ) => { - paste::paste! { - #[no_mangle] - extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer>) -> $returns { - ptr.as_ref().$func() + extern "C" fn [< $type:snake _ $func >](ptr: FFIHandle>) -> $returns { + ptr.from_ffi_handle().$func() } } }; } /// Generates a basic getter foreign function interface where the return type is a [`crate::StringKey`]. -macro_rules! ffi_arc_stringkey_getter { +macro_rules! ffi_handle_arc_stringkey_getter { ( $type:ty, $func:ident ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $type:lower _ $func >](ptr: ExternPointer>) -> OwnedPtr { - std::ffi::CString::new(ptr.as_ref().$func().str()).unwrap().into_raw() + extern "C" fn [< $type:lower _ $func >](ptr: FFIHandle>) -> NonOwnedPtrString { + std::ffi::CString::new(ptr.from_ffi_handle().$func().str()).unwrap().into_raw() } } }; } /// Generates a foreign function interface for a vec. This generates a length function, and a getter. -macro_rules! ffi_vec_value_getters { +macro_rules! ffi_handle_vec_value_getters { ( $name:ident, $type:ty, $func:ident, $returns: ty ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $name:lower _ $func _length>](ptr: ExternPointer>) -> usize { - ptr.as_ref().$func().len() + extern "C" fn [< $name:lower _ $func _length>](ptr: FFIHandle>) -> usize { + ptr.from_ffi_handle().$func().len() } #[no_mangle] - extern "C" fn [< $name:lower _ $func _get>](ptr: ExternPointer>, index: usize) -> $returns { - *ptr.as_ref().$func().get(index).unwrap() + extern "C" fn [< $name:lower _ $func _get>](ptr: FFIHandle>, index: usize) -> $returns { + *ptr.from_ffi_handle().$func().get(index).unwrap() } } }; @@ -70,33 +59,28 @@ macro_rules! ffi_vec_value_getters { /// Generates a foreign function interface for a vec of [`crate::StringKey`]. This generates a /// length function, and a getter. -macro_rules! ffi_vec_stringkey_getters { +macro_rules! ffi_handle_vec_stringkey_getters { ( $type:ty, $func:ident ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer>) -> usize { - ptr.as_ref().$func().len() + extern "C" fn [< $type:lower _ $func _length>](ptr: FFIHandle>) -> usize { + ptr.from_ffi_handle().$func().len() } #[no_mangle] - extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer>, index: usize) -> OwnedPtr { - CString::new(ptr.as_ref().$func().get(index).unwrap().str()).unwrap().into_raw() + extern "C" fn [< $type:lower _ $func _get>](ptr: FFIHandle>, index: usize) -> OwnedPtrString { + CString::new(ptr.from_ffi_handle().$func().get(index).unwrap().str()).unwrap().into_raw() } } }; } -use crate::dynamic_data::{Battle, Pokemon}; -use crate::{ValueIdentifiable, ValueIdentifier}; -pub(self) use ffi_arc_dyn_getter; -pub(self) use ffi_arc_getter; -pub(self) use ffi_arc_stringkey_getter; -pub(self) use ffi_vec_stringkey_getters; -pub(self) use ffi_vec_value_getters; +pub(self) use ffi_handle_arc_dyn_getter; +pub(self) use ffi_handle_arc_stringkey_getter; +pub(self) use ffi_handle_vec_stringkey_getters; +pub(self) use ffi_handle_vec_value_getters; use std::ffi::{c_char, CString}; -use std::mem::transmute; -use std::sync::Arc; /// Helper utility class to wrap a pointer for extern functions. #[repr(C)] @@ -115,184 +99,6 @@ impl ExternPointer { .unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::())) } } - /// Get the internal pointer as mutable reference. - #[allow(clippy::panic)] // We currently allow this as these should never be null, but we might want to change this in the future. - pub(self) fn as_mut(&mut self) -> &mut T { - unsafe { - self.ptr - .as_mut() - .unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::())) - } - } -} - -/// Helper utility class to give both the pointer and identifier to a FFI. -#[repr(C)] -pub(self) struct IdentifiablePointer { - /// The wrapped pointer. - pub ptr: *const T, - /// The identifier of the pointer. - pub id: usize, -} - -impl Clone for IdentifiablePointer { - fn clone(&self) -> Self { - Self { - id: self.id, - ptr: self.ptr, - } - } -} - -impl Copy for IdentifiablePointer {} - -impl IdentifiablePointer { - /// Creates a new IdentifiablePointer. - pub(self) fn new(ptr: *const T, id: ValueIdentifier) -> Self { - unsafe { Self { ptr, id: transmute(id) } } - } -} - -impl From<*mut T> for ExternPointer { - fn from(ptr: *mut T) -> Self { - ExternPointer { ptr } - } -} - -impl From> for IdentifiablePointer> { - fn from(v: Arc) -> Self { - let id = v.value_identifier().value(); - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } -} - -impl From>> for IdentifiablePointer> { - fn from(v: Option>) -> Self { - if let Some(v) = v { - let id = unsafe { transmute(v.value_identifier()) }; - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } else { - IdentifiablePointer::none() - } - } -} - -impl From> for IdentifiablePointer> { - fn from(v: Box) -> Self { - let id = unsafe { transmute(v.value_identifier()) }; - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } -} - -impl From<&Box> for IdentifiablePointer> { - fn from(v: &Box) -> Self { - let id = unsafe { transmute(v.value_identifier()) }; - Self { - ptr: v as *const Box, - id, - } - } -} - -impl From>> for IdentifiablePointer> { - fn from(v: Option>) -> Self { - if let Some(v) = v { - let id = unsafe { transmute(v.value_identifier()) }; - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } else { - IdentifiablePointer::none() - } - } -} - -impl From<&Option>> for IdentifiablePointer> { - fn from(v: &Option>) -> Self { - if let Some(v) = v { - let id = unsafe { transmute(v.value_identifier()) }; - unsafe { - Self { - ptr: *Box::into_raw(Box::new(v as *const Box)), - id, - } - } - } else { - IdentifiablePointer::none() - } - } -} - -impl From> for IdentifiablePointer { - fn from(v: Box) -> Self { - let id = unsafe { transmute(v.value_identifier()) }; - Self { - ptr: Box::into_raw(v), - id, - } - } -} - -impl From<*const T> for IdentifiablePointer { - #[allow(clippy::unwrap_used)] // We currently allow this as these should never be null, but we might want to change this in the future. - fn from(v: *const T) -> Self { - let id = unsafe { transmute(v.as_ref().unwrap().value_identifier()) }; - Self { ptr: v, id } - } -} - -impl From for IdentifiablePointer { - fn from(v: Pokemon) -> Self { - let id = v.value_identifier().value(); - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } -} - -impl From> for IdentifiablePointer { - fn from(v: Option) -> Self { - if let Some(v) = v { - let id = unsafe { transmute(v.value_identifier()) }; - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } else { - IdentifiablePointer::none() - } - } -} - -impl From for IdentifiablePointer { - fn from(v: Battle) -> Self { - let id = v.value_identifier().value(); - Self { - ptr: Box::into_raw(Box::new(v)), - id, - } - } -} - -impl IdentifiablePointer { - /// Returns an identifiable pointer with null as pointer, and 0 as identifier. - pub fn none() -> Self { - Self { - ptr: std::ptr::null(), - id: Default::default(), - } - } } /// Helper utility class to give either the data or an error to a FFI. @@ -301,19 +107,19 @@ union ResultUnion { /// If the result is ok, this contains the value. ok: T, /// If the result is an error, this contains the error message. - err: OwnedPtr, + err: NonOwnedPtrString, } /// The result of a FFI call that can either be an error or a value. #[repr(C)] -pub struct NativeResult { +pub struct FFIResult { /// If the result is ok, this is 1, otherwise 0. ok: u8, /// The value or error. value: ResultUnion, } -impl NativeResult { +impl FFIResult { /// Creates a new NativeResult with the given value. pub fn ok(value: T) -> Self { Self { @@ -344,7 +150,7 @@ impl NativeResult { } } -impl From> for NativeResult { +impl From> for FFIResult { fn from(value: anyhow::Result) -> Self { match value { Ok(v) => Self::ok(v), @@ -353,7 +159,7 @@ impl From> for NativeResult { } } -impl From for NativeResult { +impl From for FFIResult { fn from(value: T) -> Self { Self::ok(value) } diff --git a/src/ffi/static_data/ability.rs b/src/ffi/static_data/ability.rs index 146718a..43877dc 100644 --- a/src/ffi/static_data/ability.rs +++ b/src/ffi/static_data/ability.rs @@ -1,9 +1,10 @@ -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::FFIHandle; +use crate::ffi::FromFFIHandle; +use crate::ffi::{FFIResult, OwnedPtrString}; use crate::static_data::{Ability, AbilityImpl, EffectParameter}; use crate::StringKey; use anyhow::anyhow; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new ability. @@ -11,67 +12,61 @@ use std::sync::Arc; unsafe extern "C" fn ability_new( name: *const c_char, effect: *const c_char, - parameters: *const OwnedPtr>, + parameters: *const FFIHandle>, parameters_length: usize, -) -> NativeResult>> { +) -> FFIResult>> { let parameters = std::slice::from_raw_parts(parameters, parameters_length); let mut parameters_vec: Vec> = Vec::with_capacity(parameters_length); for parameter in parameters { - parameters_vec.push(parameter.read()); + parameters_vec.push(parameter.from_ffi_handle()); } let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(s) => s.into(), - Err(_) => return NativeResult::err(anyhow!("Failed to convert name to CStr")), + Err(_) => return FFIResult::err(anyhow!("Failed to convert name to CStr")), }; let effect: StringKey = match CStr::from_ptr(effect).to_str() { Ok(s) => s.into(), - Err(_) => return NativeResult::err(anyhow!("Failed to convert effect to CStr")), + Err(_) => return FFIResult::err(anyhow!("Failed to convert effect to CStr")), }; let arc: Arc = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec)); - NativeResult::ok(arc.into()) -} - -/// Drops a reference counted ability. -#[no_mangle] -unsafe extern "C" fn ability_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIResult::ok(FFIHandle::get_handle(arc.into())) } /// The name of the ability. #[no_mangle] -unsafe extern "C" fn ability_name(ptr: ExternPointer>) -> NativeResult> { - match CString::new(ptr.as_ref().name().str()) { - Ok(s) => NativeResult::ok(s.into_raw()), - Err(_) => NativeResult::err(anyhow!("Failed to convert name to CString")), +unsafe extern "C" fn ability_name(handle: FFIHandle>) -> FFIResult { + match CString::new(handle.from_ffi_handle().name().str()) { + Ok(s) => FFIResult::ok(s.into_raw()), + Err(_) => FFIResult::err(anyhow!("Failed to convert name to CString")), } } /// The name of the script effect of the ability. #[no_mangle] -unsafe extern "C" fn ability_effect(ptr: ExternPointer>) -> NativeResult> { - match CString::new(ptr.as_ref().effect().str()) { - Ok(s) => NativeResult::ok(s.into_raw()), - Err(_) => NativeResult::err(anyhow!("Failed to convert effect to CString")), +unsafe extern "C" fn ability_effect(ptr: FFIHandle>) -> FFIResult { + match CString::new(ptr.from_ffi_handle().effect().str()) { + Ok(s) => FFIResult::ok(s.into_raw()), + Err(_) => FFIResult::err(anyhow!("Failed to convert effect to CString")), } } /// The length of the parameters for the script effect of the ability. #[no_mangle] -unsafe extern "C" fn ability_parameter_length(ptr: ExternPointer>) -> usize { - ptr.as_ref().parameters().len() +unsafe extern "C" fn ability_parameter_length(ptr: FFIHandle>) -> usize { + ptr.from_ffi_handle().parameters().len() } /// Gets a parameter for the script effect of the ability. #[no_mangle] unsafe extern "C" fn ability_parameter_get( - ptr: ExternPointer>, + ptr: FFIHandle>, index: usize, -) -> IdentifiablePointer> { - if let Some(p) = ptr.as_ref().parameters().get(index) { - p.clone().into() +) -> FFIHandle> { + if let Some(p) = ptr.from_ffi_handle().parameters().get(index) { + FFIHandle::get_handle(p.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } diff --git a/src/ffi/static_data/form.rs b/src/ffi/static_data/form.rs index 0e34eae..c9911e9 100644 --- a/src/ffi/static_data/form.rs +++ b/src/ffi/static_data/form.rs @@ -1,13 +1,13 @@ +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::ffi::{ - ffi_arc_dyn_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer, - IdentifiablePointer, NativeResult, OwnedPtr, + ffi_handle_arc_dyn_getter, ffi_handle_vec_stringkey_getters, ffi_handle_vec_value_getters, FFIResult, + NonOwnedPtrString, OwnedPtrString, }; use crate::static_data::{Form, FormImpl, LearnableMoves, StaticStatisticSet, TypeIdentifier}; use crate::StringKey; use anyhow::anyhow; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new form. @@ -19,18 +19,18 @@ unsafe extern "C" fn form_new( base_experience: u32, types: *const TypeIdentifier, types_length: usize, - base_stats: OwnedPtr>, - abilities: *const BorrowedPtr, + base_stats: FFIHandle>>, + abilities: *const NonOwnedPtrString, abilities_length: usize, - hidden_abilities: *const BorrowedPtr, + hidden_abilities: *const NonOwnedPtrString, hidden_abilities_length: usize, - moves: OwnedPtr>, + moves: FFIHandle>, flags: *const *const c_char, flags_length: usize, -) -> NativeResult>> { +) -> FFIResult>> { let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), - Err(_) => return NativeResult::err(anyhow!("Unable to convert name to string")), + Err(_) => return FFIResult::err(anyhow!("Unable to convert name to string")), }; let abilities = std::slice::from_raw_parts(abilities, abilities_length); @@ -49,7 +49,7 @@ unsafe extern "C" fn form_new( for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, - Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")), + Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")), }; flags_set.insert(flag.into()); } @@ -60,57 +60,50 @@ unsafe extern "C" fn form_new( weight, base_experience, std::slice::from_raw_parts(types, types_length).to_vec(), - *Box::from_raw(base_stats), + base_stats.from_ffi_handle(), abilities_vec, hidden_abilities_vec, - *Box::from_raw(moves), + moves.from_ffi_handle(), flags_set, )); - NativeResult::ok(a.into()) -} - -/// Drops a reference count for a form. -#[no_mangle] -unsafe extern "C" fn form_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIResult::ok(FFIHandle::get_handle(a.into())) } /// The name of the form. #[no_mangle] -unsafe extern "C" fn form_name(ptr: ExternPointer>) -> NativeResult> { - let name = ptr.as_ref().name(); +unsafe extern "C" fn form_name(ptr: FFIHandle>) -> FFIResult { + let obj = ptr.from_ffi_handle(); + let name = obj.name(); match CString::new(name.str()) { - Ok(name) => NativeResult::ok(name.into_raw()), - Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), + Ok(name) => FFIResult::ok(name.into_raw()), + Err(_) => FFIResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), } } -ffi_arc_dyn_getter!(Form, height, f32); -ffi_arc_dyn_getter!(Form, weight, f32); -ffi_arc_dyn_getter!(Form, base_experience, u32); +ffi_handle_arc_dyn_getter!(Form, height, f32); +ffi_handle_arc_dyn_getter!(Form, weight, f32); +ffi_handle_arc_dyn_getter!(Form, base_experience, u32); -ffi_vec_value_getters!(Form, dyn Form, types, TypeIdentifier); +ffi_handle_vec_value_getters!(Form, dyn Form, types, TypeIdentifier); /// The inherent values of a form of species that are used for the stats of a Pokemon. #[no_mangle] -unsafe extern "C" fn form_base_stats( - ptr: ExternPointer>, -) -> IdentifiablePointer>> { - ptr.as_ref().base_stats().clone().into() +unsafe extern "C" fn form_base_stats(ptr: FFIHandle>) -> FFIHandle>> { + FFIHandle::get_handle(ptr.from_ffi_handle().base_stats().clone().into()) } -ffi_vec_stringkey_getters!(Form, abilities); -ffi_vec_stringkey_getters!(Form, hidden_abilities); +ffi_handle_vec_stringkey_getters!(Form, abilities); +ffi_handle_vec_stringkey_getters!(Form, hidden_abilities); /// The moves a Pokemon with this form can learn. #[no_mangle] -extern "C" fn form_moves(ptr: ExternPointer>) -> BorrowedPtr> { - ptr.as_ref().moves() as *const Box +extern "C" fn form_moves(ptr: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(ptr.from_ffi_handle().moves().clone().into()) } /// Check if the form has a specific flag set. #[no_mangle] -unsafe extern "C" fn form_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { +unsafe extern "C" fn form_has_flag(ptr: FFIHandle>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); - u8::from(ptr.as_ref().has_flag(&flag)) + u8::from(ptr.from_ffi_handle().has_flag(&flag)) } diff --git a/src/ffi/static_data/growth_rate.rs b/src/ffi/static_data/growth_rate.rs index 6e45ce9..1ae3e48 100644 --- a/src/ffi/static_data/growth_rate.rs +++ b/src/ffi/static_data/growth_rate.rs @@ -1,33 +1,26 @@ use crate::defines::LevelInt; -use crate::ffi::{ExternPointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use crate::static_data::{GrowthRate, LookupGrowthRate}; -use std::ptr::drop_in_place; +use std::sync::Arc; /// Instantiates a new lookup growth rate. The experience array should be the amount of experience /// required per level, with the first element being the experience required for level 1 (generally 0). #[no_mangle] -unsafe extern "C" fn growth_rate_lookup_new(array: *const u32, length: usize) -> OwnedPtr> { +unsafe extern "C" fn growth_rate_lookup_new(array: *const u32, length: usize) -> FFIHandle> { let array = std::slice::from_raw_parts(array, length); - Box::into_raw(Box::new(Box::new(LookupGrowthRate::new(array.to_vec())))) -} - -/// Drops the growth rate. -#[no_mangle] -unsafe extern "C" fn growth_rate_lookup_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + let g: Arc = Arc::new(LookupGrowthRate::new(array.to_vec())); + FFIHandle::get_handle(g.into()) } /// Calculate the level something with this growth rate would have at a certain experience. #[no_mangle] -extern "C" fn growth_rate_calculate_level(ptr: ExternPointer>, experience: u32) -> LevelInt { - ptr.as_ref().calculate_level(experience) +extern "C" fn growth_rate_calculate_level(ptr: FFIHandle>, experience: u32) -> LevelInt { + ptr.from_ffi_handle().calculate_level(experience) } /// Calculate the experience something with this growth rate would have at a certain level. #[no_mangle] -extern "C" fn growth_rate_calculate_experience( - ptr: ExternPointer>, - level: LevelInt, -) -> NativeResult { - ptr.as_ref().calculate_experience(level).into() +extern "C" fn growth_rate_calculate_experience(ptr: FFIHandle>, level: LevelInt) -> FFIResult { + ptr.from_ffi_handle().calculate_experience(level).into() } diff --git a/src/ffi/static_data/item.rs b/src/ffi/static_data/item.rs index 0a62db1..109f874 100644 --- a/src/ffi/static_data/item.rs +++ b/src/ffi/static_data/item.rs @@ -1,10 +1,10 @@ -use crate::ffi::{ffi_arc_dyn_getter, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{ffi_handle_arc_dyn_getter, FFIResult, OwnedPtrString}; use crate::static_data::{BattleItemCategory, Item, ItemCategory, ItemImpl}; use crate::StringKey; use anyhow::anyhow; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates an item. @@ -16,48 +16,43 @@ unsafe extern "C" fn item_new( price: i32, flags: *const *const c_char, flags_length: usize, -) -> NativeResult>> { +) -> FFIResult>> { let flags = std::slice::from_raw_parts(flags, flags_length); let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), - Err(_) => return NativeResult::err(anyhow!("Unable to convert name to string")), + Err(_) => return FFIResult::err(anyhow!("Unable to convert name to string")), }; let mut flags_set: HashSet = HashSet::with_capacity(flags_length); for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, - Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")), + Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")), }; flags_set.insert(flag.into()); } let item: Arc = Arc::new(ItemImpl::new(&name, category, battle_category, price, flags_set)); - NativeResult::ok(item.into()) -} - -/// Drops a reference counted item. -#[no_mangle] -unsafe extern "C" fn item_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIResult::ok(FFIHandle::get_handle(item.into())) } /// The name of the item. #[no_mangle] -unsafe extern "C" fn item_name(ptr: ExternPointer>) -> NativeResult> { - let name = ptr.as_ref().name(); +unsafe extern "C" fn item_name(ptr: FFIHandle>) -> FFIResult { + let item = ptr.from_ffi_handle(); + let name = item.name(); match CString::new(name.str()) { - Ok(name) => NativeResult::ok(name.into_raw()), - Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), + Ok(name) => FFIResult::ok(name.into_raw()), + Err(_) => FFIResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), } } -ffi_arc_dyn_getter!(Item, category, ItemCategory); -ffi_arc_dyn_getter!(Item, battle_category, BattleItemCategory); -ffi_arc_dyn_getter!(Item, price, i32); +ffi_handle_arc_dyn_getter!(Item, category, ItemCategory); +ffi_handle_arc_dyn_getter!(Item, battle_category, BattleItemCategory); +ffi_handle_arc_dyn_getter!(Item, price, i32); /// Checks whether the item has a specific flag. #[no_mangle] -unsafe extern "C" fn item_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { +unsafe extern "C" fn item_has_flag(ptr: FFIHandle>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); - u8::from(ptr.as_ref().has_flag(&flag)) + u8::from(ptr.from_ffi_handle().has_flag(&flag)) } diff --git a/src/ffi/static_data/learnable_moves.rs b/src/ffi/static_data/learnable_moves.rs index 57ac9ac..966ec71 100644 --- a/src/ffi/static_data/learnable_moves.rs +++ b/src/ffi/static_data/learnable_moves.rs @@ -1,29 +1,25 @@ use crate::defines::LevelInt; -use crate::ffi::{BorrowedPtr, ExternPointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{FFIResult, NonOwnedPtrString}; use crate::static_data::{LearnableMoves, LearnableMovesImpl}; -use std::ffi::{c_char, CStr}; -use std::ptr::drop_in_place; +use std::ffi::CStr; +use std::sync::Arc; /// Instantiates a new Learnable Moves. #[no_mangle] -extern "C" fn learnable_moves_new(max_level: LevelInt) -> OwnedPtr> { - Box::into_raw(Box::new(Box::new(LearnableMovesImpl::new(max_level)))) -} - -/// drops a learnablemoves struct. -#[no_mangle] -unsafe extern "C" fn learnable_moves_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) +extern "C" fn learnable_moves_new(max_level: LevelInt) -> FFIHandle> { + let p: Arc = Arc::new(LearnableMovesImpl::new(max_level)); + FFIHandle::get_handle(p.into()) } /// Adds a new level move the Pokemon can learn. #[no_mangle] unsafe extern "C" fn learnable_moves_add_level_move( - mut ptr: ExternPointer>, + ptr: FFIHandle>, level: LevelInt, - move_name: BorrowedPtr, -) -> NativeResult<()> { - ptr.as_mut() + move_name: NonOwnedPtrString, +) -> FFIResult<()> { + ptr.from_ffi_handle() .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 020ed0d..66bb63e 100644 --- a/src/ffi/static_data/libraries/growth_rate_library.rs +++ b/src/ffi/static_data/libraries/growth_rate_library.rs @@ -1,30 +1,25 @@ use crate::defines::LevelInt; -use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{FFIResult, NonOwnedPtrString}; use crate::static_data::{GrowthRate, GrowthRateLibrary, GrowthRateLibraryImpl}; -use std::ffi::{c_char, CStr}; -use std::ptr::drop_in_place; +use std::ffi::CStr; +use std::sync::Arc; /// Instantiates a new growth rate library with a capacity #[no_mangle] -extern "C" fn growth_rate_library_new(capacity: usize) -> IdentifiablePointer> { - let b: Box = Box::new(GrowthRateLibraryImpl::new(capacity)); - b.into() -} - -/// Drops the growthrate library. -#[no_mangle] -unsafe extern "C" fn growth_rate_library_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) +extern "C" fn growth_rate_library_new(capacity: usize) -> FFIHandle> { + let b: Arc = Arc::new(GrowthRateLibraryImpl::new(capacity)); + FFIHandle::get_handle(b.into()) } /// Calculates the level for a given growth key name and a certain experience. #[no_mangle] unsafe extern "C" fn growth_rate_library_calculate_level( - ptr: ExternPointer>, - growth_rate: BorrowedPtr, + ptr: FFIHandle>, + growth_rate: NonOwnedPtrString, experience: u32, -) -> NativeResult { - ptr.as_ref() +) -> FFIResult { + ptr.from_ffi_handle() .calculate_level(&CStr::from_ptr(growth_rate).into(), experience) .into() } @@ -32,11 +27,11 @@ unsafe extern "C" fn growth_rate_library_calculate_level( /// Calculates the experience for a given growth key name and a certain level. #[no_mangle] unsafe extern "C" fn growth_rate_library_calculate_experience( - ptr: ExternPointer>, - growth_rate: BorrowedPtr, + ptr: FFIHandle>, + growth_rate: NonOwnedPtrString, level: LevelInt, -) -> NativeResult { - ptr.as_ref() +) -> FFIResult { + ptr.from_ffi_handle() .calculate_experience(&CStr::from_ptr(growth_rate).into(), level) .into() } @@ -44,10 +39,10 @@ unsafe extern "C" fn growth_rate_library_calculate_experience( /// Adds a new growth rate with a name and value. #[no_mangle] unsafe extern "C" fn growth_rate_library_add_growth_rate( - mut ptr: ExternPointer>, - name: BorrowedPtr, - growth_rate: OwnedPtr>, + ptr: FFIHandle>, + name: NonOwnedPtrString, + growth_rate: FFIHandle>, ) { - ptr.as_mut() - .add_growth_rate(&CStr::from_ptr(name).into(), *Box::from_raw(growth_rate)); + ptr.from_ffi_handle() + .add_growth_rate(&CStr::from_ptr(name).into(), growth_rate.from_ffi_handle()); } diff --git a/src/ffi/static_data/libraries/library_settings.rs b/src/ffi/static_data/libraries/library_settings.rs index ac2abad..467695e 100644 --- a/src/ffi/static_data/libraries/library_settings.rs +++ b/src/ffi/static_data/libraries/library_settings.rs @@ -1,7 +1,8 @@ use crate::defines::LevelInt; -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::FFIResult; use crate::static_data::{LibrarySettings, LibrarySettingsImpl}; -use std::ptr::drop_in_place; +use std::sync::Arc; /// Creates a new settings library. /// - `maximum_level` is the highest level a Pokemon can be. @@ -12,32 +13,26 @@ use std::ptr::drop_in_place; extern "C" fn library_settings_new( max_level: LevelInt, shiny_rate: u32, -) -> NativeResult>> { +) -> FFIResult>> { match LibrarySettingsImpl::new(max_level, shiny_rate) { Ok(settings) => { - let b: Box = Box::new(settings); - let p: IdentifiablePointer> = b.into(); - p.into() + let b: Arc = Arc::new(settings); + let p: FFIHandle> = FFIHandle::get_handle(b.into()); + FFIResult::ok(p) } - Err(e) => NativeResult::err(e), + Err(e) => FFIResult::err(e), } } -/// Drop a library settings object. -#[no_mangle] -unsafe extern "C" fn library_settings_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) -} - /// The highest level a Pokemon can be. #[no_mangle] -extern "C" fn library_settings_maximum_level(ptr: ExternPointer>) -> LevelInt { - ptr.as_ref().maximum_level() +extern "C" fn library_settings_maximum_level(ptr: FFIHandle>) -> LevelInt { + ptr.from_ffi_handle().maximum_level() } /// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator /// is 1. For example, if this is 1000, then the chance of a Pokemon being shiny is 1/1000. #[no_mangle] -extern "C" fn library_settings_shiny_rate(ptr: ExternPointer>) -> u32 { - ptr.as_ref().shiny_rate() +extern "C" fn library_settings_shiny_rate(ptr: FFIHandle>) -> u32 { + ptr.from_ffi_handle().shiny_rate() } diff --git a/src/ffi/static_data/libraries/mod.rs b/src/ffi/static_data/libraries/mod.rs index 6c04091..cc80160 100644 --- a/src/ffi/static_data/libraries/mod.rs +++ b/src/ffi/static_data/libraries/mod.rs @@ -9,10 +9,10 @@ mod static_data; /// The foreign function interface for the type library. mod type_library; -use crate::ffi::{BorrowedPtr, IdentifiablePointer, OwnedPtr}; +use crate::ffi::{FFIHandle, FromFFIHandle}; +use crate::ffi::{NonOwnedPtrString, OwnedPtrString}; use crate::static_data::*; -use std::ffi::{c_char, CStr}; -use std::ptr::drop_in_place; +use std::ffi::CStr; use std::sync::Arc; /// Generates foreign function interfaces for a DataLibrary trait implementation. @@ -20,42 +20,37 @@ macro_rules! library_interface { ($library_type_name:ident, $library_type:ty, $return_type:ty) => { paste::paste! { #[no_mangle] - extern "C" fn [< $library_type_name:snake _new >](capacity: usize) -> IdentifiablePointer<$library_type> { - let value: $library_type = Box::new([<$library_type_name Impl>]::new(capacity)); - value.into() + extern "C" fn [< $library_type_name:snake _new >](capacity: usize) -> FFIHandle<$library_type> { + let value: $library_type = Arc::new([<$library_type_name Impl>]::new(capacity)); + FFIHandle::get_handle(value.into()) } #[no_mangle] - unsafe extern "C" fn [< $library_type_name:snake _drop >](ptr: OwnedPtr<$library_type>) { - drop_in_place(ptr); + unsafe extern "C" fn [< $library_type_name:snake _add >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString, value: FFIHandle>) { + let lib = ptr.from_ffi_handle(); + lib.add(&CStr::from_ptr(key).into(), value.from_ffi_handle()); } #[no_mangle] - unsafe extern "C" fn [< $library_type_name:snake _add >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr, value: OwnedPtr>) { - let lib = ptr.as_mut().unwrap(); - lib.add(&CStr::from_ptr(key).into(), *Box::from_raw(value)); - } - - #[no_mangle] - unsafe extern "C" fn [< $library_type_name:snake _remove >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr) { - let lib = ptr.as_mut().unwrap(); + unsafe extern "C" fn [< $library_type_name:snake _remove >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString) { + let lib = ptr.from_ffi_handle(); lib.remove(&CStr::from_ptr(key).into()); } #[no_mangle] - unsafe extern "C" fn [< $library_type_name:snake _get >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr) -> IdentifiablePointer> { - let lib = ptr.as_mut().unwrap(); + unsafe extern "C" fn [< $library_type_name:snake _get >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString) -> FFIHandle> { + let lib = ptr.from_ffi_handle(); let v = lib.get(&CStr::from_ptr(key).into()); if let Some(value) = v { - value.clone().into() + FFIHandle::get_handle(value.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } #[no_mangle] - unsafe extern "C" fn [< $library_type_name:snake _get_key_by_index >](ptr: OwnedPtr<$library_type>, index: usize) -> OwnedPtr { - let lib = ptr.as_mut().unwrap(); + unsafe extern "C" fn [< $library_type_name:snake _get_key_by_index >](ptr: FFIHandle<$library_type>, index: usize) -> OwnedPtrString { + let lib = ptr.from_ffi_handle(); let v = lib.get_key_by_index(index); if let Some(value) = v { std::ffi::CString::new(value.str()).unwrap().into_raw() @@ -65,15 +60,15 @@ macro_rules! library_interface { } #[no_mangle] - unsafe extern "C" fn [< $library_type_name:snake _len >](ptr: OwnedPtr<$library_type>) -> usize { - let lib = ptr.as_mut().unwrap(); + unsafe extern "C" fn [< $library_type_name:snake _len >](ptr: FFIHandle<$library_type>) -> usize { + let lib = ptr.from_ffi_handle(); lib.len() } } }; } -library_interface!(SpeciesLibrary, Box, dyn Species); -library_interface!(MoveLibrary, Box, dyn MoveData); -library_interface!(AbilityLibrary, Box, dyn Ability); -library_interface!(ItemLibrary, Box, dyn Item); +library_interface!(SpeciesLibrary, Arc, dyn Species); +library_interface!(MoveLibrary, Arc, dyn MoveData); +library_interface!(AbilityLibrary, Arc, dyn Ability); +library_interface!(ItemLibrary, Arc, dyn Item); diff --git a/src/ffi/static_data/libraries/nature_library.rs b/src/ffi/static_data/libraries/nature_library.rs index 47f0a78..abd060d 100644 --- a/src/ffi/static_data/libraries/nature_library.rs +++ b/src/ffi/static_data/libraries/nature_library.rs @@ -1,84 +1,79 @@ -use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{FFIResult, NonOwnedPtrString, OwnedPtrString}; use crate::static_data::{Nature, NatureLibrary, NatureLibraryImpl}; use crate::{PkmnError, Random}; use anyhow::anyhow; -use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; +use std::ffi::{CStr, CString}; use std::sync::Arc; /// Creates a new nature library with a given capacity. #[no_mangle] -extern "C" fn nature_library_new(capacity: usize) -> IdentifiablePointer> { - let b: Box = Box::new(NatureLibraryImpl::new(capacity)); - b.into() -} - -/// Drop a nature library. -#[no_mangle] -unsafe extern "C" fn nature_library_drop(ptr: OwnedPtr>) { - drop_in_place(ptr); +extern "C" fn nature_library_new(capacity: usize) -> FFIHandle> { + let b: Arc = Arc::new(NatureLibraryImpl::new(capacity)); + FFIHandle::get_handle(b.into()) } /// Adds a new nature with name to the library. #[no_mangle] unsafe extern "C" fn nature_library_load_nature( - mut ptr: ExternPointer>, - name: BorrowedPtr, - nature: OwnedPtr>, -) -> NativeResult<()> { - let nature = nature.as_ref().ok_or(PkmnError::NullReference); + ptr: FFIHandle>, + name: NonOwnedPtrString, + nature: FFIHandle>, +) -> FFIResult<()> { + let nature = nature.from_ffi_handle_opt().ok_or(PkmnError::NullReference); match nature { Ok(nature) => { - ptr.as_mut().load_nature(CStr::from_ptr(name).into(), nature.clone()); - NativeResult::ok(()) + ptr.from_ffi_handle() + .load_nature(CStr::from_ptr(name).into(), nature.clone()); + FFIResult::ok(()) } - Err(e) => NativeResult::err(e.into()), + Err(e) => FFIResult::err(e.into()), } } /// Gets a nature by name. #[no_mangle] unsafe extern "C" fn nature_library_get_nature( - ptr: ExternPointer>, - name: BorrowedPtr, -) -> IdentifiablePointer> { - if let Some(nature) = ptr.as_ref().get_nature(&CStr::from_ptr(name).into()) { - nature.into() + ptr: FFIHandle>, + name: NonOwnedPtrString, +) -> FFIHandle> { + if let Some(nature) = ptr.from_ffi_handle().get_nature(&CStr::from_ptr(name).into()) { + FFIHandle::get_handle(nature.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Gets a random nature. #[no_mangle] unsafe extern "C" fn nature_library_get_random_nature( - ptr: ExternPointer>, + ptr: FFIHandle>, seed: u64, -) -> NativeResult>> { +) -> FFIResult>> { let mut rand = Random::new(seed as u128); - match ptr.as_ref().get_random_nature(&mut rand) { - Ok(nature) => NativeResult::ok(nature.into()), - Err(e) => NativeResult::err(e), + match ptr.from_ffi_handle().get_random_nature(&mut rand) { + Ok(nature) => FFIResult::ok(FFIHandle::get_handle(nature.into())), + Err(e) => FFIResult::err(e), } } /// Finds a nature name by nature. #[no_mangle] unsafe extern "C" fn nature_library_get_nature_name( - ptr: ExternPointer>, - nature: BorrowedPtr>, -) -> NativeResult> { - match nature.as_ref() { + ptr: FFIHandle>, + nature: FFIHandle>, +) -> FFIResult { + match nature.from_ffi_handle_opt() { Some(nature) => { - let name = ptr.as_ref().get_nature_name(nature); + let name = ptr.from_ffi_handle().get_nature_name(&nature); 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")), + Ok(cstr) => FFIResult::ok(cstr.into_raw()), + Err(_) => FFIResult::err(anyhow!("Failed to convert nature name to C string")), }, - Err(e) => NativeResult::err(e), + Err(e) => FFIResult::err(e), } } - None => NativeResult::err(PkmnError::NullReference.into()), + None => FFIResult::err(PkmnError::NullReference.into()), } } diff --git a/src/ffi/static_data/libraries/static_data.rs b/src/ffi/static_data/libraries/static_data.rs index 9532aab..c10d95d 100644 --- a/src/ffi/static_data/libraries/static_data.rs +++ b/src/ffi/static_data/libraries/static_data.rs @@ -1,102 +1,81 @@ -use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::static_data::{ AbilityLibrary, GrowthRateLibrary, ItemLibrary, LibrarySettings, MoveLibrary, NatureLibrary, SpeciesLibrary, StaticData, StaticDataImpl, TypeLibrary, }; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new data collection. #[no_mangle] unsafe extern "C" fn static_data_new( - settings: OwnedPtr>, - species: OwnedPtr>, - moves: OwnedPtr>, - items: OwnedPtr>, - growth_rates: OwnedPtr>, - types: OwnedPtr>, - natures: OwnedPtr>, - abilities: OwnedPtr>, -) -> IdentifiablePointer> { + settings: FFIHandle>, + species: FFIHandle>, + moves: FFIHandle>, + items: FFIHandle>, + growth_rates: FFIHandle>, + types: FFIHandle>, + natures: FFIHandle>, + abilities: FFIHandle>, +) -> FFIHandle> { let b: Arc = Arc::new(StaticDataImpl::new( - settings.read(), - species.read(), - moves.read(), - items.read(), - growth_rates.read(), - types.read(), - natures.read(), - abilities.read(), + settings.from_ffi_handle(), + species.from_ffi_handle(), + moves.from_ffi_handle(), + items.from_ffi_handle(), + growth_rates.from_ffi_handle(), + types.from_ffi_handle(), + natures.from_ffi_handle(), + abilities.from_ffi_handle(), )); - b.into() -} - -/// Drop a static data. -#[no_mangle] -unsafe extern "C" fn static_data_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIHandle::get_handle(b.into()) } /// Several misc settings for the library. #[no_mangle] -unsafe extern "C" fn static_data_settings( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().settings().clone().into() +unsafe extern "C" fn static_data_settings(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(data.from_ffi_handle().settings().clone().into()) } /// All data for Pokemon species. #[no_mangle] -unsafe extern "C" fn static_data_species( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().species().clone().into() +unsafe extern "C" fn static_data_species(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(data.from_ffi_handle().species().clone().into()) } /// All data for the moves. #[no_mangle] -unsafe extern "C" fn static_data_moves( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().moves().clone().into() +unsafe extern "C" fn static_data_moves(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(data.from_ffi_handle().moves().clone().into()) } /// All data for the items. #[no_mangle] -unsafe extern "C" fn static_data_items( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - (data.as_mut().items()).clone().into() +unsafe extern "C" fn static_data_items(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle((data.from_ffi_handle().items()).clone().into()) } /// All data for growth rates. #[no_mangle] unsafe extern "C" fn static_data_growth_rates( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().growth_rates().clone().into() + data: FFIHandle>, +) -> FFIHandle> { + FFIHandle::get_handle(data.from_ffi_handle().growth_rates().clone().into()) } /// All data related to types and type effectiveness. #[no_mangle] -unsafe extern "C" fn static_data_types( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().types().clone().into() +unsafe extern "C" fn static_data_types(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(data.from_ffi_handle().types().clone().into()) } /// All data related to natures. #[no_mangle] -unsafe extern "C" fn static_data_natures( - data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_ref().natures().clone().into() +unsafe extern "C" fn static_data_natures(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle(data.from_ffi_handle().natures().clone().into()) } /// All data related to abilities. #[no_mangle] -unsafe extern "C" fn static_data_abilities( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - (data.as_mut().abilities()).clone().into() +unsafe extern "C" fn static_data_abilities(data: FFIHandle>) -> FFIHandle> { + FFIHandle::get_handle((data.from_ffi_handle().abilities()).clone().into()) } diff --git a/src/ffi/static_data/libraries/type_library.rs b/src/ffi/static_data/libraries/type_library.rs index c023864..a72c70f 100644 --- a/src/ffi/static_data/libraries/type_library.rs +++ b/src/ffi/static_data/libraries/type_library.rs @@ -1,29 +1,24 @@ -use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{FFIResult, NonOwnedPtrString}; use crate::static_data::{TypeIdentifier, TypeLibrary, TypeLibraryImpl}; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; +use std::sync::Arc; /// Instantiates a new type library with a specific capacity. #[no_mangle] -extern "C" fn type_library_new(capacity: usize) -> IdentifiablePointer> { - let b: Box = Box::new(TypeLibraryImpl::new(capacity)); - b.into() -} - -/// Drops a type library. -#[no_mangle] -unsafe extern "C" fn type_library_drop(ptr: OwnedPtr>) { - drop_in_place(ptr); +extern "C" fn type_library_new(capacity: usize) -> FFIHandle> { + let b: Arc = Arc::new(TypeLibraryImpl::new(capacity)); + FFIHandle::get_handle(b.into()) } /// Gets the type identifier for a type with a name. #[no_mangle] unsafe extern "C" fn type_library_get_type_id( - ptr: ExternPointer>, - key: BorrowedPtr, + ptr: FFIHandle>, + key: NonOwnedPtrString, found: *mut bool, ) -> TypeIdentifier { - if let Some(v) = ptr.as_ref().get_type_id(&CStr::from_ptr(key).into()) { + if let Some(v) = ptr.from_ffi_handle().get_type_id(&CStr::from_ptr(key).into()) { *found = true; v } else { @@ -35,31 +30,33 @@ unsafe extern "C" fn type_library_get_type_id( /// Gets the type name from the type identifier. #[no_mangle] unsafe extern "C" fn type_library_get_type_name( - ptr: ExternPointer>, + ptr: FFIHandle>, type_id: TypeIdentifier, found: *mut bool, -) -> NativeResult<*mut c_char> { - if let Some(v) = ptr.as_ref().get_type_name(type_id) { +) -> FFIResult<*mut c_char> { + if let Some(v) = ptr.from_ffi_handle().get_type_name(type_id) { *found = true; match CString::new(v.str()) { - Ok(v) => NativeResult::ok(v.into_raw()), - Err(e) => NativeResult::err(e.into()), + Ok(v) => FFIResult::ok(v.into_raw()), + Err(e) => FFIResult::err(e.into()), } } else { *found = false; - NativeResult::ok(std::ptr::null_mut()) + FFIResult::ok(std::ptr::null_mut()) } } /// Gets the effectiveness for a single attacking type against a single defending type. #[no_mangle] extern "C" fn type_library_get_single_effectiveness( - ptr: ExternPointer>, + ptr: FFIHandle>, attacking: TypeIdentifier, defending: TypeIdentifier, -) -> NativeResult { - ptr.as_ref().get_single_effectiveness(attacking, defending).into() +) -> FFIResult { + ptr.from_ffi_handle() + .get_single_effectiveness(attacking, defending) + .into() } /// Gets the effectiveness for a single attacking type against an amount of defending types. @@ -67,33 +64,33 @@ extern "C" fn type_library_get_single_effectiveness( /// and multiplying the results with each other. #[no_mangle] unsafe extern "C" fn type_library_get_effectiveness( - ptr: ExternPointer>, + ptr: FFIHandle>, attacking: TypeIdentifier, - defending: OwnedPtr, + defending: *const TypeIdentifier, defending_length: usize, -) -> NativeResult { +) -> FFIResult { let v = std::slice::from_raw_parts(defending, defending_length); - ptr.as_ref().get_effectiveness(attacking, v).into() + ptr.from_ffi_handle().get_effectiveness(attacking, v).into() } /// Registers a new type in the library. #[no_mangle] unsafe extern "C" fn type_library_register_type( - mut ptr: ExternPointer>, - name: BorrowedPtr, + ptr: FFIHandle>, + name: NonOwnedPtrString, ) -> TypeIdentifier { - ptr.as_mut().register_type(&CStr::from_ptr(name).into()) + ptr.from_ffi_handle().register_type(&CStr::from_ptr(name).into()) } /// Sets the effectiveness for an attacking type against a defending type. #[no_mangle] unsafe extern "C" fn type_library_set_effectiveness( - mut ptr: ExternPointer>, + ptr: FFIHandle>, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32, -) -> NativeResult<()> { - ptr.as_mut() +) -> FFIResult<()> { + ptr.from_ffi_handle() .set_effectiveness(attacking, defending, effectiveness) .into() } diff --git a/src/ffi/static_data/mod.rs b/src/ffi/static_data/mod.rs index 0ef2c47..5c990db 100644 --- a/src/ffi/static_data/mod.rs +++ b/src/ffi/static_data/mod.rs @@ -1,9 +1,11 @@ -use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FFIObject, FromFFIHandle}; +use crate::ffi::{FFIResult, OwnedPtrString}; use crate::static_data::EffectParameter; use crate::{PkmnError, StringKey}; use anyhow::anyhow; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; +use std::ops::Deref; +use std::sync::Arc; /// The Foreign Function Interface for abilities mod ability; @@ -28,94 +30,88 @@ mod statistic_set; /// Instantiates an effect parameter with a boolean. #[no_mangle] -extern "C" fn effect_parameter_new_bool(value: u8) -> IdentifiablePointer { - Box::::new((value == 1).into()).into() +extern "C" fn effect_parameter_new_bool(value: u8) -> FFIHandle> { + FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value == 1)))) } /// Instantiates an effect parameter with an integer. #[no_mangle] -extern "C" fn effect_parameter_new_int(value: i64) -> IdentifiablePointer { - Box::::new(value.into()).into() +extern "C" fn effect_parameter_new_int(value: i64) -> FFIHandle> { + FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value)))) } /// Instantiates an effect parameter with a float. #[no_mangle] -extern "C" fn effect_parameter_new_float(value: f32) -> IdentifiablePointer { - Box::::new(value.into()).into() +extern "C" fn effect_parameter_new_float(value: f32) -> FFIHandle> { + FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value)))) } /// Instantiates an effect parameter with a string. #[no_mangle] -unsafe extern "C" fn effect_parameter_new_string( - value: *const c_char, -) -> NativeResult> { +unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> FFIResult>> { let sk: StringKey = match CStr::from_ptr(value).to_str() { Ok(sk) => sk.into(), - Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), + Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()), }; - NativeResult::ok(Box::::new(sk.into()).into()) -} - -/// Drop an effect parameter. -#[no_mangle] -unsafe extern "C" fn effect_parameter_drop(ptr: OwnedPtr) { - drop_in_place(ptr) + FFIResult::ok(FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new( + EffectParameter::from(sk), + )))) } /// Get the type of an effect parameter. #[no_mangle] -extern "C" fn effect_parameter_get_type(ptr: ExternPointer) -> u8 { - match ptr.as_ref() { - EffectParameter::Bool(_, _) => 0, - EffectParameter::Int(_, _) => 1, - EffectParameter::Float(_, _) => 2, - EffectParameter::String(_, _) => 3, +extern "C" fn effect_parameter_get_type(ptr: FFIHandle>) -> u8 { + match ptr.from_ffi_handle().deref() { + EffectParameter::Bool(_) => 0, + EffectParameter::Int(_) => 1, + EffectParameter::Float(_) => 2, + EffectParameter::String(_) => 3, } } /// Get the boolean contained in the effect parameter, panics if the effect parameter is not a bool. #[no_mangle] -extern "C" fn effect_parameter_get_as_bool(ptr: ExternPointer) -> NativeResult { - let p = ptr.as_ref(); - if let EffectParameter::Bool(_, b) = p { - NativeResult::ok(u8::from(*b)) +extern "C" fn effect_parameter_get_as_bool(ptr: FFIHandle>) -> FFIResult { + let p = ptr.from_ffi_handle(); + if let EffectParameter::Bool(b) = p.deref() { + FFIResult::ok(u8::from(*b)) } else { - NativeResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p)) + FFIResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p)) } } /// Get the int contained in the effect parameter, panics if the effect parameter is not a int. #[no_mangle] -extern "C" fn effect_parameter_get_as_int(ptr: ExternPointer) -> NativeResult { - let p = ptr.as_ref(); - if let EffectParameter::Int(_, b) = p { - NativeResult::ok(*b) +extern "C" fn effect_parameter_get_as_int(ptr: FFIHandle>) -> FFIResult { + let p = ptr.from_ffi_handle(); + if let EffectParameter::Int(b) = p.deref() { + FFIResult::ok(*b) } else { - NativeResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p)) + FFIResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p)) } } /// Get the float contained in the effect parameter, panics if the effect parameter is not a float. #[no_mangle] -extern "C" fn effect_parameter_get_as_float(ptr: ExternPointer) -> NativeResult { - let p = ptr.as_ref(); - if let EffectParameter::Float(_, b) = p { - NativeResult::ok(*b) +extern "C" fn effect_parameter_get_as_float(ptr: FFIHandle>) -> FFIResult { + let p = ptr.from_ffi_handle(); + if let EffectParameter::Float(b) = p.deref() { + FFIResult::ok(*b) } else { - NativeResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p)) + FFIResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p)) } } /// Get the string contained in the effect parameter, panics if the effect parameter is not a string. #[no_mangle] -extern "C" fn effect_parameter_get_as_string(ptr: ExternPointer) -> NativeResult> { - let p = ptr.as_ref(); - if let EffectParameter::String(_, b) = p { +extern "C" fn effect_parameter_get_as_string(ptr: FFIHandle>) -> FFIResult { + let p = ptr.from_ffi_handle(); + if let EffectParameter::String(b) = p.deref() { match CString::new(b.str().to_string()) { - Ok(cstr) => NativeResult::ok(cstr.into_raw()), - Err(_) => NativeResult::err(PkmnError::InvalidCString.into()), + Ok(cstr) => FFIResult::ok(cstr.into_raw()), + Err(_) => FFIResult::err(PkmnError::InvalidCString.into()), } } else { - NativeResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p)) + FFIResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p)) } } diff --git a/src/ffi/static_data/move_data.rs b/src/ffi/static_data/move_data.rs index 53f8e1e..90b6615 100644 --- a/src/ffi/static_data/move_data.rs +++ b/src/ffi/static_data/move_data.rs @@ -1,4 +1,5 @@ -use crate::ffi::{ffi_arc_dyn_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; +use crate::ffi::{ffi_handle_arc_dyn_getter, ExternPointer, FFIResult, NonOwnedPtrString, OwnedPtrString}; use crate::static_data::{ EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier, @@ -7,7 +8,6 @@ use crate::StringKey; use anyhow::anyhow; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new move. @@ -21,27 +21,27 @@ unsafe extern "C" fn move_data_new( base_usages: u8, target: MoveTarget, priority: i8, - secondary_effect: *mut Box, + secondary_effect: FFIHandle>, flags: *const *const c_char, flags_length: usize, -) -> NativeResult>> { +) -> FFIResult>> { let flags = std::slice::from_raw_parts(flags, flags_length); let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), - Err(_) => return NativeResult::err_from_str("Unable to convert name to string"), + Err(_) => return FFIResult::err_from_str("Unable to convert name to string"), }; let mut flags_set: HashSet = HashSet::with_capacity(flags_length); for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, - Err(_) => return NativeResult::err_from_str("Unable to convert flag to string"), + Err(_) => return FFIResult::err_from_str("Unable to convert flag to string"), }; flags_set.insert(flag.into()); } - let secondary_effect = if secondary_effect.is_null() { + let secondary_effect = if secondary_effect.is_none() { None } else { - Some(*Box::from_raw(secondary_effect)) + Some(secondary_effect.from_ffi_handle()) }; let a: Arc = Arc::new(MoveDataImpl::new( &name, @@ -55,39 +55,37 @@ unsafe extern "C" fn move_data_new( secondary_effect, flags_set, )); - NativeResult::ok(a.into()) -} - -/// Drops a reference counted move. -#[no_mangle] -unsafe extern "C" fn move_data_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIResult::ok(FFIHandle::get_handle(a.into())) } /// The name of the move. #[no_mangle] -unsafe extern "C" fn move_data_name(ptr: ExternPointer>) -> NativeResult> { - let name = ptr.as_ref().name(); +unsafe extern "C" fn move_data_name(ptr: FFIHandle>) -> FFIResult { + let move_data = ptr.from_ffi_handle(); + let name = move_data.name(); match CString::new(name.str()) { - Ok(name) => NativeResult::ok(name.into_raw()), - Err(_) => NativeResult::err_from_str("Unable to convert name to string"), + Ok(name) => FFIResult::ok(name.into_raw()), + Err(_) => FFIResult::err_from_str("Unable to convert name to string"), } } -ffi_arc_dyn_getter!(MoveData, move_type, TypeIdentifier); -ffi_arc_dyn_getter!(MoveData, category, MoveCategory); -ffi_arc_dyn_getter!(MoveData, base_power, u8); -ffi_arc_dyn_getter!(MoveData, accuracy, u8); -ffi_arc_dyn_getter!(MoveData, base_usages, u8); -ffi_arc_dyn_getter!(MoveData, target, MoveTarget); -ffi_arc_dyn_getter!(MoveData, priority, i8); +ffi_handle_arc_dyn_getter!(MoveData, move_type, TypeIdentifier); +ffi_handle_arc_dyn_getter!(MoveData, category, MoveCategory); +ffi_handle_arc_dyn_getter!(MoveData, base_power, u8); +ffi_handle_arc_dyn_getter!(MoveData, accuracy, u8); +ffi_handle_arc_dyn_getter!(MoveData, base_usages, u8); +ffi_handle_arc_dyn_getter!(MoveData, target, MoveTarget); +ffi_handle_arc_dyn_getter!(MoveData, priority, i8); /// The optional secondary effect the move has. #[no_mangle] unsafe extern "C" fn move_data_secondary_effect( - ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().secondary_effect().into() + ptr: FFIHandle>, +) -> FFIHandle> { + match ptr.from_ffi_handle().secondary_effect() { + Some(secondary_effect) => FFIHandle::get_handle(secondary_effect.clone().into()), + None => FFIHandle::none(), + } } /// Arbitrary flags that can be applied to the move. @@ -101,28 +99,22 @@ unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer>, f #[no_mangle] unsafe extern "C" fn secondary_effect_new( chance: f32, - effect_name: BorrowedPtr, - parameters: *mut OwnedPtr>, + effect_name: NonOwnedPtrString, + parameters: *mut FFIHandle>, parameters_length: usize, -) -> IdentifiablePointer> { +) -> FFIHandle> { let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length); let mut parameters = Vec::with_capacity(parameters_length); for parameter in parameter_slice { - parameters.push(*Box::from_raw(*parameter)) + parameters.push(parameter.from_ffi_handle()) } - let b: Box = Box::new(SecondaryEffectImpl::new( + let b: Arc = Arc::new(SecondaryEffectImpl::new( chance, CStr::from_ptr(effect_name).into(), parameters, )); - b.into() -} - -/// Drop a secondary effect. -#[no_mangle] -unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIHandle::get_handle(b.into()) } /// The chance the effect triggers. @@ -135,10 +127,10 @@ unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer>, -) -> NativeResult> { +) -> FFIResult { match CString::new(ptr.as_ref().effect_name().str()) { - Ok(name) => NativeResult::ok(name.into_raw()), - Err(_) => NativeResult::err(anyhow!( + Ok(name) => FFIResult::ok(name.into_raw()), + Err(_) => FFIResult::err(anyhow!( "Unable to convert effect name '{}' to CString", ptr.as_ref().effect_name() )), @@ -156,10 +148,10 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer>, index: usize, -) -> IdentifiablePointer> { +) -> FFIHandle> { if let Some(v) = ptr.as_ref().parameters().get(index) { - v.clone().into() + FFIHandle::get_handle(v.clone().into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } diff --git a/src/ffi/static_data/nature.rs b/src/ffi/static_data/nature.rs index e11532d..1668835 100644 --- a/src/ffi/static_data/nature.rs +++ b/src/ffi/static_data/nature.rs @@ -1,6 +1,5 @@ -use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; +use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::static_data::{Nature, NatureImpl, Statistic}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates a new statistic. @@ -10,32 +9,26 @@ extern "C" fn nature_new( decrease_stat: Statistic, increase_modifier: f32, decrease_modifier: f32, -) -> IdentifiablePointer> { +) -> FFIHandle> { let arc: Arc = NatureImpl::new(increase_stat, decrease_stat, increase_modifier, decrease_modifier); - arc.into() -} - -/// Reduce the reference count for a nature. -#[no_mangle] -unsafe extern "C" fn nature_drop(ptr: OwnedPtr>) { - drop_in_place(ptr) + FFIHandle::get_handle(arc.into()) } /// The stat that should receive the increased modifier. #[no_mangle] -extern "C" fn nature_increased_stat(ptr: ExternPointer>) -> Statistic { - ptr.as_ref().increased_stat() +extern "C" fn nature_increased_stat(ptr: FFIHandle>) -> Statistic { + ptr.from_ffi_handle().increased_stat() } /// The stat that should receive the decreased modifier. #[no_mangle] -extern "C" fn nature_decreased_stat(ptr: ExternPointer>) -> Statistic { - ptr.as_ref().decreased_stat() +extern "C" fn nature_decreased_stat(ptr: FFIHandle>) -> Statistic { + ptr.from_ffi_handle().decreased_stat() } /// Calculates the modifier for a given stat. If it's the increased stat, returns the increased /// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0 #[no_mangle] -extern "C" fn nature_get_stat_modifier(ptr: ExternPointer>, stat: Statistic) -> f32 { - ptr.as_ref().get_stat_modifier(stat) +extern "C" fn nature_get_stat_modifier(ptr: FFIHandle>, stat: Statistic) -> f32 { + ptr.from_ffi_handle().get_stat_modifier(stat) } diff --git a/src/ffi/static_data/species.rs b/src/ffi/static_data/species.rs index ffc10b0..b210317 100644 --- a/src/ffi/static_data/species.rs +++ b/src/ffi/static_data/species.rs @@ -1,33 +1,32 @@ +use crate::ffi::ffi_handle::FFIHandle; use crate::ffi::{ - ffi_arc_dyn_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, - OwnedPtr, + ffi_handle_arc_dyn_getter, ffi_handle_arc_stringkey_getter, FFIResult, FromFFIHandle, NonOwnedPtrString, }; use crate::static_data::{Form, Gender, Species, SpeciesImpl}; use crate::{PkmnError, Random, StringKey}; use hashbrown::HashSet; use std::ffi::{c_char, CStr}; -use std::ptr::drop_in_place; use std::sync::Arc; /// Creates a new species. #[no_mangle] unsafe extern "C" fn species_new( id: u16, - name: BorrowedPtr, + name: NonOwnedPtrString, gender_rate: f32, - growth_rate: BorrowedPtr, + growth_rate: NonOwnedPtrString, capture_rate: u8, - default_form: OwnedPtr>, + default_form: FFIHandle>, flags: *const *const c_char, flags_length: usize, -) -> NativeResult>> { +) -> FFIResult>> { let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), - Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), + Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()), }; let growth_rate: StringKey = match CStr::from_ptr(growth_rate).to_str() { Ok(growth_rate) => growth_rate.into(), - Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), + Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()), }; let flags = std::slice::from_raw_parts(flags, flags_length); @@ -35,13 +34,14 @@ unsafe extern "C" fn species_new( for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, - Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), + Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()), }; flags_set.insert(flag.into()); } - let default_form = match default_form.as_ref() { - Some(default_form) => default_form, - None => return NativeResult::err(PkmnError::NullReference.into()), + let default_form = if default_form.is_none() { + return FFIResult::err(PkmnError::NullReference.into()); + } else { + default_form.from_ffi_handle() }; let a: Arc = Arc::new(SpeciesImpl::new( @@ -53,53 +53,48 @@ unsafe extern "C" fn species_new( default_form.clone(), flags_set, )); - NativeResult::ok(a.into()) + FFIResult::ok(FFIHandle::get_handle(a.into())) } -/// Drop a reference to the species. -#[no_mangle] -unsafe extern "C" fn species_drop(ptr: OwnedPtr>) { - drop_in_place(ptr); -} - -ffi_arc_dyn_getter!(Species, id, u16); -ffi_arc_stringkey_getter!(Species, name); -ffi_arc_dyn_getter!(Species, gender_rate, f32); -ffi_arc_stringkey_getter!(Species, growth_rate); -ffi_arc_dyn_getter!(Species, capture_rate, u8); +ffi_handle_arc_dyn_getter!(Species, id, u16); +ffi_handle_arc_stringkey_getter!(Species, name); +ffi_handle_arc_dyn_getter!(Species, gender_rate, f32); +ffi_handle_arc_stringkey_getter!(Species, growth_rate); +ffi_handle_arc_dyn_getter!(Species, capture_rate, u8); /// Adds a new form to the species. #[no_mangle] unsafe extern "C" fn species_add_form( - mut species: ExternPointer>, - name: BorrowedPtr, - form: OwnedPtr>, -) -> NativeResult<()> { - let form = match form.as_ref() { - Some(form) => form.clone(), - None => return NativeResult::err(PkmnError::NullReference.into()), + species: FFIHandle>, + name: NonOwnedPtrString, + form: FFIHandle>, +) -> FFIResult<()> { + let form = if form.is_none() { + return FFIResult::err(PkmnError::NullReference.into()); + } else { + form.from_ffi_handle() }; - species.as_mut().add_form(CStr::from_ptr(name).into(), form); - NativeResult::ok(()) + species.from_ffi_handle().add_form(CStr::from_ptr(name).into(), form); + FFIResult::ok(()) } /// Gets a form by name. #[no_mangle] unsafe extern "C" fn species_get_form( - species: ExternPointer>, - name: BorrowedPtr, -) -> IdentifiablePointer> { - let form = species.as_ref().get_form(&CStr::from_ptr(name).into()); + species: FFIHandle>, + name: NonOwnedPtrString, +) -> FFIHandle> { + let form = species.from_ffi_handle().get_form(&CStr::from_ptr(name).into()); if let Some(form) = form { - form.into() + FFIHandle::get_handle(form.into()) } else { - IdentifiablePointer::none() + FFIHandle::none() } } /// Gets a form by name. #[no_mangle] -unsafe extern "C" fn species_get_random_gender(species: ExternPointer>, seed: u64) -> Gender { +unsafe extern "C" fn species_get_random_gender(species: FFIHandle>, seed: u64) -> Gender { let mut rand = Random::new(seed as u128); - species.as_ref().get_random_gender(&mut rand) + species.from_ffi_handle().get_random_gender(&mut rand) } diff --git a/src/ffi/static_data/statistic_set.rs b/src/ffi/static_data/statistic_set.rs index 7b36e2f..95aecf6 100644 --- a/src/ffi/static_data/statistic_set.rs +++ b/src/ffi/static_data/statistic_set.rs @@ -1,6 +1,7 @@ -use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; +use crate::ffi::FFIHandle; +use crate::ffi::FromFFIHandle; use crate::static_data::{StaticStatisticSet, Statistic, StatisticSet}; -use std::ptr::drop_in_place; +use std::sync::Arc; /// Basic foreign function interface for a statistic set. macro_rules! statistic_set { @@ -15,40 +16,35 @@ extern "C" fn []( special_attack: $num_type, special_defense: $num_type, speed: $num_type, -) -> IdentifiablePointer> { - Box::new(StatisticSet::new( +) -> FFIHandle>> { + FFIHandle::get_handle(Arc::new(StatisticSet::new( hp, attack, defense, special_attack, special_defense, speed, - )).into() + )).into()) } #[no_mangle] -unsafe extern "C" fn [](ptr: OwnedPtr>) { - drop_in_place(ptr) +extern "C" fn [](ptr: FFIHandle>>, stat: Statistic) -> $num_type { + ptr.from_ffi_handle().get_stat(stat) } #[no_mangle] -extern "C" fn [](ptr: ExternPointer>, stat: Statistic) -> $num_type { - ptr.as_ref().get_stat(stat) +extern "C" fn [](ptr: FFIHandle>>, stat: Statistic, value: $num_type) { + ptr.from_ffi_handle().set_stat(stat, value) } #[no_mangle] -extern "C" fn [](ptr: ExternPointer>, stat: Statistic, value: $num_type) { - ptr.as_ref().set_stat(stat, value) +extern "C" fn [](ptr: FFIHandle>>, stat: Statistic, value: $num_type) { + ptr.from_ffi_handle().increase_stat(stat, value) } #[no_mangle] -extern "C" fn [](ptr: ExternPointer>, stat: Statistic, value: $num_type) { - ptr.as_ref().increase_stat(stat, value) -} - -#[no_mangle] -extern "C" fn [](ptr: ExternPointer>, stat: Statistic, value: $num_type) { - ptr.as_ref().decrease_stat(stat, value) +extern "C" fn [](ptr: FFIHandle>>, stat: Statistic, value: $num_type) { + ptr.from_ffi_handle().decrease_stat(stat, value) } } @@ -56,11 +52,11 @@ extern "C" fn [](ptr: ExternPointer]( special_attack: $num_type, special_defense: $num_type, speed: $num_type, -) -> IdentifiablePointer> { - Box::new(StaticStatisticSet::new( +) -> FFIHandle>> { + FFIHandle::get_handle(Arc::new(StaticStatisticSet::new( hp, attack, defense, special_attack, special_defense, speed, - )).into() + )).into()) } #[no_mangle] -unsafe extern "C" fn [](ptr: OwnedPtr>) { - drop_in_place(ptr) -} - -#[no_mangle] -extern "C" fn [](ptr: ExternPointer>, stat: Statistic) -> $num_type { - ptr.as_ref().get_stat(stat) +extern "C" fn [](ptr: FFIHandle>>, stat: Statistic) -> $num_type { + ptr.from_ffi_handle().get_stat(stat) } } }; } -static_statistic_set!(u8); +// static_statistic_set!(u8); static_statistic_set!(u16); -static_statistic_set!(u32); -static_statistic_set!(i8); -static_statistic_set!(i16); -static_statistic_set!(i32); +// static_statistic_set!(u32); +// static_statistic_set!(i8); +// static_statistic_set!(i16); +// static_statistic_set!(i32); diff --git a/src/lib.rs b/src/lib.rs index 31c5d6c..f1f4f29 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,9 @@ #![allow(incomplete_features)] #![allow(ambiguous_glob_reexports)] #![allow(hidden_glob_reexports)] -#![deny(missing_docs)] -#![deny(clippy::missing_docs_in_private_items)] +// Documentation linters +// #![deny(missing_docs)] +// #![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)] diff --git a/src/script_implementations/wasm/export_registry/mod.rs b/src/script_implementations/wasm/export_registry/mod.rs index b611054..116f219 100755 --- a/src/script_implementations/wasm/export_registry/mod.rs +++ b/src/script_implementations/wasm/export_registry/mod.rs @@ -146,10 +146,10 @@ fn effect_parameter_get_type( ) -> WasmResult { let value = get_value_arc!(parameter, env); wasm_ok(match value.deref() { - EffectParameter::Bool(_, _) => 1, - EffectParameter::Int(_, _) => 2, - EffectParameter::Float(_, _) => 3, - EffectParameter::String(_, _) => 4, + EffectParameter::Bool(_) => 1, + EffectParameter::Int(_) => 2, + EffectParameter::Float(_) => 3, + EffectParameter::String(_) => 4, }) } @@ -160,7 +160,7 @@ fn effect_parameter_as_bool( ) -> WasmResult { let value = get_value_arc!(parameter, env); match value.deref() { - EffectParameter::Bool(_, b) => wasm_ok(>::from(*b)), + EffectParameter::Bool(b) => wasm_ok(>::from(*b)), _ => wasm_err::(anyhow!("Unexpected parameter type. Expected bool, got {}", value), &env), } } @@ -172,7 +172,7 @@ fn effect_parameter_as_int( ) -> WasmResult { let value = get_value_arc!(parameter, env); match value.deref() { - EffectParameter::Int(_, i) => wasm_ok(*i), + EffectParameter::Int(i) => wasm_ok(*i), _ => wasm_err::(anyhow!("Unexpected parameter type. Expected int, got {}", value), &env), } } @@ -184,7 +184,7 @@ fn effect_parameter_as_float( ) -> WasmResult { let value = get_value_arc!(parameter, env); match value.deref() { - EffectParameter::Float(_, f) => wasm_ok(*f), + EffectParameter::Float(f) => wasm_ok(*f), _ => wasm_err::( anyhow!("Unexpected parameter type. Expected float, got {}", value), &env, @@ -199,7 +199,7 @@ fn effect_parameter_as_string( ) -> WasmResult> { let value = get_value_arc!(parameter, env); match value.deref() { - EffectParameter::String(_, s) => wasm_ok(ExternRef::::func_new(&env, s.clone().into())), + EffectParameter::String(s) => wasm_ok(ExternRef::::func_new(&env, s.clone().into())), _ => wasm_err::>( anyhow!("Unexpected parameter type. Expected string, got {}", value), &env, diff --git a/src/script_implementations/wasm/extern_ref.rs b/src/script_implementations/wasm/extern_ref.rs index 503b7fe..8b56ce4 100755 --- a/src/script_implementations/wasm/extern_ref.rs +++ b/src/script_implementations/wasm/extern_ref.rs @@ -1,4 +1,3 @@ -use crate::ValueIdentifiable; use anyhow_ext::Result; use std::marker::PhantomData; use std::mem::transmute; @@ -41,7 +40,7 @@ impl Default for ExternRef { } } -impl ExternRef { +impl ExternRef { /// Instantiates a new ExternRef for a bit of data. If we already have made an Extern Ref for /// this data and type, we use that instead. pub fn new(env: &WebAssemblyEnvironmentData, value: WasmObject) -> Self { diff --git a/src/script_implementations/wasm/script_resolver.rs b/src/script_implementations/wasm/script_resolver.rs index 92f21a4..4756553 100755 --- a/src/script_implementations/wasm/script_resolver.rs +++ b/src/script_implementations/wasm/script_resolver.rs @@ -1,3 +1,4 @@ +use std::any::Any; use std::fmt::{Debug, Formatter}; use std::mem::{align_of, forget, size_of}; use std::sync::{Arc, Weak}; @@ -19,19 +20,17 @@ 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, VecExt}; +use crate::{ScriptCategory, StringKey, VecExt}; /// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly. pub struct WebAssemblyScriptResolver { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The global state storage of WASM. _store: *mut Store, /// The WASM modules we have loaded. - modules: Vec, + modules: RwLock>, /// Our currently loaded WASM instances. Empty until finalize() is called, after which the loaded modules get turned /// into actual instances. - instances: Vec, + instances: RwLock>, /// This is the WASM function to load a script. load_script_fn: Option), u32>>, @@ -51,7 +50,7 @@ struct ScriptCapabilitiesKey { impl WebAssemblyScriptResolver { /// Instantiates a new WebAssemblyScriptResolver. - pub fn new() -> Box { + pub fn new() -> Arc { let compiler = wasmer::LLVM::default(); let mut features = Features::new(); features.multi_value = true; @@ -65,7 +64,6 @@ impl WebAssemblyScriptResolver { environment.self_arc.write().replace(Arc::downgrade(&environment)); let s = Self { - identifier: Default::default(), _store: store_ptr, modules: Default::default(), instances: Default::default(), @@ -73,7 +71,7 @@ impl WebAssemblyScriptResolver { environment_data: environment, }; - Box::new(s) + Arc::new(s) } /// Get an immutable reference to the current WASM Store. @@ -93,15 +91,15 @@ impl WebAssemblyScriptResolver { } /// Load a compiled WASM module. - pub fn load_wasm_from_bytes(&mut self, bytes: &[u8]) -> Result<()> { + pub fn load_wasm_from_bytes(&self, bytes: &[u8]) -> Result<()> { // FIXME: Error handling let module = Module::new(&self.store_ref(), bytes)?; - self.modules.push(module); + self.modules.write().push(module); Ok(()) } /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. - pub fn finalize(&mut self) -> Result<()> { + pub fn finalize(&self) -> Result<()> { let mut imports = Imports::new(); let env = FunctionEnv::new( @@ -109,7 +107,8 @@ impl WebAssemblyScriptResolver { WebAssemblyEnv::new(Arc::downgrade(&self.environment_data)), ); register_webassembly_funcs(&mut imports, &mut self.store_mut(), &env); - for module in &self.modules { + let modules = self.modules.read(); + for module in modules.iter() { for import in module.imports() { if imports.get_export("env", import.name()).is_none() { println!( @@ -143,8 +142,12 @@ impl WebAssemblyScriptResolver { if let Some(m) = &self.environment_data.memory.read().as_ref() { 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())?) + unsafe { + #[allow(clippy::unwrap_used)] // We know this is valid. + if let Some(f) = exported_functions.get::(&"load_script".into()) { + let self_mut = (self as *const Self as *mut Self).as_mut().unwrap(); + self_mut.load_script_fn = Some(f.typed(&self.store_ref())?) + } } if let Some(f) = exported_functions.get::(&"allocate_mem".into()) { let _ = self @@ -160,7 +163,7 @@ impl WebAssemblyScriptResolver { .write() .insert(TempWasmAllocator::new(temp_memory_slab.0, temp_memory_slab.1)); } - self.instances.push(instance); + self.instances.write().push(instance); } Ok(()) } @@ -171,12 +174,6 @@ impl WebAssemblyScriptResolver { } } -impl ValueIdentifiable for WebAssemblyScriptResolver { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - impl ScriptResolver for WebAssemblyScriptResolver { fn load_script( &self, @@ -199,6 +196,10 @@ impl ScriptResolver for WebAssemblyScriptResolver { fn load_item_script(&self, _key: &dyn Item) -> Result>> { todo!() } + + fn as_any(&self) -> &dyn Any { + self + } } impl Debug for WebAssemblyScriptResolver { diff --git a/src/static_data/items.rs b/src/static_data/items.rs index b7698ba..acaf440 100755 --- a/src/static_data/items.rs +++ b/src/static_data/items.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use std::any::Any; use std::fmt::Debug; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// An item category defines which bag slot items are stored in. #[derive(Debug, Copy, Clone)] @@ -47,7 +47,7 @@ pub enum BattleItemCategory { } /// An item is an object which the player can pick up, keep in their Bag, and use in some manner -pub trait Item: ValueIdentifiable + Debug + Any { +pub trait Item: Debug + Any { /// The name of the item. fn name(&self) -> &StringKey; /// Which bag slot items are stored in. @@ -66,8 +66,6 @@ pub trait Item: ValueIdentifiable + Debug + Any { /// An item is an object which the player can pick up, keep in their Bag, and use in some manner #[derive(Debug)] pub struct ItemImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The name of the item. name: StringKey, /// Which bag slot items are stored in. @@ -90,7 +88,6 @@ impl ItemImpl { flags: HashSet, ) -> ItemImpl { ItemImpl { - identifier: Default::default(), name: name.clone(), category, battle_category, @@ -128,12 +125,6 @@ impl Item for ItemImpl { } } -impl ValueIdentifiable for ItemImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] pub(crate) mod tests { @@ -150,10 +141,5 @@ pub(crate) mod tests { fn flags(&self) -> &HashSet; fn has_flag(&self, key: &StringKey) -> bool; } - impl ValueIdentifiable for Item { - fn value_identifier(&self) -> ValueIdentifier { - ValueIdentifier::new(0) - } - } } } diff --git a/src/static_data/libraries/ability_library.rs b/src/static_data/libraries/ability_library.rs index 3f5a01f..a490fbe 100755 --- a/src/static_data/libraries/ability_library.rs +++ b/src/static_data/libraries/ability_library.rs @@ -5,16 +5,14 @@ use indexmap::IndexMap; use crate::static_data::Ability; use crate::static_data::DataLibrary; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// A storage for all abilities that can be used in this data library. -pub trait AbilityLibrary: DataLibrary + ValueIdentifiable + Debug {} +pub trait AbilityLibrary: DataLibrary + Debug {} /// A storage for all abilities that can be used in this data library. #[derive(Debug)] pub struct AbilityLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying map for the library. map: IndexMap>, } @@ -23,7 +21,6 @@ impl AbilityLibraryImpl { /// Instantiates a new ability library. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -40,12 +37,6 @@ impl DataLibrary for AbilityLibraryImpl { } } -impl ValueIdentifiable for AbilityLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -57,7 +48,7 @@ pub mod tests { use std::sync::Arc; pub fn build() -> AbilityLibraryImpl { - let mut lib = AbilityLibraryImpl::new(1); + let lib = AbilityLibraryImpl::new(1); lib.add( &StringKey::new("test_ability"), Arc::new(AbilityImpl::new( diff --git a/src/static_data/libraries/data_library.rs b/src/static_data/libraries/data_library.rs index 80ed996..d42f404 100755 --- a/src/static_data/libraries/data_library.rs +++ b/src/static_data/libraries/data_library.rs @@ -15,13 +15,17 @@ pub trait DataLibrary { fn get_modify(&mut self) -> &mut IndexMap>; /// Adds a new value to the library. - fn add(&mut self, key: &StringKey, value: Arc) { - self.get_modify().insert(key.clone(), value); + fn add(&self, key: &StringKey, value: Arc) { + #[allow(clippy::unwrap_used)] // We know this cant fail. + let self_mut = unsafe { (self as *const Self as *mut Self).as_mut() }.unwrap(); + self_mut.get_modify().insert(key.clone(), value); } /// Removes a value from the library. - fn remove(&mut self, key: &StringKey) { - self.get_modify().remove(key); + fn remove(&self, key: &StringKey) { + #[allow(clippy::unwrap_used)] // We know this cant fail. + let self_mut = unsafe { (self as *const Self as *mut Self).as_mut() }.unwrap(); + self_mut.get_modify().remove(key); } /// Gets a value from the library. diff --git a/src/static_data/libraries/growth_rate_library.rs b/src/static_data/libraries/growth_rate_library.rs index e002911..a52163f 100755 --- a/src/static_data/libraries/growth_rate_library.rs +++ b/src/static_data/libraries/growth_rate_library.rs @@ -1,37 +1,36 @@ use anyhow::Result; use std::fmt; use std::fmt::{Debug, Formatter}; +use std::sync::Arc; use hashbrown::HashMap; +use parking_lot::RwLock; use crate::defines::LevelInt; use crate::static_data::GrowthRate; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// A library to store all growth rates. -pub trait GrowthRateLibrary: Debug + ValueIdentifiable { +pub trait GrowthRateLibrary: Debug { /// Calculates the level for a given growth key name and a certain experience. 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. - fn add_growth_rate(&mut self, key: &StringKey, value: Box); + fn add_growth_rate(&self, key: &StringKey, value: Arc); } /// A library to store all growth rates. pub struct GrowthRateLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying data structure. - growth_rates: HashMap>, + growth_rates: RwLock>>, } impl GrowthRateLibraryImpl { /// Instantiates a new growth rate library with a capacity. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), - growth_rates: HashMap::with_capacity(capacity), + growth_rates: RwLock::new(HashMap::with_capacity(capacity)), } } } @@ -41,6 +40,7 @@ impl GrowthRateLibrary for GrowthRateLibraryImpl { fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result { Ok(self .growth_rates + .read() .get(growth_rate) .ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))? .calculate_level(experience)) @@ -48,20 +48,15 @@ impl GrowthRateLibrary for GrowthRateLibraryImpl { /// 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 + .read() .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. - fn add_growth_rate(&mut self, key: &StringKey, value: Box) { - self.growth_rates.insert(key.clone(), value); - } -} - -impl ValueIdentifiable for GrowthRateLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier + fn add_growth_rate(&self, key: &StringKey, value: Arc) { + self.growth_rates.write().insert(key.clone(), value); } } @@ -87,7 +82,7 @@ pub mod tests { let w = &mut lib; w.add_growth_rate( &"test_growthrate".into(), - Box::new(LookupGrowthRate::new(vec![0, 5, 10, 100])), + Arc::new(LookupGrowthRate::new(vec![0, 5, 10, 100])), ); // Drops borrow as mut @@ -100,12 +95,7 @@ pub mod tests { impl GrowthRateLibrary for GrowthRateLibrary { 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); - } - impl ValueIdentifiable for GrowthRateLibrary { - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } + fn add_growth_rate(&self, key: &StringKey, value: Arc); } } diff --git a/src/static_data/libraries/item_library.rs b/src/static_data/libraries/item_library.rs index 0b2d59d..e61614c 100755 --- a/src/static_data/libraries/item_library.rs +++ b/src/static_data/libraries/item_library.rs @@ -5,16 +5,14 @@ use indexmap::IndexMap; use crate::static_data::DataLibrary; use crate::static_data::Item; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// A library to store all items. -pub trait ItemLibrary: DataLibrary + ValueIdentifiable + Debug {} +pub trait ItemLibrary: DataLibrary + Debug {} /// A library to store all items. #[derive(Debug)] pub struct ItemLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying data structure. map: IndexMap>, } @@ -23,7 +21,6 @@ impl ItemLibraryImpl { /// Instantiates a new Item Library. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -41,12 +38,6 @@ impl DataLibrary for ItemLibraryImpl { } } -impl ValueIdentifiable for ItemLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] pub mod tests { use hashbrown::HashSet; diff --git a/src/static_data/libraries/library_settings.rs b/src/static_data/libraries/library_settings.rs index e0752bc..86a7926 100755 --- a/src/static_data/libraries/library_settings.rs +++ b/src/static_data/libraries/library_settings.rs @@ -1,11 +1,10 @@ use crate::defines::LevelInt; -use crate::{ValueIdentifiable, ValueIdentifier}; use anyhow::Result; use anyhow_ext::ensure; use std::fmt::Debug; /// This library holds several misc settings for the library. -pub trait LibrarySettings: Debug + ValueIdentifiable { +pub trait LibrarySettings: Debug { /// The highest level a Pokemon can be. fn maximum_level(&self) -> LevelInt; @@ -17,8 +16,6 @@ pub trait LibrarySettings: Debug + ValueIdentifiable { /// This library holds several misc settings for the library. #[derive(Debug)] pub struct LibrarySettingsImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The highest level a Pokemon can be. maximum_level: LevelInt, /// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator @@ -36,7 +33,6 @@ impl LibrarySettingsImpl { ensure!(shiny_rate >= 1); ensure!(maximum_level >= 1); Ok(Self { - identifier: Default::default(), maximum_level, shiny_rate, }) @@ -51,9 +47,3 @@ impl LibrarySettings for LibrarySettingsImpl { self.shiny_rate } } - -impl ValueIdentifiable for LibrarySettingsImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} diff --git a/src/static_data/libraries/move_library.rs b/src/static_data/libraries/move_library.rs index 5361bc6..25f8cf6 100755 --- a/src/static_data/libraries/move_library.rs +++ b/src/static_data/libraries/move_library.rs @@ -5,16 +5,14 @@ use indexmap::IndexMap; use crate::static_data::DataLibrary; use crate::static_data::MoveData; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// A library to store all data for moves. -pub trait MoveLibrary: DataLibrary + ValueIdentifiable + Debug {} +pub trait MoveLibrary: DataLibrary + Debug {} /// A library to store all data for moves. #[derive(Debug)] pub struct MoveLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying map. map: IndexMap>, } @@ -23,7 +21,6 @@ impl MoveLibraryImpl { /// Instantiates a new Move Library. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -40,12 +37,6 @@ impl DataLibrary for MoveLibraryImpl { } } -impl ValueIdentifiable for MoveLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] pub mod tests { use hashbrown::HashSet; diff --git a/src/static_data/libraries/nature_library.rs b/src/static_data/libraries/nature_library.rs index 8268b63..75f6002 100644 --- a/src/static_data/libraries/nature_library.rs +++ b/src/static_data/libraries/nature_library.rs @@ -1,15 +1,16 @@ use crate::static_data::Nature; -use crate::{Random, StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::{Random, StringKey}; use anyhow::bail; use anyhow_ext::{ensure, Result}; use indexmap::IndexMap; +use parking_lot::RwLock; use std::fmt::Debug; use std::sync::Arc; /// A library of all natures that can be used, stored by their names. -pub trait NatureLibrary: Debug + ValueIdentifiable { +pub trait NatureLibrary: Debug { /// Adds a new nature with name to the library. - fn load_nature(&mut self, name: StringKey, nature: Arc); + fn load_nature(&self, name: StringKey, nature: Arc); /// Gets a nature by name. fn get_nature(&self, key: &StringKey) -> Option>; /// Gets a random nature. @@ -21,38 +22,35 @@ pub trait NatureLibrary: Debug + ValueIdentifiable { /// A library of all natures that can be used, stored by their names. #[derive(Debug)] pub struct NatureLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying data structure. - map: IndexMap>, + map: RwLock>>, } impl NatureLibraryImpl { /// Creates a new nature library with a given capacity. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), - map: IndexMap::with_capacity(capacity), + map: RwLock::new(IndexMap::with_capacity(capacity)), } } } impl NatureLibrary for NatureLibraryImpl { /// Adds a new nature with name to the library. - fn load_nature(&mut self, name: StringKey, nature: Arc) { - self.map.insert(name, nature); + fn load_nature(&self, name: StringKey, nature: Arc) { + self.map.write().insert(name, nature); } /// Gets a nature by name. fn get_nature(&self, key: &StringKey) -> Option> { - self.map.get(key).cloned() + self.map.read().get(key).cloned() } 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); - Ok(self - .map + let map = self.map.read(); + ensure!(!map.is_empty(), "No natures were loaded into the library."); + let i = rand.get_between(0, map.len() as i32); + Ok(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."))? @@ -62,10 +60,11 @@ impl NatureLibrary for NatureLibraryImpl { /// Finds a nature name by nature. fn get_nature_name(&self, nature: &Arc) -> Result { - for kv in &self.map { + let read_lock = self.map.read(); + for kv in read_lock.iter() { // 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() { + if Arc::ptr_eq(&kv.1, nature) { return Ok(kv.0.clone()); } } @@ -73,12 +72,6 @@ impl NatureLibrary for NatureLibraryImpl { } } -impl ValueIdentifiable for NatureLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -89,7 +82,7 @@ pub mod tests { use crate::static_data::{NatureImpl, NatureLibrary, NatureLibraryImpl}; pub fn build() -> NatureLibraryImpl { - let mut lib = NatureLibraryImpl::new(2); + let lib = NatureLibraryImpl::new(2); lib.load_nature( "test_nature".into(), @@ -103,21 +96,16 @@ pub mod tests { #[derive(Debug)] pub NatureLibrary{} impl NatureLibrary for NatureLibrary { - fn load_nature(&mut self, name: StringKey, nature: Arc); + fn load_nature(&self, name: StringKey, nature: Arc); fn get_nature(&self, key: &StringKey) -> Option>; 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{ - ValueIdentifier::new(0) - } - } } #[test] fn create_nature_library_insert_and_retrieve() { - let mut lib = NatureLibraryImpl::new(2); + let lib = NatureLibraryImpl::new(2); lib.load_nature( "foo".into(), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), @@ -135,7 +123,7 @@ pub mod tests { #[test] fn create_nature_library_insert_and_get_name() { - let mut lib = NatureLibraryImpl::new(2); + let lib = NatureLibraryImpl::new(2); lib.load_nature( "foo".into(), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), @@ -155,7 +143,7 @@ pub mod tests { #[test] fn create_nature_library_insert_single_and_retrieve_random() { - let mut lib = NatureLibraryImpl::new(2); + let lib = NatureLibraryImpl::new(2); lib.load_nature( "foo".into(), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), diff --git a/src/static_data/libraries/species_library.rs b/src/static_data/libraries/species_library.rs index 2b9c6cd..d03bbe1 100755 --- a/src/static_data/libraries/species_library.rs +++ b/src/static_data/libraries/species_library.rs @@ -5,16 +5,14 @@ use indexmap::IndexMap; use crate::static_data::DataLibrary; use crate::static_data::Species; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// A library to store all data for Pokemon species. -pub trait SpeciesLibrary: DataLibrary + ValueIdentifiable + Debug {} +pub trait SpeciesLibrary: DataLibrary + Debug {} /// A library to store all data for Pokemon species. #[derive(Debug)] pub struct SpeciesLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The underlying map. map: IndexMap>, } @@ -23,7 +21,6 @@ impl SpeciesLibraryImpl { /// Instantiates a new Species Library. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -40,12 +37,6 @@ impl DataLibrary for SpeciesLibraryImpl { } } -impl ValueIdentifiable for SpeciesLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -65,11 +56,6 @@ pub mod tests { fn map(&self) -> &IndexMap>; fn get_modify(&mut self) -> &mut IndexMap>; } - impl ValueIdentifiable for SpeciesLibrary { - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } - } } fn build_species() -> Arc { @@ -85,10 +71,10 @@ pub mod tests { 0.0, 0, Vec::new(), - StaticStatisticSet::new(10, 10, 10, 10, 10, 10), + Arc::new(StaticStatisticSet::new(10, 10, 10, 10, 10, 10)), Vec::new(), Vec::new(), - Box::new(LearnableMovesImpl::new(100)), + Arc::new(LearnableMovesImpl::new(100)), HashSet::new(), )), HashSet::new(), diff --git a/src/static_data/libraries/static_data.rs b/src/static_data/libraries/static_data.rs index 2d3d6dc..322e2fb 100755 --- a/src/static_data/libraries/static_data.rs +++ b/src/static_data/libraries/static_data.rs @@ -6,12 +6,11 @@ use crate::static_data::MoveLibrary; use crate::static_data::NatureLibrary; use crate::static_data::SpeciesLibrary; use crate::static_data::TypeLibrary; -use crate::{ValueIdentifiable, ValueIdentifier}; use std::fmt::Debug; use std::sync::Arc; /// The storage for all different libraries. -pub trait StaticData: Debug + ValueIdentifiable { +pub trait StaticData: Debug { /// Several misc settings for the library. fn settings(&self) -> &Arc; /// All data for Pokemon species. @@ -34,8 +33,6 @@ pub trait StaticData: Debug + ValueIdentifiable { /// The storage for all different libraries. #[derive(Debug)] pub struct StaticDataImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// Several misc settings for the library. settings: Arc, /// All data for Pokemon species. @@ -67,7 +64,6 @@ impl StaticDataImpl { abilities: Arc, ) -> Self { Self { - identifier: Default::default(), settings, species, moves, @@ -116,12 +112,6 @@ impl StaticData for StaticDataImpl { } } -impl ValueIdentifiable for StaticDataImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -143,16 +133,10 @@ pub mod test { fn natures(&self) -> &Arc; fn abilities(&self) -> &Arc; } - impl ValueIdentifiable for StaticData { - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } - } } pub fn build() -> StaticDataImpl { StaticDataImpl { - identifier: Default::default(), settings: Arc::new(LibrarySettingsImpl::new(100, 100).unwrap()), species: crate::static_data::libraries::species_library::tests::build(), moves: crate::static_data::libraries::move_library::tests::build(), diff --git a/src/static_data/libraries/type_library.rs b/src/static_data/libraries/type_library.rs index 8bd2ab3..99f0b37 100755 --- a/src/static_data/libraries/type_library.rs +++ b/src/static_data/libraries/type_library.rs @@ -1,9 +1,10 @@ use anyhow_ext::Result; use atomig::Atom; use hashbrown::HashMap; +use parking_lot::{RwLock, RwLockReadGuard}; use std::fmt::{Debug, Display}; -use crate::{PkmnError, StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::{PkmnError, StringKey}; /// A unique key that can be used to store a reference to a type. Opaque reference to a byte /// internally. @@ -33,7 +34,7 @@ impl Display for TypeIdentifier { } /// All data related to types and effectiveness. -pub trait TypeLibrary: Debug + ValueIdentifiable { +pub trait TypeLibrary: Debug { /// Gets the type identifier for a type with a name. fn get_type_id(&self, key: &StringKey) -> Option; @@ -49,48 +50,56 @@ pub trait TypeLibrary: Debug + ValueIdentifiable { fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result; /// Registers a new type in the library. - fn register_type(&mut self, name: &StringKey) -> TypeIdentifier; + fn register_type(&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, - ) -> Result<()>; + fn set_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32) + -> Result<()>; } /// All data related to types and effectiveness. #[derive(Debug)] pub struct TypeLibraryImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// A list of types - types: HashMap, + types: RwLock>, /// The effectiveness of the different types against each other. - effectiveness: Vec>, + effectiveness: RwLock>>, } impl TypeLibraryImpl { /// Instantiates a new type library with a specific capacity. pub fn new(capacity: usize) -> Self { Self { - identifier: Default::default(), - types: HashMap::with_capacity(capacity), - effectiveness: vec![], + types: RwLock::new(HashMap::with_capacity(capacity)), + effectiveness: RwLock::new(vec![]), } } } +impl TypeLibraryImpl { + fn get_single_effectiveness_with_lock( + lock: &RwLockReadGuard>>, + attacking: TypeIdentifier, + defending: TypeIdentifier, + ) -> Result { + Ok(*lock + .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 })?) + } +} + impl TypeLibrary for TypeLibraryImpl { /// Gets the type identifier for a type with a name. fn get_type_id(&self, key: &StringKey) -> Option { - self.types.get(key).cloned() + self.types.read().get(key).cloned() } /// Gets the type name from the type identifier. fn get_type_name(&self, t: TypeIdentifier) -> Option { - for kv in &self.types { + let types = self.types.read(); + for kv in types.iter() { if *kv.1 == t { return Some(kv.0.clone()); } @@ -100,12 +109,7 @@ 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) -> 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 })?) + Self::get_single_effectiveness_with_lock(&self.effectiveness.read(), attacking, defending) } /// Gets the effectiveness for a single attacking type against an amount of defending types. @@ -113,20 +117,24 @@ impl TypeLibrary for TypeLibraryImpl { /// multiplying the results with each other. fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result { let mut e = 1.0; + let lock = self.effectiveness.read(); for def in defending { - e *= self.get_single_effectiveness(attacking, *def)?; + e *= Self::get_single_effectiveness_with_lock(&lock, attacking, *def)?; } Ok(e) } /// Registers a new type in the library. - fn register_type(&mut self, name: &StringKey) -> TypeIdentifier { + fn register_type(&self, name: &StringKey) -> TypeIdentifier { + let mut types_write_lock = self.types.write(); + let mut effectiveness_write_lock = self.effectiveness.write(); + let id = TypeIdentifier { - val: (self.types.len() + 1) as u8, + val: (types_write_lock.len() + 1) as u8, }; - self.types.insert(name.clone(), id); - self.effectiveness.resize((id.val) as usize, vec![]); - for effectiveness in &mut self.effectiveness { + types_write_lock.insert(name.clone(), id); + effectiveness_write_lock.resize((id.val) as usize, vec![]); + for effectiveness in &mut effectiveness_write_lock.iter_mut() { effectiveness.resize((id.val) as usize, 1.0) } id @@ -134,13 +142,14 @@ impl TypeLibrary for TypeLibraryImpl { /// Sets the effectiveness for an attacking type against a defending type. fn set_effectiveness( - &mut self, + &self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32, ) -> Result<()> { *self .effectiveness + .write() .get_mut((attacking.val - 1) as usize) .ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })? .get_mut((defending.val - 1) as usize) @@ -149,12 +158,6 @@ impl TypeLibrary for TypeLibraryImpl { } } -impl ValueIdentifiable for TypeLibraryImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] diff --git a/src/static_data/mod.rs b/src/static_data/mod.rs index a84e7ba..c2412ec 100755 --- a/src/static_data/mod.rs +++ b/src/static_data/mod.rs @@ -1,4 +1,4 @@ -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; #[doc(inline)] pub use growth_rates::*; #[doc(inline)] @@ -56,57 +56,46 @@ mod statistics; #[derive(PartialEq, Debug, Clone)] pub enum EffectParameter { /// A boolean value. - Bool(ValueIdentifier, bool), + Bool(bool), /// An integer value. Stored as a 64 bit int to deal with potentially large numbers. - Int(ValueIdentifier, i64), + Int(i64), /// A float value. Stored as a 32 bit float. - Float(ValueIdentifier, f32), + Float(f32), /// A string value. - String(ValueIdentifier, StringKey), + String(StringKey), } impl From for EffectParameter { fn from(b: bool) -> Self { - EffectParameter::Bool(Default::default(), b) + EffectParameter::Bool(b) } } impl From for EffectParameter { fn from(i: i64) -> Self { - EffectParameter::Int(Default::default(), i) + EffectParameter::Int(i) } } impl From for EffectParameter { fn from(f: f32) -> Self { - EffectParameter::Float(Default::default(), f) + EffectParameter::Float(f) } } impl From for EffectParameter { fn from(s: StringKey) -> Self { - EffectParameter::String(Default::default(), s) + EffectParameter::String(s) } } impl Display for EffectParameter { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - EffectParameter::Bool(_, v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")), - EffectParameter::Int(_, v) => f.write_fmt(format_args!("EffectParameter::Int({v})")), - EffectParameter::Float(_, v) => f.write_fmt(format_args!("EffectParameter::Float({v})")), - EffectParameter::String(_, v) => f.write_fmt(format_args!("EffectParameter::String({v})")), - } - } -} - -impl ValueIdentifiable for EffectParameter { - fn value_identifier(&self) -> ValueIdentifier { - match self { - EffectParameter::Bool(i, _) => *i, - EffectParameter::Int(i, _) => *i, - EffectParameter::Float(i, _) => *i, - EffectParameter::String(i, _) => *i, + EffectParameter::Bool(v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")), + EffectParameter::Int(v) => f.write_fmt(format_args!("EffectParameter::Int({v})")), + EffectParameter::Float(v) => f.write_fmt(format_args!("EffectParameter::Float({v})")), + EffectParameter::String(v) => f.write_fmt(format_args!("EffectParameter::String({v})")), } } } diff --git a/src/static_data/moves/move_data.rs b/src/static_data/moves/move_data.rs index 448a380..465e4ee 100755 --- a/src/static_data/moves/move_data.rs +++ b/src/static_data/moves/move_data.rs @@ -2,9 +2,10 @@ use hashbrown::HashSet; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::fmt::Debug; +use std::sync::Arc; use crate::static_data::{SecondaryEffect, TypeIdentifier}; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; /// The move category defines what global kind of move this move is. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -61,7 +62,7 @@ pub enum MoveTarget { } /// A move is the skill Pokémon primarily use in battle. This is the data related to that. -pub trait MoveData: Debug + ValueIdentifiable { +pub trait MoveData: Debug { /// The name of the move. fn name(&self) -> &StringKey; /// The attacking type of the move. @@ -82,7 +83,7 @@ pub trait MoveData: Debug + ValueIdentifiable { fn priority(&self) -> i8; /// The optional secondary effect the move has. - fn secondary_effect(&self) -> &Option>; + fn secondary_effect(&self) -> &Option>; /// Arbitrary flags that can be applied to the move. fn has_flag(&self, key: &StringKey) -> bool; @@ -94,8 +95,6 @@ pub trait MoveData: Debug + ValueIdentifiable { /// A move is the skill Pokémon primarily use in battle. This is the data related to that. #[derive(Debug)] pub struct MoveDataImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The name of the move. name: StringKey, /// The attacking type of the move. @@ -114,7 +113,7 @@ pub struct MoveDataImpl { /// The priority of the move. A higher priority means the move should go before other moves. priority: i8, /// The optional secondary effect the move has. - secondary_effect: Option>, + secondary_effect: Option>, /// Arbitrary flags that can be applied to the move. flags: HashSet, } @@ -130,11 +129,10 @@ impl MoveDataImpl { base_usages: u8, target: MoveTarget, priority: i8, - secondary_effect: Option>, + secondary_effect: Option>, flags: HashSet, ) -> Self { Self { - identifier: Default::default(), name: name.clone(), move_type, category, @@ -186,7 +184,7 @@ impl MoveData for MoveDataImpl { } /// The optional secondary effect the move has. - fn secondary_effect(&self) -> &Option> { + fn secondary_effect(&self) -> &Option> { &self.secondary_effect } @@ -201,12 +199,6 @@ impl MoveData for MoveDataImpl { } } -impl ValueIdentifiable for MoveDataImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -225,14 +217,9 @@ pub(crate) mod tests { fn base_usages(&self) -> u8; fn target(&self) -> MoveTarget; fn priority(&self) -> i8; - fn secondary_effect(&self) -> &Option>; + fn secondary_effect(&self) -> &Option>; fn has_flag(&self, key: &StringKey) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool; } - impl ValueIdentifiable for MoveData{ - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } - } } } diff --git a/src/static_data/moves/secondary_effect.rs b/src/static_data/moves/secondary_effect.rs index 8ee083c..07fd518 100755 --- a/src/static_data/moves/secondary_effect.rs +++ b/src/static_data/moves/secondary_effect.rs @@ -1,10 +1,10 @@ use crate::static_data::EffectParameter; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; use std::fmt::Debug; use std::sync::Arc; /// A secondary effect is an effect on a move that happens after it hits. -pub trait SecondaryEffect: Debug + ValueIdentifiable { +pub trait SecondaryEffect: Debug { /// The chance in percentages that the effect triggers. -1 to make it always trigger. fn chance(&self) -> f32; /// The name of the effect. @@ -16,8 +16,6 @@ pub trait SecondaryEffect: Debug + ValueIdentifiable { /// A secondary effect is an effect on a move that happens after it hits. #[derive(Debug)] pub struct SecondaryEffectImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The chance in percentages that the effect triggers. -1 to make it always trigger. chance: f32, /// The name of the effect. @@ -30,7 +28,6 @@ impl SecondaryEffectImpl { /// Instantiates a new Secondary Effect. pub fn new(chance: f32, effect_name: StringKey, parameters: Vec>) -> Self { Self { - identifier: Default::default(), chance, effect_name, parameters, @@ -53,12 +50,6 @@ impl SecondaryEffect for SecondaryEffectImpl { } } -impl ValueIdentifiable for SecondaryEffectImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -77,11 +68,6 @@ pub(crate) mod tests { fn effect_name(&self) -> &StringKey; fn parameters(&self) -> &Vec>; } - impl ValueIdentifiable for SecondaryEffect{ - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) - } - } } #[test] diff --git a/src/static_data/natures.rs b/src/static_data/natures.rs index 7b273df..ede2472 100755 --- a/src/static_data/natures.rs +++ b/src/static_data/natures.rs @@ -1,11 +1,10 @@ use crate::static_data::Statistic; -use crate::{ValueIdentifiable, ValueIdentifier}; use std::fmt::Debug; use std::sync::Arc; /// A nature is an attribute on a Pokemon that modifies the effective base stats on a Pokemon. They /// can have an increased statistic and a decreased statistic, or be neutral. -pub trait Nature: ValueIdentifiable + Debug { +pub trait Nature: Debug { /// The stat that should receive the increased modifier. fn increased_stat(&self) -> Statistic; @@ -27,8 +26,6 @@ pub trait Nature: ValueIdentifiable + Debug { /// can have an increased statistic and a decreased statistic, or be neutral. #[derive(Debug)] pub struct NatureImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The stat that should receive the increased modifier. increase_stat: Statistic, /// The stat that should receive the decreased modifier. @@ -48,7 +45,6 @@ impl NatureImpl { decrease_modifier: f32, ) -> Arc { Arc::new(Self { - identifier: Default::default(), increase_stat, decrease_stat, increase_modifier, @@ -89,12 +85,6 @@ impl Nature for NatureImpl { } } -impl ValueIdentifiable for NatureImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -111,10 +101,5 @@ pub(crate) mod tests { fn decreased_modifier(&self) -> f32; fn get_stat_modifier(&self, stat: Statistic) -> f32; } - impl ValueIdentifiable for Nature { - fn value_identifier(&self) -> ValueIdentifier { - ValueIdentifier::new(0) - } - } } } diff --git a/src/static_data/species_data/ability.rs b/src/static_data/species_data/ability.rs index 425763c..726f3ff 100755 --- a/src/static_data/species_data/ability.rs +++ b/src/static_data/species_data/ability.rs @@ -1,10 +1,10 @@ use crate::static_data::EffectParameter; -use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use crate::StringKey; use std::fmt::Debug; use std::sync::Arc; /// An ability is a passive effect in battle that is attached to a Pokemon. -pub trait Ability: Debug + ValueIdentifiable { +pub trait Ability: Debug { /// The name of the ability. fn name(&self) -> &StringKey; /// The name of the script effect of the ability. @@ -16,8 +16,6 @@ pub trait Ability: Debug + ValueIdentifiable { /// An ability is a passive effect in battle that is attached to a Pokemon. #[derive(Debug)] pub struct AbilityImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The name of the ability. name: StringKey, /// The name of the script effect of the ability. @@ -30,7 +28,6 @@ impl AbilityImpl { /// Instantiates a new ability. pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec>) -> Self { Self { - identifier: Default::default(), name: name.clone(), effect: effect.clone(), parameters, @@ -53,12 +50,6 @@ impl Ability for AbilityImpl { } } -impl ValueIdentifiable for AbilityImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - /// An ability index allows us to find an ability on a form. It combines a bool for whether the /// ability is hidden or not, and then an index of the ability. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -84,10 +75,5 @@ pub(crate) mod tests { fn effect(&self) -> &StringKey; fn parameters(&self) -> &Vec>; } - impl ValueIdentifiable for Ability { - fn value_identifier(&self) -> ValueIdentifier { - ValueIdentifier::new(0) - } - } } } diff --git a/src/static_data/species_data/form.rs b/src/static_data/species_data/form.rs index a5fd7d4..110ec3b 100755 --- a/src/static_data/species_data/form.rs +++ b/src/static_data/species_data/form.rs @@ -7,12 +7,12 @@ use crate::static_data::Statistic; use crate::static_data::TypeIdentifier; use crate::static_data::{Ability, StaticStatisticSet}; use crate::static_data::{AbilityIndex, LearnableMoves}; -use crate::{Random, ValueIdentifiable, ValueIdentifier}; +use crate::Random; 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. -pub trait Form: ValueIdentifiable + Debug { +pub trait Form: Debug { /// The name of the form. fn name(&self) -> &StringKey; /// The height of the form in meters. @@ -31,7 +31,7 @@ pub trait Form: ValueIdentifiable + Debug { fn hidden_abilities(&self) -> &Vec; /// The moves a Pokemon with this form can learn. - fn moves(&self) -> &Box; + fn moves(&self) -> &Arc; /// Arbitrary flags can be set on a form for scripting use. fn flags(&self) -> &HashSet; @@ -62,8 +62,6 @@ pub trait Form: ValueIdentifiable + Debug { /// many more. #[derive(Debug)] pub struct FormImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The name of the form. name: StringKey, /// The height of the form in meters. @@ -81,7 +79,7 @@ pub struct FormImpl { /// The possible hidden abilities a Pokemon with this form can have. hidden_abilities: Vec, /// The moves a Pokemon with this form can learn. - moves: Box, + moves: Arc, /// Arbitrary flags can be set on a form for scripting use. flags: HashSet, } @@ -94,20 +92,19 @@ impl FormImpl { weight: f32, base_experience: u32, types: Vec, - base_stats: StaticStatisticSet, + base_stats: Arc>, abilities: Vec, hidden_abilities: Vec, - moves: Box, + moves: Arc, flags: HashSet, ) -> Self { Self { - identifier: Default::default(), name: name.clone(), height, weight, base_experience, types, - base_stats: Arc::new(base_stats), + base_stats, abilities, hidden_abilities, moves, @@ -151,7 +148,7 @@ impl Form for FormImpl { } /// The moves a Pokemon with this form can learn. - fn moves(&self) -> &Box { + fn moves(&self) -> &Arc { &self.moves } /// Arbitrary flags can be set on a form for scripting use. @@ -222,12 +219,6 @@ impl Form for FormImpl { } } -impl ValueIdentifiable for FormImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -246,7 +237,7 @@ pub(crate) mod tests { fn base_stats(&self) -> &Arc>; fn abilities(&self) -> &Vec; fn hidden_abilities(&self) -> &Vec; - fn moves(&self) -> &Box; + fn moves(&self) -> &Arc; fn flags(&self) -> &HashSet; fn get_type(&self, index: usize) -> Result; fn get_base_stat(&self, stat: Statistic) -> u16; @@ -257,10 +248,5 @@ pub(crate) mod tests { fn has_flag(&self, key: &StringKey) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool; } - impl ValueIdentifiable for Form { - fn value_identifier(&self) -> ValueIdentifier { - ValueIdentifier::new(0) - } - } } } diff --git a/src/static_data/species_data/learnable_moves.rs b/src/static_data/species_data/learnable_moves.rs index 63e05e2..b81e38c 100755 --- a/src/static_data/species_data/learnable_moves.rs +++ b/src/static_data/species_data/learnable_moves.rs @@ -1,5 +1,6 @@ use anyhow_ext::Result; use indexmap::IndexSet; +use parking_lot::RwLock; use std::fmt::Debug; use crate::defines::LevelInt; @@ -8,27 +9,27 @@ 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) -> Result<()>; + fn add_level_move(&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>; + fn get_learned_by_level(&self, level: LevelInt) -> Option>; /// Gets the distinct moves a Pokemon can learn through leveling up. - fn get_distinct_level_moves(&self) -> &IndexSet; + fn get_distinct_level_moves(&self) -> IndexSet; } /// The storage of the moves a Pokemon can learn. -#[derive(PartialEq, Eq, Debug)] +#[derive(Debug)] pub struct LearnableMovesImpl { /// A map of the moves a Pokemon can learn per level. - learned_by_level: Vec>, + learned_by_level: RwLock>>, /// A list of the distinct moves a Pokemon can learn through leveling up. - distinct_level_moves: IndexSet, + distinct_level_moves: RwLock>, } impl LearnableMovesImpl { /// Instantiates a new Learnable Moves. pub fn new(max_level: LevelInt) -> Self { Self { - learned_by_level: vec![Vec::new(); (max_level + 1) as usize], + learned_by_level: RwLock::new(vec![Vec::new(); (max_level + 1) as usize]), distinct_level_moves: Default::default(), } } @@ -36,20 +37,23 @@ 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) -> Result<()> { - self.learned_by_level.get_mut_res(level as usize)?.push(m.clone()); - self.distinct_level_moves.insert(m.clone()); + fn add_level_move(&self, level: LevelInt, m: &StringKey) -> Result<()> { + self.learned_by_level + .write() + .get_mut_res(level as usize)? + .push(m.clone()); + self.distinct_level_moves.write().insert(m.clone()); Ok(()) } /// Gets all moves a Pokemon can learn when leveling up to a specific level. - fn get_learned_by_level(&self, level: LevelInt) -> Option<&Vec> { - self.learned_by_level.get(level as usize) + fn get_learned_by_level(&self, level: LevelInt) -> Option> { + self.learned_by_level.read().get(level as usize).cloned() } /// Gets the distinct moves a Pokemon can learn through leveling up. - fn get_distinct_level_moves(&self) -> &IndexSet { - &self.distinct_level_moves + fn get_distinct_level_moves(&self) -> IndexSet { + self.distinct_level_moves.read().clone() } } @@ -61,7 +65,7 @@ pub(crate) mod tests { #[test] fn adds_level_moves() { - let mut moves = LearnableMovesImpl::new(100); + let moves = LearnableMovesImpl::new(100); moves.add_level_move(1, &"foo".into()).unwrap(); moves.add_level_move(1, &"bar".into()).unwrap(); @@ -73,7 +77,7 @@ pub(crate) mod tests { #[test] fn adds_two_same_moves_at_different_level() { - let mut moves = LearnableMovesImpl::new(100); + let moves = LearnableMovesImpl::new(100); moves.add_level_move(1, &"foo".into()).unwrap(); moves.add_level_move(5, &"foo".into()).unwrap(); diff --git a/src/static_data/species_data/species.rs b/src/static_data/species_data/species.rs index e920f5f..6d8a940 100755 --- a/src/static_data/species_data/species.rs +++ b/src/static_data/species_data/species.rs @@ -8,11 +8,11 @@ use parking_lot::{RawRwLock, RwLock}; use crate::static_data::Form; use crate::static_data::Gender; +use crate::Random; use crate::StringKey; -use crate::{Random, ValueIdentifiable, ValueIdentifier}; /// The data belonging to a Pokemon with certain characteristics. -pub trait Species: ValueIdentifiable + Debug { +pub trait Species: Debug { /// The national dex identifier of the Pokemon. fn id(&self) -> u16; /// The name of the Pokemon. @@ -47,8 +47,6 @@ pub trait Species: ValueIdentifiable + Debug { /// The data belonging to a Pokemon with certain characteristics. #[derive(Debug)] pub struct SpeciesImpl { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The national dex identifier of the Pokemon. id: u16, /// The name of the Pokemon. @@ -88,7 +86,6 @@ impl SpeciesImpl { let mut forms = HashMap::with_capacity(1); forms.insert_unique_unchecked(get_default_key(), default_form); Self { - identifier: Default::default(), id, name: name.clone(), gender_rate, @@ -176,12 +173,6 @@ impl Species for SpeciesImpl { } } -impl ValueIdentifiable for SpeciesImpl { - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] #[allow(clippy::unwrap_used)] @@ -207,10 +198,5 @@ pub(crate) mod tests { fn has_flag(&self, key: &StringKey) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool; } - impl ValueIdentifiable for Species { - fn value_identifier(&self) -> ValueIdentifier { - ValueIdentifier::new(0) - } - } } } diff --git a/src/static_data/statistic_set.rs b/src/static_data/statistic_set.rs index d6bcb38..4d40749 100755 --- a/src/static_data/statistic_set.rs +++ b/src/static_data/statistic_set.rs @@ -1,6 +1,5 @@ use std::sync::atomic::Ordering; -use crate::{ValueIdentifiable, ValueIdentifier}; use atomig::impls::{PrimitiveAtom, PrimitiveAtomInteger}; use atomig::{Atom, AtomInteger, Atomic}; use num_traits::{clamp, NumCast, PrimInt}; @@ -20,8 +19,6 @@ where ::Repr: PrimitiveAtomInteger, T: AtomInteger, { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The health point stat value. hp: Atomic, /// The physical attack stat value. @@ -47,7 +44,6 @@ where /// Creates a new statistic set with given stats. pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { Self { - identifier: Default::default(), hp: Atomic::::new(hp), attack: Atomic::::new(attack), defense: Atomic::::new(defense), @@ -131,19 +127,6 @@ where } } -impl ValueIdentifiable for StatisticSet -where - T: PrimitiveAtom, - T: Atom, - T: PrimitiveAtomInteger, - ::Repr: PrimitiveAtomInteger, - T: AtomInteger, -{ - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - /// A collection of statistics that can not be modified after creation. /// /// As no modifications happen, this struct does not use atomics. @@ -152,8 +135,6 @@ pub struct StaticStatisticSet where T: PrimInt, { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The health point stat value. hp: T, /// The physical attack stat value. @@ -175,7 +156,6 @@ where /// Create a new static statistic set. pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { Self { - identifier: Default::default(), hp, attack, defense, @@ -223,15 +203,6 @@ where } } -impl ValueIdentifiable for StaticStatisticSet -where - T: PrimInt, -{ - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - /// A clamped statistic set holds the 6 normal stats for a Pokemon, but ensures it always remains /// between two values (inclusive on the two values). #[derive(Default, Debug)] @@ -245,8 +216,6 @@ where T: NumCast, T: PrimInt, { - /// A unique identifier so we know what value this is. - identifier: ValueIdentifier, /// The health point stat value. hp: Atomic, /// The physical attack stat value. @@ -295,7 +264,6 @@ where /// Instantiates a new clamped statistic set. pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { Self { - identifier: Default::default(), hp: Self::clamped_cast(hp), attack: Self::clamped_cast(attack), defense: Self::clamped_cast(defense), @@ -409,21 +377,6 @@ where } } -impl ValueIdentifiable for ClampedStatisticSet -where - T: PrimitiveAtom, - T: Atom, - T: PrimitiveAtomInteger, - ::Repr: PrimitiveAtomInteger, - T: AtomInteger, - T: NumCast, - T: PrimInt, -{ - fn value_identifier(&self) -> ValueIdentifier { - self.identifier - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 7c3c508..7754bd7 100755 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -3,8 +3,6 @@ pub use random::Random; #[doc(inline)] pub use string_key::StringKey; #[doc(inline)] -pub use value_identifier::*; -#[doc(inline)] pub use vec_ext::*; /// The random module defines a RNG implementation used in pkmn_lib @@ -12,7 +10,5 @@ mod random; /// The string_key module defines a custom string handling for reduced allocations and fast lookups /// and equality checks. mod string_key; -/// Helper tool to keep track of moving memory for FFI. -mod value_identifier; /// Helper functions for vecs mod vec_ext; diff --git a/src/utils/string_key.rs b/src/utils/string_key.rs index 158f555..4ced669 100755 --- a/src/utils/string_key.rs +++ b/src/utils/string_key.rs @@ -1,4 +1,3 @@ -use crate::{ValueIdentifiable, ValueIdentifier}; use arcstr::ArcStr; use hashbrown::HashMap; use parking_lot::RwLock; @@ -126,12 +125,6 @@ impl From<&CStr> for StringKey { } } -impl ValueIdentifiable for StringKey { - fn value_identifier(&self) -> ValueIdentifier { - ValueIdentifier::new(self.hash as usize) - } -} - /// The difference in ascii characters to translate from uppercase to lowercase. const CAPITAL_DIFF: u8 = b'a' - b'A'; diff --git a/src/utils/value_identifier.rs b/src/utils/value_identifier.rs deleted file mode 100644 index 0304f99..0000000 --- a/src/utils/value_identifier.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -/// The current index for the value counter. -static CURRENT: AtomicUsize = AtomicUsize::new(1); - -/// An extremely basic way to identify a piece of data. -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -#[repr(C)] -pub struct ValueIdentifier(usize); - -impl Default for ValueIdentifier { - fn default() -> Self { - Self(CURRENT.fetch_add(1, Ordering::SeqCst)) - } -} - -impl ValueIdentifier { - /// Creates an identifier by number. - pub(crate) fn new(v: usize) -> Self { - Self(v) - } - - /// Get the underlying numeric integer of the value - pub fn value(&self) -> usize { - self.0 - } -} - -/// An object with a specific identifier. -pub trait ValueIdentifiable { - /// Get the identifier for the current object. - fn value_identifier(&self) -> ValueIdentifier; -} diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index aaf82a0..bc8a8e6 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -107,7 +107,7 @@ pub fn load_types(path: &String) -> Arc { .from_path(path.to_string() + "Types.csv") .unwrap(); - let mut type_library = TypeLibraryImpl::new(20); + let type_library = TypeLibraryImpl::new(20); let headers = reader.headers().unwrap(); for header in headers.iter().skip(1) { @@ -135,7 +135,7 @@ pub fn load_natures(path: &String) -> Arc { .from_path(path.to_string() + "Natures.csv") .unwrap(); - let mut nature_library = NatureLibraryImpl::new(24); + let nature_library = NatureLibraryImpl::new(24); for record in reader.records() { let record = record.unwrap(); let nature_name = record.get(0).unwrap().into(); @@ -162,7 +162,7 @@ pub fn load_items(path: &String) -> Arc { let json: Value = serde_json::from_str(&data).unwrap(); let json_array = json.as_array().unwrap(); - let mut item_library = ItemLibraryImpl::new(400); + let item_library = ItemLibraryImpl::new(400); for v in json_array { let name = v.get("name").unwrap().as_str().unwrap().into(); let category = serde_json::from_value(v.get("itemType").unwrap().clone()).unwrap(); @@ -194,7 +194,7 @@ pub fn load_growth_rates(path: &String) -> Arc { let json: Value = serde_json::from_str(&data).unwrap(); let o = json.as_object().unwrap(); - let mut growth_rate_library = GrowthRateLibraryImpl::new(10); + let growth_rate_library = GrowthRateLibraryImpl::new(10); for (key, value) in o { let name = StringKey::new(key); let experience_required_json = value.as_array().unwrap(); @@ -203,7 +203,7 @@ pub fn load_growth_rates(path: &String) -> Arc { experience_required.push(v.as_i64().unwrap() as u32); } - growth_rate_library.add_growth_rate(&name, Box::new(LookupGrowthRate::new(experience_required))); + growth_rate_library.add_growth_rate(&name, Arc::new(LookupGrowthRate::new(experience_required))); } Arc::new(growth_rate_library) } @@ -215,7 +215,7 @@ pub fn load_abilities(path: &String) -> Arc { let json: Value = serde_json::from_str(&data).unwrap(); let o = json.as_object().unwrap(); - let mut ability_library = AbilityLibraryImpl::new(400); + let ability_library = AbilityLibraryImpl::new(400); for (key, value) in o { let name = StringKey::new(key); let mut effect = StringKey::empty(); @@ -240,7 +240,7 @@ pub fn load_moves(path: &String, types: &Arc) -> Arc) -> Arc> = if let Some(v) = move_data.get("effect") { + let secondary_effect: Option> = if let Some(v) = move_data.get("effect") { let mut chance = -1.0; if let Some(chance_value) = v.get("chance") { chance = chance_value.as_f64().unwrap() as f32; @@ -265,7 +265,7 @@ pub fn load_moves(path: &String, types: &Arc) -> Arc Box { - Box::new(EmptyScriptResolver::default()) +fn load_script_resolver(path: &String) -> Arc { + Arc::new(EmptyScriptResolver::default()) } #[cfg(feature = "wasm")] -fn load_script_resolver(path: &String) -> Box { - let mut resolver = pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver::new(); +fn load_script_resolver(path: &String) -> Arc { + let resolver = pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver::new(); let file = File::open(path.to_string() + "gen7_scripts.wasm").unwrap(); let mut reader = BufReader::new(file); let mut buffer = Vec::new(); @@ -413,12 +413,12 @@ fn parse_form( )) } -fn parse_statistics(value: &Value) -> StaticStatisticSet +fn parse_statistics(value: &Value) -> Arc> where T: PrimInt + TryFrom, >::Error: Debug, { - StaticStatisticSet::new( + Arc::new(StaticStatisticSet::new( >::try_from(value.get("hp").unwrap_or(&Value::Number(0.into())).as_u64().unwrap()).unwrap(), >::try_from( value @@ -454,11 +454,11 @@ where .unwrap(), >::try_from(value.get("speed").unwrap_or(&Value::Number(0.into())).as_u64().unwrap()) .unwrap(), - ) + )) } -fn parse_moves(value: &Value, move_library: &Arc) -> Box { - let mut moves = LearnableMovesImpl::new(100); +fn parse_moves(value: &Value, move_library: &Arc) -> Arc { + let moves = LearnableMovesImpl::new(100); let level_moves = value.get("levelMoves").unwrap().as_array().unwrap(); for level_move in level_moves { @@ -468,7 +468,7 @@ fn parse_moves(value: &Value, move_library: &Arc) -> Box Arc { diff --git a/tests/common/test_step.rs b/tests/common/test_step.rs index f5fe1ed..65cd290 100755 --- a/tests/common/test_step.rs +++ b/tests/common/test_step.rs @@ -1,4 +1,5 @@ use serde::Deserialize; +use std::sync::Arc; use pkmn_lib::dynamic_data::Battle; use pkmn_lib::dynamic_data::{MoveChoice, PassChoice, TurnChoice}; @@ -56,12 +57,12 @@ impl TestStep { assert!(used_move.is_some()); assert!(battle - .try_set_choice(TurnChoice::Move(MoveChoice::new( + .try_set_choice(Arc::new(TurnChoice::Move(MoveChoice::new( pokemon, used_move.unwrap(), target[0], target[1], - ))) + )))) .unwrap()); } TestStep::SetPassChoice { for_pokemon } => { @@ -69,7 +70,9 @@ impl TestStep { .as_ref() .unwrap() .clone(); - assert!(battle.try_set_choice(TurnChoice::Pass(PassChoice::new(p))).unwrap()); + assert!(battle + .try_set_choice(Arc::new(TurnChoice::Pass(PassChoice::new(p)))) + .unwrap()); } TestStep::Assert { value, expected } => { let v = value.get(battle); diff --git a/tests/integration.rs b/tests/integration.rs index 33d49c1..bb7bfaa 100755 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,7 +1,8 @@ #![feature(custom_test_frameworks)] +#![feature(lazy_cell)] #![allow(clippy::borrowed_box)] -use std::sync::Arc; +use std::sync::{Arc, LazyLock}; use pkmn_lib::dynamic_data::{ Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty, @@ -13,8 +14,10 @@ use crate::common::library_loader; pub mod common; pub mod datatests; +static LIBRARY: LazyLock> = LazyLock::new(|| library_loader::load_library().library); + fn get_library() -> Arc { - library_loader::load_library().library + LIBRARY.clone() } #[test]