From 41b40ef98eb2ea8019b877e6f6177f770806aaa1 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 8 Oct 2022 13:15:04 +0200 Subject: [PATCH] Rework of FFI, adding a value identifier, so we can keep knowledge of data even when data moves. --- src/ffi/mod.rs | 72 +++++++++++++++++-- src/ffi/static_data/ability.rs | 24 ++++--- src/ffi/static_data/form.rs | 32 +++++---- src/ffi/static_data/item.rs | 19 ++--- .../libraries/growth_rate_library.rs | 6 +- .../static_data/libraries/library_settings.rs | 6 +- src/ffi/static_data/libraries/mod.rs | 14 ++-- .../static_data/libraries/nature_library.rs | 21 +++--- src/ffi/static_data/libraries/static_data.rs | 40 ++++++----- src/ffi/static_data/libraries/type_library.rs | 6 +- src/ffi/static_data/mod.rs | 30 ++++---- src/ffi/static_data/move_data.rs | 51 +++++++------ src/ffi/static_data/nature.rs | 27 +++---- src/ffi/static_data/species.rs | 40 ++++++----- src/ffi/static_data/statistic_set.rs | 14 ++-- .../wasm/export_registry/mod.rs | 16 ++--- src/static_data/items.rs | 11 ++- src/static_data/libraries/ability_library.rs | 14 +++- src/static_data/libraries/data_library.rs | 4 +- .../libraries/growth_rate_library.rs | 11 ++- src/static_data/libraries/item_library.rs | 14 +++- src/static_data/libraries/library_settings.rs | 14 +++- src/static_data/libraries/move_library.rs | 14 +++- src/static_data/libraries/nature_library.rs | 19 +++-- src/static_data/libraries/species_library.rs | 18 +++-- src/static_data/libraries/static_data.rs | 11 +++ src/static_data/libraries/type_library.rs | 11 ++- src/static_data/mod.rs | 53 +++++++++++--- src/static_data/moves/move_data.rs | 11 ++- src/static_data/moves/secondary_effect.rs | 11 ++- src/static_data/natures.rs | 17 ++++- src/static_data/species_data/ability.rs | 11 ++- src/static_data/species_data/form.rs | 11 ++- src/static_data/species_data/species.rs | 37 ++++++---- src/static_data/statistic_set.rs | 49 ++++++++++++- src/utils/mod.rs | 3 + src/utils/value_identifier.rs | 22 ++++++ tests/common/library_loader.rs | 28 ++++---- 38 files changed, 582 insertions(+), 230 deletions(-) create mode 100644 src/utils/value_identifier.rs diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index a1449f1..aab36ad 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -16,13 +16,26 @@ macro_rules! ffi_getter { }; } -macro_rules! ffi_stringkey_getter { +macro_rules! ffi_arc_getter { + ( + $type:ty, $func:ident, $returns: ty + ) => { + paste::paste! { + #[no_mangle] + extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer>) -> $returns { + ptr.as_ref().$func() + } + } + }; +} + +macro_rules! ffi_arc_stringkey_getter { ( $type:ty, $func:ident ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $type:lower _ $func >](ptr: ExternPointer<$type>) -> OwnedPtr { + extern "C" fn [< $type:lower _ $func >](ptr: ExternPointer>) -> OwnedPtr { std::ffi::CString::new(ptr.as_ref().$func().str()).unwrap().into_raw() } } @@ -35,11 +48,11 @@ macro_rules! ffi_vec_value_getters { ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer<$type>) -> usize { + extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer>) -> usize { ptr.as_ref().$func().len() } #[no_mangle] - extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer<$type>, index: usize) -> $returns { + extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer>, index: usize) -> $returns { *ptr.as_ref().$func().get(index).unwrap() } } @@ -52,21 +65,24 @@ macro_rules! ffi_vec_stringkey_getters { ) => { paste::paste! { #[no_mangle] - extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer<$type>) -> usize { + extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer>) -> usize { ptr.as_ref().$func().len() } #[no_mangle] - extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer<$type>, index: usize) -> OwnedPtr { + 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() } } }; } +use crate::{ValueIdentifiable, ValueIdentifier}; +pub(self) use ffi_arc_getter; +pub(self) use ffi_arc_stringkey_getter; pub(self) use ffi_getter; -pub(self) use ffi_stringkey_getter; pub(self) use ffi_vec_stringkey_getters; pub(self) use ffi_vec_value_getters; +use std::sync::Arc; #[repr(C)] pub(self) struct ExternPointer { @@ -98,3 +114,45 @@ impl Into> for *mut T { ExternPointer { ptr: self } } } + +#[repr(C)] +pub(self) struct IdentifiablePointer { + pub ptr: *const T, + pub id: ValueIdentifier, +} + +impl From> for IdentifiablePointer> { + fn from(v: Arc) -> Self { + let id = v.value_identifier(); + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } +} + +impl From> for IdentifiablePointer { + fn from(v: Box) -> Self { + let id = v.value_identifier(); + Self { + ptr: Box::into_raw(v), + id, + } + } +} + +impl From<*const T> for IdentifiablePointer { + fn from(v: *const T) -> Self { + let id = unsafe { v.as_ref() }.unwrap().value_identifier(); + Self { ptr: v, id } + } +} + +impl IdentifiablePointer { + pub fn none() -> Self { + Self { + ptr: std::ptr::null(), + id: Default::default(), + } + } +} diff --git a/src/ffi/static_data/ability.rs b/src/ffi/static_data/ability.rs index 40e7639..0f657e5 100644 --- a/src/ffi/static_data/ability.rs +++ b/src/ffi/static_data/ability.rs @@ -1,8 +1,9 @@ -use crate::ffi::{BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{Ability, EffectParameter}; use crate::StringKey; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; +use std::sync::Arc; #[no_mangle] unsafe extern "C" fn ability_new( @@ -10,7 +11,7 @@ unsafe extern "C" fn ability_new( effect: *const c_char, parameters: *const OwnedPtr, parameters_length: usize, -) -> OwnedPtr { +) -> IdentifiablePointer> { let parameters = std::slice::from_raw_parts(parameters, parameters_length); let mut parameters_vec: Vec = Vec::with_capacity(parameters_length); for parameter in parameters { @@ -20,34 +21,37 @@ unsafe extern "C" fn ability_new( let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let effect: StringKey = CStr::from_ptr(effect).to_str().unwrap().into(); - Box::into_raw(Box::new(Ability::new(&name, &effect, parameters_vec))) + Arc::new(Ability::new(&name, &effect, parameters_vec)).into() } #[no_mangle] -unsafe extern "C" fn ability_drop(ptr: OwnedPtr) { +unsafe extern "C" fn ability_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } #[no_mangle] -unsafe extern "C" fn ability_name(ptr: ExternPointer) -> OwnedPtr { +unsafe extern "C" fn ability_name(ptr: ExternPointer>) -> OwnedPtr { CString::new(ptr.as_ref().name().str()).unwrap().into_raw() } #[no_mangle] -unsafe extern "C" fn ability_effect(ptr: ExternPointer) -> OwnedPtr { +unsafe extern "C" fn ability_effect(ptr: ExternPointer>) -> OwnedPtr { CString::new(ptr.as_ref().effect().str()).unwrap().into_raw() } #[no_mangle] -unsafe extern "C" fn ability_parameter_length(ptr: ExternPointer) -> usize { +unsafe extern "C" fn ability_parameter_length(ptr: ExternPointer>) -> usize { ptr.as_ref().parameters().len() } #[no_mangle] -unsafe extern "C" fn ability_parameter_get(ptr: ExternPointer, index: usize) -> BorrowedPtr { +unsafe extern "C" fn ability_parameter_get( + ptr: ExternPointer>, + index: usize, +) -> IdentifiablePointer { if let Some(p) = ptr.as_ref().parameters().get(index) { - p as *const EffectParameter + (p as *const EffectParameter).into() } else { - std::ptr::null() + IdentifiablePointer::none() } } diff --git a/src/ffi/static_data/form.rs b/src/ffi/static_data/form.rs index 771145c..ccb20f3 100644 --- a/src/ffi/static_data/form.rs +++ b/src/ffi/static_data/form.rs @@ -1,9 +1,13 @@ -use crate::ffi::{ffi_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{ + ffi_arc_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer, IdentifiablePointer, + OwnedPtr, +}; use crate::static_data::{Form, LearnableMoves, StaticStatisticSet, TypeIdentifier}; use crate::StringKey; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; +use std::sync::Arc; #[no_mangle] unsafe extern "C" fn form_new( @@ -21,7 +25,7 @@ unsafe extern "C" fn form_new( moves: OwnedPtr, flags: *const *const c_char, flags_length: usize, -) -> OwnedPtr
{ +) -> IdentifiablePointer> { let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let abilities = std::slice::from_raw_parts(abilities, abilities_length); @@ -41,7 +45,7 @@ unsafe extern "C" fn form_new( flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into()); } - Box::into_raw(Box::new(Form::new( + Arc::new(Form::new( &name, height, weight, @@ -52,35 +56,39 @@ unsafe extern "C" fn form_new( hidden_abilities_vec, *Box::from_raw(moves), flags_set, - ))) + )) + .into() } #[no_mangle] -unsafe extern "C" fn form_drop(ptr: OwnedPtr) { +unsafe extern "C" fn form_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } #[no_mangle] -unsafe extern "C" fn form_name(ptr: ExternPointer) -> OwnedPtr { +unsafe extern "C" fn form_name(ptr: ExternPointer>) -> OwnedPtr { let name = ptr.as_ref().name(); CString::new(name.str()).unwrap().into_raw() } -ffi_getter!(Form, height, f32); -ffi_getter!(Form, weight, f32); -ffi_getter!(Form, base_experience, u32); +ffi_arc_getter!(Form, height, f32); +ffi_arc_getter!(Form, weight, f32); +ffi_arc_getter!(Form, base_experience, u32); ffi_vec_value_getters!(Form, types, TypeIdentifier); -ffi_getter!(Form, base_stats, BorrowedPtr>); +#[no_mangle] +unsafe extern "C" fn form_base_stats(ptr: ExternPointer>) -> IdentifiablePointer> { + (ptr.as_ref().base_stats() as *const StaticStatisticSet).into() +} ffi_vec_stringkey_getters!(Form, abilities); ffi_vec_stringkey_getters!(Form, hidden_abilities); -ffi_getter!(Form, moves, BorrowedPtr); +ffi_arc_getter!(Form, moves, BorrowedPtr); #[no_mangle] -unsafe extern "C" fn form_has_flag(ptr: ExternPointer, flag: *const c_char) -> u8 { +unsafe extern "C" fn form_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); if ptr.as_ref().has_flag(&flag) { 1 diff --git a/src/ffi/static_data/item.rs b/src/ffi/static_data/item.rs index 4a6f342..bfac537 100644 --- a/src/ffi/static_data/item.rs +++ b/src/ffi/static_data/item.rs @@ -1,9 +1,10 @@ -use crate::ffi::{ffi_getter, ExternPointer, OwnedPtr}; +use crate::ffi::{ffi_arc_getter, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{BattleItemCategory, Item, ItemCategory}; use crate::StringKey; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; +use std::sync::Arc; #[no_mangle] unsafe extern "C" fn item_new( @@ -13,33 +14,33 @@ unsafe extern "C" fn item_new( price: i32, flags: *const *const c_char, flags_length: usize, -) -> OwnedPtr { +) -> IdentifiablePointer> { let flags = std::slice::from_raw_parts(flags, flags_length); let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let mut flags_set: HashSet = HashSet::with_capacity(flags_length); for flag in flags { flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into()); } - Box::into_raw(Box::new(Item::new(&name, category, battle_category, price, flags_set))) + Arc::new(Item::new(&name, category, battle_category, price, flags_set)).into() } #[no_mangle] -unsafe extern "C" fn item_drop(ptr: OwnedPtr) { +unsafe extern "C" fn item_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } #[no_mangle] -unsafe extern "C" fn item_name(ptr: ExternPointer) -> OwnedPtr { +unsafe extern "C" fn item_name(ptr: ExternPointer>) -> OwnedPtr { let name = ptr.as_ref().name(); CString::new(name.str()).unwrap().into_raw() } -ffi_getter!(Item, category, ItemCategory); -ffi_getter!(Item, battle_category, BattleItemCategory); -ffi_getter!(Item, price, i32); +ffi_arc_getter!(Item, category, ItemCategory); +ffi_arc_getter!(Item, battle_category, BattleItemCategory); +ffi_arc_getter!(Item, price, i32); #[no_mangle] -unsafe extern "C" fn item_has_flag(ptr: ExternPointer, flag: *const c_char) -> u8 { +unsafe extern "C" fn item_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); if ptr.as_ref().has_flag(&flag) { 1 diff --git a/src/ffi/static_data/libraries/growth_rate_library.rs b/src/ffi/static_data/libraries/growth_rate_library.rs index 8a57eda..299af6c 100644 --- a/src/ffi/static_data/libraries/growth_rate_library.rs +++ b/src/ffi/static_data/libraries/growth_rate_library.rs @@ -1,12 +1,12 @@ use crate::defines::LevelInt; -use crate::ffi::{BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{GrowthRate, GrowthRateLibrary}; use std::ffi::{c_char, CStr}; use std::ptr::drop_in_place; #[no_mangle] -extern "C" fn growth_rate_library_new(capacity: usize) -> OwnedPtr { - Box::into_raw(Box::new(GrowthRateLibrary::new(capacity))) +extern "C" fn growth_rate_library_new(capacity: usize) -> IdentifiablePointer { + Box::new(GrowthRateLibrary::new(capacity)).into() } #[no_mangle] diff --git a/src/ffi/static_data/libraries/library_settings.rs b/src/ffi/static_data/libraries/library_settings.rs index 5fcd57e..a83c139 100644 --- a/src/ffi/static_data/libraries/library_settings.rs +++ b/src/ffi/static_data/libraries/library_settings.rs @@ -1,11 +1,11 @@ use crate::defines::LevelInt; -use crate::ffi::{ExternPointer, OwnedPtr}; +use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::LibrarySettings; use std::ptr::drop_in_place; #[no_mangle] -extern "C" fn library_settings_new(max_level: LevelInt) -> OwnedPtr { - Box::into_raw(Box::new(LibrarySettings::new(max_level))) +extern "C" fn library_settings_new(max_level: LevelInt) -> IdentifiablePointer { + Box::new(LibrarySettings::new(max_level)).into() } #[no_mangle] diff --git a/src/ffi/static_data/libraries/mod.rs b/src/ffi/static_data/libraries/mod.rs index 94b1fe0..6bd0440 100644 --- a/src/ffi/static_data/libraries/mod.rs +++ b/src/ffi/static_data/libraries/mod.rs @@ -4,7 +4,7 @@ mod nature_library; mod static_data; mod type_library; -use crate::ffi::{BorrowedPtr, OwnedPtr}; +use crate::ffi::{BorrowedPtr, IdentifiablePointer, OwnedPtr}; use crate::static_data::*; use std::ffi::{c_char, CStr}; use std::ptr::drop_in_place; @@ -14,8 +14,8 @@ macro_rules! library_interface { ($library_type:ty, $return_type:ty) => { paste::paste! { #[no_mangle] - extern "C" fn [< $library_type:snake _new >](capacity: usize) -> OwnedPtr<$library_type> { - Box::into_raw(Box::new($library_type::new(capacity))) + extern "C" fn [< $library_type:snake _new >](capacity: usize) -> IdentifiablePointer<$library_type> { + Box::new($library_type::new(capacity)).into() } #[no_mangle] @@ -24,7 +24,7 @@ macro_rules! library_interface { } #[no_mangle] - unsafe extern "C" fn [< $library_type:snake _add >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr, value: OwnedPtr<$return_type>) { + unsafe extern "C" fn [< $library_type: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)); } @@ -36,13 +36,13 @@ macro_rules! library_interface { } #[no_mangle] - unsafe extern "C" fn [< $library_type:snake _get >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr) -> BorrowedPtr<$return_type> { + unsafe extern "C" fn [< $library_type:snake _get >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr) -> IdentifiablePointer> { let lib = ptr.as_mut().unwrap(); let v = lib.get(&CStr::from_ptr(key).into()); if let Some(value) = v { - Arc::as_ptr(value) + value.clone().into() } else { - std::ptr::null() + IdentifiablePointer::none() } } diff --git a/src/ffi/static_data/libraries/nature_library.rs b/src/ffi/static_data/libraries/nature_library.rs index d1ae012..1b64ec7 100644 --- a/src/ffi/static_data/libraries/nature_library.rs +++ b/src/ffi/static_data/libraries/nature_library.rs @@ -1,12 +1,12 @@ -use crate::ffi::{BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{Nature, NatureLibrary}; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; use std::sync::Arc; #[no_mangle] -extern "C" fn nature_library_new(capacity: usize) -> OwnedPtr { - Box::into_raw(Box::new(NatureLibrary::new(capacity))) +extern "C" fn nature_library_new(capacity: usize) -> IdentifiablePointer { + Box::new(NatureLibrary::new(capacity)).into() } #[no_mangle] @@ -18,31 +18,30 @@ unsafe extern "C" fn nature_library_drop(ptr: OwnedPtr) { unsafe extern "C" fn nature_library_load_nature( ptr: ExternPointer, name: BorrowedPtr, - nature: OwnedPtr, + nature: OwnedPtr>, ) { ptr.as_mut() - .load_nature(CStr::from_ptr(name).into(), *Box::from_raw(nature)) + .load_nature(CStr::from_ptr(name).into(), nature.as_ref().unwrap().clone()) } #[no_mangle] unsafe extern "C" fn nature_library_get_nature( ptr: ExternPointer, name: BorrowedPtr, -) -> BorrowedPtr { +) -> IdentifiablePointer> { if let Some(nature) = ptr.as_ref().get_nature(&CStr::from_ptr(name).into()) { - Arc::into_raw(nature.clone()) + nature.clone().into() } else { - std::ptr::null() + IdentifiablePointer::none() } } #[no_mangle] unsafe extern "C" fn nature_library_get_nature_name( ptr: ExternPointer, - nature: BorrowedPtr, + nature: BorrowedPtr>, ) -> OwnedPtr { - let arc = Arc::from_raw(nature); - CString::new(ptr.as_ref().get_nature_name(&arc).str()) + CString::new(ptr.as_ref().get_nature_name(nature.as_ref().unwrap()).str()) .unwrap() .into_raw() } diff --git a/src/ffi/static_data/libraries/static_data.rs b/src/ffi/static_data/libraries/static_data.rs index ecfefd0..e71a1d9 100644 --- a/src/ffi/static_data/libraries/static_data.rs +++ b/src/ffi/static_data/libraries/static_data.rs @@ -1,4 +1,4 @@ -use crate::ffi::{BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{ AbilityLibrary, GrowthRateLibrary, ItemLibrary, LibrarySettings, MoveLibrary, NatureLibrary, SpeciesLibrary, StaticData, TypeLibrary, @@ -6,8 +6,8 @@ use crate::static_data::{ use std::ptr::drop_in_place; #[no_mangle] -unsafe extern "C" fn static_data_new(settings: OwnedPtr) -> OwnedPtr { - Box::into_raw(Box::new(StaticData::new(*Box::from_raw(settings)))) +unsafe extern "C" fn static_data_new(settings: OwnedPtr) -> IdentifiablePointer { + Box::new(StaticData::new(*Box::from_raw(settings))).into() } #[no_mangle] @@ -16,41 +16,43 @@ unsafe extern "C" fn static_data_drop(ptr: OwnedPtr) { } #[no_mangle] -unsafe extern "C" fn static_data_settings(data: ExternPointer) -> BorrowedPtr { - data.as_mut().settings() as *const LibrarySettings +unsafe extern "C" fn static_data_settings(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().settings() as *const LibrarySettings).into() } #[no_mangle] -unsafe extern "C" fn static_data_species(data: ExternPointer) -> BorrowedPtr { - data.as_mut().species_mut() as *mut SpeciesLibrary +unsafe extern "C" fn static_data_species(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().species_mut() as *const SpeciesLibrary).into() } #[no_mangle] -unsafe extern "C" fn static_data_moves(data: ExternPointer) -> BorrowedPtr { - data.as_mut().moves_mut() as *mut MoveLibrary +unsafe extern "C" fn static_data_moves(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().moves_mut() as *const MoveLibrary).into() } #[no_mangle] -unsafe extern "C" fn static_data_items(data: ExternPointer) -> BorrowedPtr { - data.as_mut().items_mut() as *mut ItemLibrary +unsafe extern "C" fn static_data_items(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().items_mut() as *const ItemLibrary).into() } #[no_mangle] -unsafe extern "C" fn static_data_growth_rates(data: ExternPointer) -> BorrowedPtr { - data.as_mut().growth_rates_mut() as *mut GrowthRateLibrary +unsafe extern "C" fn static_data_growth_rates( + data: ExternPointer, +) -> IdentifiablePointer { + (data.as_mut().growth_rates_mut() as *const GrowthRateLibrary).into() } #[no_mangle] -unsafe extern "C" fn static_data_types(data: ExternPointer) -> BorrowedPtr { - data.as_mut().types_mut() as *mut TypeLibrary +unsafe extern "C" fn static_data_types(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().types_mut() as *const TypeLibrary).into() } #[no_mangle] -unsafe extern "C" fn static_data_natures(data: ExternPointer) -> BorrowedPtr { - data.as_mut().natures_mut() as *mut NatureLibrary +unsafe extern "C" fn static_data_natures(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().natures_mut() as *const NatureLibrary).into() } #[no_mangle] -unsafe extern "C" fn static_data_abilities(data: ExternPointer) -> BorrowedPtr { - data.as_mut().abilities_mut() as *mut AbilityLibrary +unsafe extern "C" fn static_data_abilities(data: ExternPointer) -> IdentifiablePointer { + (data.as_mut().abilities_mut() as *const AbilityLibrary).into() } diff --git a/src/ffi/static_data/libraries/type_library.rs b/src/ffi/static_data/libraries/type_library.rs index 9d09b87..d23302d 100644 --- a/src/ffi/static_data/libraries/type_library.rs +++ b/src/ffi/static_data/libraries/type_library.rs @@ -1,11 +1,11 @@ -use crate::ffi::{BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{TypeIdentifier, TypeLibrary}; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; #[no_mangle] -extern "C" fn type_library_new(capacity: usize) -> OwnedPtr { - Box::into_raw(Box::new(TypeLibrary::new(capacity))) +extern "C" fn type_library_new(capacity: usize) -> IdentifiablePointer { + Box::new(TypeLibrary::new(capacity)).into() } #[no_mangle] diff --git a/src/ffi/static_data/mod.rs b/src/ffi/static_data/mod.rs index 607096d..ebd5e67 100644 --- a/src/ffi/static_data/mod.rs +++ b/src/ffi/static_data/mod.rs @@ -1,5 +1,6 @@ use crate::ffi::{ExternPointer, OwnedPtr}; use crate::static_data::EffectParameter; +use crate::StringKey; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; @@ -8,32 +9,31 @@ mod form; mod growth_rate; mod item; mod learnable_moves; +mod libraries; mod move_data; mod nature; mod species; mod statistic_set; -mod libraries; #[no_mangle] extern "C" fn effect_parameter_new_bool(value: u8) -> OwnedPtr { - Box::into_raw(Box::new(EffectParameter::Bool(value == 1))) + Box::into_raw(Box::new((value == 1).into())) } #[no_mangle] extern "C" fn effect_parameter_new_int(value: i64) -> OwnedPtr { - Box::into_raw(Box::new(EffectParameter::Int(value))) + Box::into_raw(Box::new(value.into())) } #[no_mangle] extern "C" fn effect_parameter_new_float(value: f32) -> OwnedPtr { - Box::into_raw(Box::new(EffectParameter::Float(value))) + Box::into_raw(Box::new(value.into())) } #[no_mangle] unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> OwnedPtr { - Box::into_raw(Box::new(EffectParameter::String( - CStr::from_ptr(value).to_str().unwrap().into(), - ))) + let sk: StringKey = CStr::from_ptr(value).to_str().unwrap().into(); + Box::into_raw(Box::new(sk.into())) } #[no_mangle] @@ -44,17 +44,17 @@ unsafe extern "C" fn effect_parameter_drop(ptr: OwnedPtr) { #[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, + EffectParameter::Bool(_, _) => 0, + EffectParameter::Int(_, _) => 1, + EffectParameter::Float(_, _) => 2, + EffectParameter::String(_, _) => 3, } } #[no_mangle] extern "C" fn effect_parameter_get_as_bool(ptr: ExternPointer) -> u8 { let p = ptr.as_ref(); - if let EffectParameter::Bool(b) = p { + if let EffectParameter::Bool(_, b) = p { return if *b { 1 } else { 0 }; } panic!("Unexpected effect parameter. Expected bool, was: {}", p); @@ -63,7 +63,7 @@ extern "C" fn effect_parameter_get_as_bool(ptr: ExternPointer) #[no_mangle] extern "C" fn effect_parameter_get_as_int(ptr: ExternPointer) -> i64 { let p = ptr.as_ref(); - if let EffectParameter::Int(b) = p { + if let EffectParameter::Int(_, b) = p { return *b; } panic!("Unexpected effect parameter. Expected int, was: {}", p); @@ -72,7 +72,7 @@ extern "C" fn effect_parameter_get_as_int(ptr: ExternPointer) - #[no_mangle] extern "C" fn effect_parameter_get_as_float(ptr: ExternPointer) -> f32 { let p = ptr.as_ref(); - if let EffectParameter::Float(b) = p { + if let EffectParameter::Float(_, b) = p { return *b; } panic!("Unexpected effect parameter. Expected float, was: {}", p); @@ -81,7 +81,7 @@ extern "C" fn effect_parameter_get_as_float(ptr: ExternPointer) #[no_mangle] extern "C" fn effect_parameter_get_as_string(ptr: ExternPointer) -> OwnedPtr { let p = ptr.as_ref(); - if let EffectParameter::String(b) = p { + if let EffectParameter::String(_, b) = p { return CString::new(b.str().to_string()).unwrap().into_raw(); } panic!("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 9a6be4d..e28233a 100644 --- a/src/ffi/static_data/move_data.rs +++ b/src/ffi/static_data/move_data.rs @@ -1,9 +1,10 @@ -use crate::ffi::{ffi_getter, BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{ffi_arc_getter, ffi_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, TypeIdentifier}; use crate::StringKey; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; +use std::sync::Arc; #[no_mangle] unsafe extern "C" fn move_data_new( @@ -18,7 +19,7 @@ unsafe extern "C" fn move_data_new( secondary_effect: *mut SecondaryEffect, flags: *const *const c_char, flags_length: usize, -) -> OwnedPtr { +) -> IdentifiablePointer> { let flags = std::slice::from_raw_parts(flags, flags_length); let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let mut flags_set: HashSet = HashSet::with_capacity(flags_length); @@ -30,7 +31,7 @@ unsafe extern "C" fn move_data_new( } else { Some(*Box::from_raw(secondary_effect)) }; - Box::into_raw(Box::new(MoveData::new( + Arc::new(MoveData::new( &name, move_type, category, @@ -41,40 +42,43 @@ unsafe extern "C" fn move_data_new( priority, secondary_effect, flags_set, - ))) + )) + .into() } #[no_mangle] -unsafe extern "C" fn move_data_drop(ptr: OwnedPtr) { +unsafe extern "C" fn move_data_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } #[no_mangle] -unsafe extern "C" fn move_data_name(ptr: ExternPointer) -> OwnedPtr { +unsafe extern "C" fn move_data_name(ptr: ExternPointer>) -> OwnedPtr { let name = ptr.as_ref().name(); CString::new(name.str()).unwrap().into_raw() } -ffi_getter!(MoveData, move_type, TypeIdentifier); -ffi_getter!(MoveData, category, MoveCategory); -ffi_getter!(MoveData, base_power, u8); -ffi_getter!(MoveData, accuracy, u8); -ffi_getter!(MoveData, base_usages, u8); -ffi_getter!(MoveData, target, MoveTarget); -ffi_getter!(MoveData, priority, i8); +ffi_arc_getter!(MoveData, move_type, TypeIdentifier); +ffi_arc_getter!(MoveData, category, MoveCategory); +ffi_arc_getter!(MoveData, base_power, u8); +ffi_arc_getter!(MoveData, accuracy, u8); +ffi_arc_getter!(MoveData, base_usages, u8); +ffi_arc_getter!(MoveData, target, MoveTarget); +ffi_arc_getter!(MoveData, priority, i8); #[no_mangle] -unsafe extern "C" fn move_data_secondary_effect(ptr: ExternPointer) -> BorrowedPtr { +unsafe extern "C" fn move_data_secondary_effect( + ptr: ExternPointer>, +) -> IdentifiablePointer { let effect = ptr.as_ref().secondary_effect(); if let Some(v) = effect { - v as *const SecondaryEffect + (v as *const SecondaryEffect).into() } else { - std::ptr::null() + IdentifiablePointer::none() } } #[no_mangle] -unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer, flag: *const c_char) -> u8 { +unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); if ptr.as_ref().has_flag(&flag) { 1 @@ -89,18 +93,19 @@ unsafe extern "C" fn secondary_effect_new( effect_name: BorrowedPtr, parameters: *mut OwnedPtr, parameters_length: usize, -) -> OwnedPtr { +) -> IdentifiablePointer { 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)) } - Box::into_raw(Box::new(SecondaryEffect::new( + Box::new(SecondaryEffect::new( chance, CStr::from_ptr(effect_name).into(), parameters, - ))) + )) + .into() } #[no_mangle] @@ -124,10 +129,10 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer, index: usize, -) -> BorrowedPtr { +) -> IdentifiablePointer { if let Some(v) = ptr.as_ref().parameters().get(index) { - v as *const EffectParameter + (v as *const EffectParameter).into() } else { - std::ptr::null() + IdentifiablePointer::none() } } diff --git a/src/ffi/static_data/nature.rs b/src/ffi/static_data/nature.rs index 1b5cd9a..50bb171 100644 --- a/src/ffi/static_data/nature.rs +++ b/src/ffi/static_data/nature.rs @@ -1,6 +1,7 @@ -use crate::ffi::{ffi_getter, ExternPointer, OwnedPtr}; +use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{Nature, Statistic}; use std::ptr::drop_in_place; +use std::sync::Arc; #[no_mangle] extern "C" fn nature_new( @@ -8,24 +9,26 @@ extern "C" fn nature_new( decrease_stat: Statistic, increase_modifier: f32, decrease_modifier: f32, -) -> OwnedPtr { - Box::into_raw(Box::new(Nature::new( - increase_stat, - decrease_stat, - increase_modifier, - decrease_modifier, - ))) +) -> IdentifiablePointer> { + Nature::new(increase_stat, decrease_stat, increase_modifier, decrease_modifier).into() } #[no_mangle] -unsafe extern "C" fn nature_drop(ptr: OwnedPtr) { +unsafe extern "C" fn nature_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } -ffi_getter!(Nature, increased_stat, Statistic); -ffi_getter!(Nature, decreased_stat, Statistic); +#[no_mangle] +extern "C" fn nature_increased_stat(ptr: ExternPointer>) -> Statistic { + ptr.as_ref().increased_stat() +} #[no_mangle] -extern "C" fn nature_get_stat_modifier(ptr: ExternPointer, stat: Statistic) -> f32 { +extern "C" fn nature_decreased_stat(ptr: ExternPointer>) -> Statistic { + ptr.as_ref().decreased_stat() +} + +#[no_mangle] +extern "C" fn nature_get_stat_modifier(ptr: ExternPointer>, stat: Statistic) -> f32 { ptr.as_ref().get_stat_modifier(stat) } diff --git a/src/ffi/static_data/species.rs b/src/ffi/static_data/species.rs index dc8a8a3..7b79478 100644 --- a/src/ffi/static_data/species.rs +++ b/src/ffi/static_data/species.rs @@ -1,4 +1,4 @@ -use crate::ffi::{ffi_getter, ffi_stringkey_getter, BorrowedPtr, ExternPointer, OwnedPtr}; +use crate::ffi::{ffi_arc_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{Form, Species}; use crate::StringKey; use hashbrown::HashSet; @@ -13,10 +13,10 @@ unsafe extern "C" fn species_new( gender_rate: f32, growth_rate: BorrowedPtr, capture_rate: u8, - default_form: OwnedPtr, + default_form: OwnedPtr>, flags: *const *const c_char, flags_length: usize, -) -> OwnedPtr { +) -> IdentifiablePointer> { let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let growth_rate: StringKey = CStr::from_ptr(growth_rate).to_str().unwrap().into(); @@ -25,44 +25,48 @@ unsafe extern "C" fn species_new( for flag in flags { flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into()); } - Box::into_raw(Box::new(Species::new( + Arc::new(Species::new( id, &name, gender_rate, &growth_rate, capture_rate, - *Box::from_raw(default_form), + default_form.as_ref().unwrap().clone(), flags_set, - ))) + )) + .into() } #[no_mangle] -unsafe extern "C" fn species_drop(ptr: OwnedPtr) { +unsafe extern "C" fn species_drop(ptr: OwnedPtr>) { drop_in_place(ptr); } -ffi_getter!(Species, id, u16); -ffi_stringkey_getter!(Species, name); -ffi_getter!(Species, gender_rate, f32); -ffi_stringkey_getter!(Species, growth_rate); -ffi_getter!(Species, capture_rate, u8); +ffi_arc_getter!(Species, id, u16); +ffi_arc_stringkey_getter!(Species, name); +ffi_arc_getter!(Species, gender_rate, f32); +ffi_arc_stringkey_getter!(Species, growth_rate); +ffi_arc_getter!(Species, capture_rate, u8); #[no_mangle] unsafe extern "C" fn species_add_form( - species: ExternPointer, + species: ExternPointer>, name: BorrowedPtr, - form: OwnedPtr, + form: OwnedPtr>, ) { - let form = *Box::from_raw(form); + let form = form.as_ref().unwrap().clone(); species.as_mut().add_form(CStr::from_ptr(name).into(), form) } #[no_mangle] -unsafe extern "C" fn species_get_form(species: ExternPointer, name: BorrowedPtr) -> BorrowedPtr { +unsafe extern "C" fn species_get_form( + species: ExternPointer>, + name: BorrowedPtr, +) -> IdentifiablePointer> { let form = species.as_ref().get_form(&CStr::from_ptr(name).into()); if let Some(form) = form { - Arc::as_ptr(form) + form.into() } else { - std::ptr::null() + IdentifiablePointer::none() } } diff --git a/src/ffi/static_data/statistic_set.rs b/src/ffi/static_data/statistic_set.rs index 90cb867..92f4e02 100644 --- a/src/ffi/static_data/statistic_set.rs +++ b/src/ffi/static_data/statistic_set.rs @@ -1,4 +1,4 @@ -use crate::ffi::{ExternPointer, OwnedPtr}; +use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::{StaticStatisticSet, Statistic, StatisticSet}; use std::ptr::drop_in_place; @@ -14,15 +14,15 @@ extern "C" fn []( special_attack: $num_type, special_defense: $num_type, speed: $num_type, -) -> OwnedPtr> { - Box::into_raw(Box::new(StatisticSet::new( +) -> IdentifiablePointer> { + Box::new(StatisticSet::new( hp, attack, defense, special_attack, special_defense, speed, - ))) + )).into() } #[no_mangle] @@ -73,15 +73,15 @@ extern "C" fn []( special_attack: $num_type, special_defense: $num_type, speed: $num_type, -) -> OwnedPtr> { - Box::into_raw(Box::new(StaticStatisticSet::new( +) -> IdentifiablePointer> { + Box::new(StaticStatisticSet::new( hp, attack, defense, special_attack, special_defense, speed, - ))) + )).into() } #[no_mangle] diff --git a/src/script_implementations/wasm/export_registry/mod.rs b/src/script_implementations/wasm/export_registry/mod.rs index eae7ac9..0e4c1e2 100755 --- a/src/script_implementations/wasm/export_registry/mod.rs +++ b/src/script_implementations/wasm/export_registry/mod.rs @@ -138,10 +138,10 @@ fn string_key_get_str(env: FunctionEnvMut, string_key: ExternRef fn effect_parameter_get_type(env: FunctionEnvMut, parameter: ExternRef) -> u8 { let v = parameter.value_func(&env).unwrap(); match v { - EffectParameter::Bool(_) => 1, - EffectParameter::Int(_) => 2, - EffectParameter::Float(_) => 3, - EffectParameter::String(_) => 4, + EffectParameter::Bool(_, _) => 1, + EffectParameter::Int(_, _) => 2, + EffectParameter::Float(_, _) => 3, + EffectParameter::String(_, _) => 4, } } @@ -149,7 +149,7 @@ fn effect_parameter_get_type(env: FunctionEnvMut, parameter: Ext fn effect_parameter_as_bool(env: FunctionEnvMut, parameter: ExternRef) -> u8 { let v = parameter.value_func(&env).unwrap(); match v { - EffectParameter::Bool(b) => { + EffectParameter::Bool(_, b) => { if *b { 1 } else { @@ -164,7 +164,7 @@ fn effect_parameter_as_bool(env: FunctionEnvMut, parameter: Exte fn effect_parameter_as_int(env: FunctionEnvMut, parameter: ExternRef) -> i64 { let v = parameter.value_func(&env).unwrap(); match v { - EffectParameter::Int(i) => *i, + EffectParameter::Int(_, i) => *i, _ => panic!("Unexpected parameter type!"), } } @@ -173,7 +173,7 @@ fn effect_parameter_as_int(env: FunctionEnvMut, parameter: Exter fn effect_parameter_as_float(env: FunctionEnvMut, parameter: ExternRef) -> f32 { let v = parameter.value_func(&env).unwrap(); match v { - EffectParameter::Float(f) => *f, + EffectParameter::Float(_, f) => *f, _ => panic!("Unexpected parameter type!"), } } @@ -185,7 +185,7 @@ fn effect_parameter_as_string( ) -> ExternRef { let v = parameter.value_func(&env).unwrap(); match v { - EffectParameter::String(s) => ExternRef::func_new(&env, s), + EffectParameter::String(_, s) => ExternRef::func_new(&env, s), _ => panic!("Unexpected parameter type!"), } } diff --git a/src/static_data/items.rs b/src/static_data/items.rs index 4bb60e6..8c1671b 100755 --- a/src/static_data/items.rs +++ b/src/static_data/items.rs @@ -2,7 +2,7 @@ use hashbrown::HashSet; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// An item category defines which bag slot items are stored in. #[derive(Debug, Copy, Clone)] @@ -48,6 +48,8 @@ pub enum BattleItemCategory { #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct Item { + /// 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. @@ -70,6 +72,7 @@ impl Item { flags: HashSet, ) -> Item { Item { + identifier: Default::default(), name: name.clone(), category, battle_category, @@ -104,3 +107,9 @@ impl Item { self.flags.contains(key) } } + +impl ValueIdentifiable for Item { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/static_data/libraries/ability_library.rs b/src/static_data/libraries/ability_library.rs index 5a57823..bca6768 100755 --- a/src/static_data/libraries/ability_library.rs +++ b/src/static_data/libraries/ability_library.rs @@ -4,11 +4,13 @@ use indexmap::IndexMap; use crate::static_data::Ability; use crate::static_data::DataLibrary; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A storage for all abilities that can be used in this data library. #[derive(Debug)] pub struct AbilityLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The underlying map for the library. map: IndexMap>, } @@ -17,6 +19,7 @@ impl AbilityLibrary { /// Instantiates a new ability library. pub fn new(capacity: usize) -> AbilityLibrary { AbilityLibrary { + identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -31,18 +34,25 @@ impl DataLibrary<'_, Ability> for AbilityLibrary { } } +impl ValueIdentifiable for AbilityLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod tests { use crate::static_data::Ability; use crate::static_data::AbilityLibrary; use crate::static_data::DataLibrary; use crate::StringKey; + use std::sync::Arc; pub fn build() -> AbilityLibrary { let mut lib = AbilityLibrary::new(1); lib.add( &StringKey::new("test_ability".into()), - Ability::new(&"test_ability".into(), &"test_ability".into(), Vec::new()), + Arc::new(Ability::new(&"test_ability".into(), &"test_ability".into(), Vec::new())), ); // Drops borrow as mut diff --git a/src/static_data/libraries/data_library.rs b/src/static_data/libraries/data_library.rs index 9aab330..45158a5 100755 --- a/src/static_data/libraries/data_library.rs +++ b/src/static_data/libraries/data_library.rs @@ -14,8 +14,8 @@ pub trait DataLibrary<'a, T: 'a> { fn get_modify(&mut self) -> &mut IndexMap>; /// Adds a new value to the library. - fn add(&mut self, key: &StringKey, value: T) { - self.get_modify().insert(key.clone(), Arc::new(value)); + fn add(&mut self, key: &StringKey, value: Arc) { + self.get_modify().insert(key.clone(), value); } /// Removes 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 1630381..4ac29a1 100755 --- a/src/static_data/libraries/growth_rate_library.rs +++ b/src/static_data/libraries/growth_rate_library.rs @@ -5,10 +5,12 @@ use hashbrown::HashMap; use crate::defines::LevelInt; use crate::static_data::GrowthRate; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A library to store all growth rates. pub struct GrowthRateLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The underlying data structure. growth_rates: HashMap>, } @@ -17,6 +19,7 @@ impl GrowthRateLibrary { /// Instantiates a new growth rate library with a capacity. pub fn new(capacity: usize) -> GrowthRateLibrary { GrowthRateLibrary { + identifier: Default::default(), growth_rates: HashMap::with_capacity(capacity), } } @@ -36,6 +39,12 @@ impl GrowthRateLibrary { } } +impl ValueIdentifiable for GrowthRateLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + impl Debug for GrowthRateLibrary { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("GrowthRateLibrary").finish() diff --git a/src/static_data/libraries/item_library.rs b/src/static_data/libraries/item_library.rs index 14daa98..cd9b943 100755 --- a/src/static_data/libraries/item_library.rs +++ b/src/static_data/libraries/item_library.rs @@ -4,12 +4,14 @@ use indexmap::IndexMap; use crate::static_data::DataLibrary; use crate::static_data::Item; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A library to store all items. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct ItemLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The underlying data structure. map: IndexMap>, } @@ -18,6 +20,7 @@ impl ItemLibrary { /// Instantiates a new Item Library. pub fn new(capacity: usize) -> ItemLibrary { ItemLibrary { + identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -33,9 +36,16 @@ impl DataLibrary<'_, Item> for ItemLibrary { } } +impl ValueIdentifiable for ItemLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod tests { use hashbrown::HashSet; + use std::sync::Arc; use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::item_library::ItemLibrary; @@ -57,7 +67,7 @@ pub mod tests { let m = build_item(); // Borrow as mut so we can insert let w = &mut lib; - w.add(&"foo".into(), m); + w.add(&"foo".into(), Arc::new(m)); // Drops borrow as mut lib diff --git a/src/static_data/libraries/library_settings.rs b/src/static_data/libraries/library_settings.rs index ade746b..8745e06 100755 --- a/src/static_data/libraries/library_settings.rs +++ b/src/static_data/libraries/library_settings.rs @@ -1,9 +1,12 @@ use crate::defines::LevelInt; +use crate::{ValueIdentifiable, ValueIdentifier}; /// This library holds several misc settings for the library. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct LibrarySettings { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The highest level a Pokemon can be. maximum_level: LevelInt, } @@ -11,7 +14,10 @@ pub struct LibrarySettings { impl LibrarySettings { /// Creates a new settings library. pub fn new(maximum_level: LevelInt) -> Self { - Self { maximum_level } + Self { + identifier: Default::default(), + maximum_level, + } } /// The highest level a Pokemon can be. @@ -19,3 +25,9 @@ impl LibrarySettings { self.maximum_level } } + +impl ValueIdentifiable for LibrarySettings { + 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 9e943b4..15b3aba 100755 --- a/src/static_data/libraries/move_library.rs +++ b/src/static_data/libraries/move_library.rs @@ -4,12 +4,14 @@ use indexmap::IndexMap; use crate::static_data::DataLibrary; use crate::static_data::MoveData; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A library to store all data for moves. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct MoveLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The underlying map. map: IndexMap>, } @@ -18,6 +20,7 @@ impl MoveLibrary { /// Instantiates a new Move Library. pub fn new(capacity: usize) -> MoveLibrary { MoveLibrary { + identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -32,9 +35,16 @@ impl DataLibrary<'_, MoveData> for MoveLibrary { } } +impl ValueIdentifiable for MoveLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod tests { use hashbrown::HashSet; + use std::sync::Arc; use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::move_library::MoveLibrary; @@ -61,7 +71,7 @@ pub mod tests { let m = build_move(); // Borrow as mut so we can insert let w = &mut lib; - w.add(&StringKey::new("foo".into()), m); + w.add(&StringKey::new("foo".into()), Arc::new(m)); // Drops borrow as mut lib diff --git a/src/static_data/libraries/nature_library.rs b/src/static_data/libraries/nature_library.rs index 9244eee..8b6b5bf 100644 --- a/src/static_data/libraries/nature_library.rs +++ b/src/static_data/libraries/nature_library.rs @@ -1,11 +1,13 @@ use crate::static_data::Nature; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use hashbrown::HashMap; use std::sync::Arc; /// A library of all natures that can be used, stored by their names. #[derive(Debug)] pub struct NatureLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The underlying data structure. map: HashMap>, } @@ -14,13 +16,14 @@ impl NatureLibrary { /// Creates a new nature library with a given capacity. pub fn new(capacity: usize) -> Self { NatureLibrary { + identifier: Default::default(), map: HashMap::with_capacity(capacity), } } /// Adds a new nature with name to the library. - pub fn load_nature(&mut self, name: StringKey, nature: Nature) { - self.map.insert(name, Arc::new(nature)); + pub fn load_nature(&mut self, name: StringKey, nature: Arc) { + self.map.insert(name, nature); } /// Gets a nature by name. @@ -29,11 +32,11 @@ impl NatureLibrary { } /// Finds a nature name by nature. - pub fn get_nature_name(&self, nature: &Arc) -> StringKey { + pub fn get_nature_name(&self, nature: &Nature) -> StringKey { for kv in &self.map { // As natures can't be copied, and should always be the same reference as the value // in the map, we just compare by reference. - if Arc::ptr_eq(kv.1, nature) { + if std::ptr::eq(Arc::as_ptr(kv.1), nature) { return kv.0.clone(); } } @@ -41,6 +44,12 @@ impl NatureLibrary { } } +impl ValueIdentifiable for NatureLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod tests { use crate::static_data::statistics::Statistic; diff --git a/src/static_data/libraries/species_library.rs b/src/static_data/libraries/species_library.rs index e1e31a1..1dfb0fc 100755 --- a/src/static_data/libraries/species_library.rs +++ b/src/static_data/libraries/species_library.rs @@ -4,12 +4,14 @@ use indexmap::IndexMap; use crate::static_data::DataLibrary; use crate::static_data::Species; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A library to store all data for Pokemon species. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct SpeciesLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The underlying map. map: IndexMap>, } @@ -18,6 +20,7 @@ impl SpeciesLibrary { /// Instantiates a new Species Library. pub fn new(capacity: usize) -> SpeciesLibrary { SpeciesLibrary { + identifier: Default::default(), map: IndexMap::with_capacity(capacity), } } @@ -32,9 +35,16 @@ impl<'a> DataLibrary<'a, Species> for SpeciesLibrary { } } +impl ValueIdentifiable for SpeciesLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod tests { use hashbrown::HashSet; + use std::sync::Arc; use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::species_library::SpeciesLibrary; @@ -50,7 +60,7 @@ pub mod tests { 0.5, &"test_growthrate".into(), 0, - Form::new( + Arc::new(Form::new( &"default".into(), 0.0, 0.0, @@ -61,7 +71,7 @@ pub mod tests { Vec::new(), LearnableMoves::new(), HashSet::new(), - ), + )), HashSet::new(), ) } @@ -71,7 +81,7 @@ pub mod tests { let species = build_species(); // Borrow as mut so we can insert let w = &mut lib; - w.add(&"foo".into(), species); + w.add(&"foo".into(), Arc::new(species)); // Drops borrow as mut lib diff --git a/src/static_data/libraries/static_data.rs b/src/static_data/libraries/static_data.rs index 9259008..51cf3a6 100755 --- a/src/static_data/libraries/static_data.rs +++ b/src/static_data/libraries/static_data.rs @@ -6,11 +6,14 @@ use crate::static_data::MoveLibrary; use crate::static_data::NatureLibrary; use crate::static_data::SpeciesLibrary; use crate::static_data::TypeLibrary; +use crate::{ValueIdentifiable, ValueIdentifier}; /// The storage for all different libraries. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct StaticData { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// Several misc settings for the library. settings: LibrarySettings, /// All data for Pokemon species. @@ -33,6 +36,7 @@ impl StaticData { /// Instantiates a new data collection. pub fn new(settings: LibrarySettings) -> Self { Self { + identifier: Default::default(), settings, species: SpeciesLibrary::new(0), moves: MoveLibrary::new(0), @@ -106,6 +110,12 @@ impl StaticData { } } +impl ValueIdentifiable for StaticData { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod test { use crate::static_data::libraries::library_settings::LibrarySettings; @@ -116,6 +126,7 @@ pub mod test { pub fn build() -> StaticData { StaticData { + identifier: Default::default(), settings: LibrarySettings::new(100), species: species_library::tests::build(), moves: move_library::tests::build(), diff --git a/src/static_data/libraries/type_library.rs b/src/static_data/libraries/type_library.rs index b0d4af8..d2b95f5 100755 --- a/src/static_data/libraries/type_library.rs +++ b/src/static_data/libraries/type_library.rs @@ -1,7 +1,7 @@ use atomig::Atom; use hashbrown::HashMap; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A unique key that can be used to store a reference to a type. Opaque reference to a byte /// internally. @@ -28,6 +28,8 @@ impl From for u8 { #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct TypeLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// A list of types types: HashMap, /// The effectiveness of the different types against each other. @@ -38,6 +40,7 @@ impl TypeLibrary { /// Instantiates a new type library with a specific capacity. pub fn new(capacity: usize) -> TypeLibrary { TypeLibrary { + identifier: Default::default(), types: HashMap::with_capacity(capacity), effectiveness: vec![], } @@ -93,6 +96,12 @@ impl TypeLibrary { } } +impl ValueIdentifiable for TypeLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod tests { use assert_approx_eq::assert_approx_eq; diff --git a/src/static_data/mod.rs b/src/static_data/mod.rs index aa58926..0c23e8b 100755 --- a/src/static_data/mod.rs +++ b/src/static_data/mod.rs @@ -1,4 +1,4 @@ -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; #[doc(inline)] pub use growth_rates::*; #[doc(inline)] @@ -40,22 +40,57 @@ mod statistics; #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub enum EffectParameter { /// A boolean value. - Bool(bool), + Bool(ValueIdentifier, bool), /// An integer value. Stored as a 64 bit int to deal with potentially large numbers. - Int(i64), + Int(ValueIdentifier, i64), /// A float value. Stored as a 32 bit float. - Float(f32), + Float(ValueIdentifier, f32), /// A string value. - String(StringKey), + String(ValueIdentifier, StringKey), +} + +impl Into for bool { + fn into(self) -> EffectParameter { + EffectParameter::Bool(Default::default(), self) + } +} + +impl Into for i64 { + fn into(self) -> EffectParameter { + EffectParameter::Int(Default::default(), self) + } +} + +impl Into for f32 { + fn into(self) -> EffectParameter { + EffectParameter::Float(Default::default(), self) + } +} + +impl Into for StringKey { + fn into(self) -> EffectParameter { + EffectParameter::String(Default::default(), self) + } } 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)), + 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, } } } diff --git a/src/static_data/moves/move_data.rs b/src/static_data/moves/move_data.rs index 03feb52..9ffa746 100755 --- a/src/static_data/moves/move_data.rs +++ b/src/static_data/moves/move_data.rs @@ -3,7 +3,7 @@ use hashbrown::HashSet; use serde::{Deserialize, Serialize}; use crate::static_data::{SecondaryEffect, TypeIdentifier}; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// The move category defines what global kind of move this move is. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -63,6 +63,8 @@ pub enum MoveTarget { #[derive(PartialEq, Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct MoveData { + /// 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. @@ -101,6 +103,7 @@ impl MoveData { flags: HashSet, ) -> MoveData { MoveData { + identifier: Default::default(), name: name.clone(), move_type, category, @@ -163,3 +166,9 @@ impl MoveData { self.flags.contains::(&key_hash) } } + +impl ValueIdentifiable for MoveData { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/static_data/moves/secondary_effect.rs b/src/static_data/moves/secondary_effect.rs index 72c1f77..d4ab9bd 100755 --- a/src/static_data/moves/secondary_effect.rs +++ b/src/static_data/moves/secondary_effect.rs @@ -1,9 +1,11 @@ use crate::static_data::EffectParameter; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// A secondary effect is an effect on a move that happens after it hits. #[derive(PartialEq, Debug)] pub struct SecondaryEffect { + /// 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. @@ -16,6 +18,7 @@ impl SecondaryEffect { /// Instantiates a new Secondary Effect. pub fn new(chance: f32, effect_name: StringKey, parameters: Vec) -> SecondaryEffect { SecondaryEffect { + identifier: Default::default(), chance, effect_name, parameters, @@ -36,6 +39,12 @@ impl SecondaryEffect { } } +impl ValueIdentifiable for SecondaryEffect { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] mod tests { use assert_approx_eq::assert_approx_eq; diff --git a/src/static_data/natures.rs b/src/static_data/natures.rs index ed31573..c4b9180 100755 --- a/src/static_data/natures.rs +++ b/src/static_data/natures.rs @@ -1,9 +1,13 @@ use crate::static_data::Statistic; +use crate::{ValueIdentifiable, ValueIdentifier}; +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. #[derive(Debug)] pub struct Nature { + /// 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. @@ -21,13 +25,14 @@ impl Nature { decrease_stat: Statistic, increase_modifier: f32, decrease_modifier: f32, - ) -> Self { - Self { + ) -> Arc { + Arc::new(Self { + identifier: Default::default(), increase_stat, decrease_stat, increase_modifier, decrease_modifier, - } + }) } /// The stat that should receive the increased modifier. @@ -52,3 +57,9 @@ impl Nature { } } } + +impl ValueIdentifiable for Nature { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/static_data/species_data/ability.rs b/src/static_data/species_data/ability.rs index 5110427..3318a51 100755 --- a/src/static_data/species_data/ability.rs +++ b/src/static_data/species_data/ability.rs @@ -1,9 +1,11 @@ use crate::static_data::EffectParameter; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// An ability is a passive effect in battle that is attached to a Pokemon. #[derive(Debug)] pub struct Ability { + /// 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. @@ -16,6 +18,7 @@ impl Ability { /// 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, @@ -36,6 +39,12 @@ impl Ability { } } +impl ValueIdentifiable for Ability { + 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)] diff --git a/src/static_data/species_data/form.rs b/src/static_data/species_data/form.rs index 5949512..c98377a 100755 --- a/src/static_data/species_data/form.rs +++ b/src/static_data/species_data/form.rs @@ -4,13 +4,15 @@ 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; use crate::StringKey; +use crate::{Random, ValueIdentifiable, ValueIdentifier}; /// A form is a variant of a specific species. A species always has at least one form, but can have /// many more. #[derive(Debug)] pub struct Form { + /// 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. @@ -48,6 +50,7 @@ impl Form { flags: HashSet, ) -> Form { Form { + identifier: Default::default(), name: name.clone(), height, weight, @@ -156,3 +159,9 @@ impl Form { self.flags.contains(key) } } + +impl ValueIdentifiable for Form { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/static_data/species_data/species.rs b/src/static_data/species_data/species.rs index 1885b56..8e5f99e 100755 --- a/src/static_data/species_data/species.rs +++ b/src/static_data/species_data/species.rs @@ -1,16 +1,20 @@ use std::sync::{Arc, LazyLock}; use hashbrown::{HashMap, HashSet}; +use parking_lot::lock_api::RwLockReadGuard; +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. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct Species { + /// 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. @@ -23,7 +27,7 @@ pub struct Species { /// uncatchable. capture_rate: u8, /// The forms that belong to this Pokemon. - forms: HashMap>, + forms: RwLock>>, /// The arbitrary flags that can be set on a Pokemon for script use. flags: HashSet, } @@ -44,18 +48,19 @@ impl Species { gender_rate: f32, growth_rate: &StringKey, capture_rate: u8, - default_form: Form, + default_form: Arc, flags: HashSet, ) -> Species { let mut forms = HashMap::with_capacity(1); - forms.insert_unique_unchecked(get_default_key(), Arc::new(default_form)); + forms.insert_unique_unchecked(get_default_key(), default_form); Species { + identifier: Default::default(), id, name: name.clone(), gender_rate, growth_rate: growth_rate.clone(), capture_rate, - forms, + forms: RwLock::new(forms), flags, } } @@ -82,8 +87,8 @@ impl Species { self.capture_rate } /// The forms that belong to this Pokemon. - pub fn forms(&self) -> &HashMap> { - &self.forms + pub fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap>> { + self.forms.read() } /// The arbitrary flags that can be set on a Pokemon for script use. pub fn flags(&self) -> &HashSet { @@ -91,18 +96,18 @@ impl Species { } /// Adds a new form to the species. - pub fn add_form(&mut self, id: StringKey, form: Form) { - self.forms.insert(id, Arc::new(form)); + pub fn add_form(&self, id: StringKey, form: Arc) { + self.forms.write().insert(id, form); } /// Gets a form by name. - pub fn get_form(&self, id: &StringKey) -> Option<&Arc> { - self.forms.get(id) + pub fn get_form(&self, id: &StringKey) -> Option> { + self.forms.read().get(id).cloned() } /// Gets the form the Pokemon will have by default, if no other form is specified. - pub fn get_default_form(&self) -> &Arc { - self.forms.get(&get_default_key()).unwrap() + pub fn get_default_form(&self) -> Arc { + self.forms.read().get(&get_default_key()).unwrap().clone() } /// Gets a random gender. @@ -121,3 +126,9 @@ impl Species { self.flags.contains(key) } } + +impl ValueIdentifiable for Species { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/static_data/statistic_set.rs b/src/static_data/statistic_set.rs index 522f60e..36b1c91 100755 --- a/src/static_data/statistic_set.rs +++ b/src/static_data/statistic_set.rs @@ -1,5 +1,6 @@ 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,6 +21,8 @@ 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. @@ -45,6 +48,7 @@ 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), @@ -128,6 +132,19 @@ 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. @@ -136,6 +153,8 @@ 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. @@ -155,8 +174,9 @@ where T: PrimInt, { /// Create a new static statistic set. - pub const fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { + 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, @@ -204,6 +224,15 @@ 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)] @@ -218,6 +247,8 @@ 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. @@ -264,6 +295,7 @@ 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), @@ -377,6 +409,21 @@ 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 4d9f5d3..ec89cf6 100755 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,9 +2,12 @@ pub use random::Random; #[doc(inline)] pub use string_key::StringKey; +#[doc(inline)] +pub use value_identifier::*; /// The random module defines a RNG implementation used in pkmn_lib mod random; /// The string_key module defines a custom string handling for reduced allocations and fast lookups /// and equality checks. mod string_key; +mod value_identifier; diff --git a/src/utils/value_identifier.rs b/src/utils/value_identifier.rs new file mode 100644 index 0000000..f4efd75 --- /dev/null +++ b/src/utils/value_identifier.rs @@ -0,0 +1,22 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +static CURRENT: AtomicUsize = AtomicUsize::new(1); + +/// An extremely basic way to identify a piece of data. +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +#[repr(C)] +pub struct ValueIdentifier(usize); + +impl Default for ValueIdentifier { + fn default() -> Self { + Self { + 0: CURRENT.fetch_add(1, Ordering::SeqCst), + } + } +} + +/// 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 b4de2c6..0f1e8b0 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use std::fmt::Debug; use std::fs::File; use std::io::{BufReader, Read}; +use std::sync::Arc; use hashbrown::HashSet; use num_traits::PrimInt; @@ -116,7 +117,10 @@ pub fn load_items(path: &String, lib: &mut ItemLibrary) { } } - lib.add(&name, Item::new(&name, category, battle_category, price as i32, flags)); + lib.add( + &name, + Arc::new(Item::new(&name, category, battle_category, price as i32, flags)), + ); } } @@ -159,7 +163,7 @@ pub fn load_abilities(path: &String, ability_library: &mut AbilityLibrary) { } } - ability_library.add(&name, Ability::new(&name, &effect, parameters)); + ability_library.add(&name, Arc::new(Ability::new(&name, &effect, parameters))); } } @@ -212,7 +216,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { lib.moves_mut().add( &move_name, - MoveData::new( + Arc::new(MoveData::new( &move_name.clone(), move_type_id, move_category, @@ -223,7 +227,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { priority, secondary_effect, flags, - ), + )), ); } } @@ -269,7 +273,7 @@ pub fn load_species(path: &String, library: &mut StaticData) { default_form, Default::default(), ); - library.species_mut().add(&name, species); + library.species_mut().add(&name, Arc::new(species)); } } @@ -282,7 +286,7 @@ fn load_wasm(path: &String, library: &mut WebAssemblyScriptResolver) { library.finalize(); } -fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Form { +fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Arc { let mut abilities = Vec::new(); for a in value.get("abilities").unwrap().as_array().unwrap() { abilities.push(StringKey::new(a.as_str().unwrap().into())); @@ -312,7 +316,7 @@ fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Form let moves = parse_moves(&value.get("moves").unwrap(), library.moves()); - Form::new( + Arc::new(Form::new( &name, height as f32, weight as f32, @@ -323,7 +327,7 @@ fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Form hidden_abilities, moves, Default::default(), - ) + )) } fn parse_statistics(value: &Value) -> StaticStatisticSet @@ -389,15 +393,15 @@ fn parse_effect_parameter(value: &Value) -> EffectParameter { Value::Null => { panic!("Unexpected type") } - Value::Bool(b) => EffectParameter::Bool(*b), + Value::Bool(b) => (*b).into(), Value::Number(n) => { if n.is_f64() { - EffectParameter::Float(n.as_f64().unwrap() as f32) + (n.as_f64().unwrap() as f32).into() } else { - EffectParameter::Int(n.as_i64().unwrap()) + n.as_i64().unwrap().into() } } - Value::String(s) => EffectParameter::String(StringKey::new(s.as_str().into())), + Value::String(s) => StringKey::new(s.as_str().into()).into(), Value::Array(_) => { panic!("Unexpected type") }