A bunch more work on replacing every potential panic with results
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -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};
|
||||
use crate::{script_hook, PkmnError, ValueIdentifiable, ValueIdentifier, VecExt};
|
||||
use anyhow::Result;
|
||||
use anyhow_ext::anyhow;
|
||||
use parking_lot::lock_api::MappedRwLockReadGuard;
|
||||
@@ -81,9 +81,7 @@ impl ChoiceQueue {
|
||||
let len = self.queue.read().len();
|
||||
let mut write_lock = self.queue.write();
|
||||
for index in self.current..len {
|
||||
let choice = &mut write_lock
|
||||
.get_mut(index)
|
||||
.ok_or(PkmnError::IndexOutOfBounds { index, len })?;
|
||||
let choice = &mut write_lock.get_mut_res(index)?;
|
||||
if let Some(choice) = choice {
|
||||
let mut speed = choice.user().boosted_stats().speed();
|
||||
script_hook!(change_speed, (*choice), choice, &mut speed);
|
||||
@@ -121,14 +119,9 @@ impl ChoiceQueue {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let len = queue_lock.len();
|
||||
// Take the choice we want to move forward out of it's place.
|
||||
let choice = queue_lock
|
||||
.get_mut(desired_index)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: self.current,
|
||||
len,
|
||||
})?
|
||||
.get_mut_res(desired_index)?
|
||||
.take()
|
||||
.ok_or(anyhow!("Choice was already taken"))?;
|
||||
// Iterate backwards from the spot before the choice we want to move up, push them all back
|
||||
@@ -136,15 +129,8 @@ impl ChoiceQueue {
|
||||
for index in (self.current..desired_index).rev() {
|
||||
queue_lock.swap(index, index + 1);
|
||||
}
|
||||
let len = queue_lock.len();
|
||||
// Place the choice that needs to be next in the next to be executed position.
|
||||
let _ = queue_lock
|
||||
.get_mut(self.current)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: self.current,
|
||||
len,
|
||||
})?
|
||||
.insert(choice);
|
||||
let _ = queue_lock.get_mut_res(self.current)?.insert(choice);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
@@ -173,13 +159,13 @@ impl ValueIdentifiable for ChoiceQueue {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::defines::LevelInt;
|
||||
use crate::dynamic_data::{DynamicLibrary, PassChoice};
|
||||
use crate::static_data::{AbilityIndex, Gender};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn create_empty_queue() {
|
||||
let queue = ChoiceQueue::new(Vec::new());
|
||||
|
||||
@@ -7,9 +7,9 @@ use num_traits::abs;
|
||||
use crate::dynamic_data::Battle;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use crate::static_data::MoveTarget;
|
||||
use crate::PkmnError;
|
||||
use crate::VecExt;
|
||||
|
||||
/// Helper type for the vector of targets we will return.
|
||||
/// Helper type for the vector of targ ets we will return.
|
||||
pub type TargetList = Vec<Option<Arc<Pokemon>>>;
|
||||
|
||||
/// This returns all Pokemon in the battle.
|
||||
@@ -127,16 +127,7 @@ pub fn resolve_targets(side: u8, index: u8, target: MoveTarget, battle: &Battle)
|
||||
// the client deal with what side is passed.
|
||||
MoveTarget::AllAlly | MoveTarget::AllOpponent => {
|
||||
let mut v = Vec::new();
|
||||
for pokemon in battle
|
||||
.sides()
|
||||
.get(side as usize)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: side as usize,
|
||||
len: battle.sides().len(),
|
||||
})?
|
||||
.pokemon()
|
||||
.deref()
|
||||
{
|
||||
for pokemon in battle.sides().get_res(side as usize)?.pokemon().deref() {
|
||||
v.push(pokemon.as_ref().cloned());
|
||||
}
|
||||
v
|
||||
|
||||
@@ -20,7 +20,7 @@ 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};
|
||||
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
|
||||
|
||||
/// A pokemon battle, with any amount of sides and pokemon per side.
|
||||
#[derive(Debug)]
|
||||
@@ -271,13 +271,7 @@ impl Battle {
|
||||
let side = choice.user().get_battle_side_index();
|
||||
match side {
|
||||
Some(side) => {
|
||||
self.sides
|
||||
.get(side as usize)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: side as usize,
|
||||
len: self.sides.len(),
|
||||
})?
|
||||
.set_choice(choice)?;
|
||||
self.sides.get_res(side as usize)?.set_choice(choice)?;
|
||||
self.check_choices_set_and_run()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use anyhow::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
@@ -19,12 +20,12 @@ pub struct BattleParty {
|
||||
impl BattleParty {
|
||||
/// Initializes a battle party with the underlying party, and the indices the party is responsible
|
||||
/// for.
|
||||
pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Self {
|
||||
Self {
|
||||
pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identifier: Default::default(),
|
||||
party,
|
||||
responsible_indices,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks whether the party is responsible for the given index.
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
|
||||
use crate::dynamic_data::Script;
|
||||
use crate::dynamic_data::ScriptSet;
|
||||
use crate::dynamic_data::VolatileScriptsOwner;
|
||||
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier};
|
||||
use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
|
||||
|
||||
/// A side on a battle.
|
||||
#[derive(Debug)]
|
||||
@@ -149,12 +149,7 @@ impl BattleSide {
|
||||
for (index, pokemon_slot) in self.pokemon.read().iter().enumerate() {
|
||||
if let Some(pokemon) = pokemon_slot {
|
||||
if std::ptr::eq(pokemon.deref(), choice.user().deref()) {
|
||||
let len = self.choices.read().len();
|
||||
self.choices
|
||||
.write()
|
||||
.get_mut(index)
|
||||
.ok_or(PkmnError::IndexOutOfBounds { index, len })?
|
||||
.replace(choice);
|
||||
self.choices.write().get_mut_res(index)?.replace(choice);
|
||||
self.choices_set.fetch_add(1, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
}
|
||||
@@ -180,10 +175,7 @@ impl BattleSide {
|
||||
pub fn set_pokemon(&self, index: u8, pokemon: Option<Arc<Pokemon>>) -> Result<()> {
|
||||
{
|
||||
let mut write_lock = self.pokemon.write();
|
||||
let old = write_lock.get_mut(index as usize).ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: index as usize,
|
||||
len: self.pokemon_per_side as usize,
|
||||
})?;
|
||||
let old = write_lock.get_mut_res(index as usize)?;
|
||||
let old = match pokemon {
|
||||
Some(pokemon) => old.replace(pokemon),
|
||||
None => old.take(),
|
||||
@@ -193,23 +185,17 @@ impl BattleSide {
|
||||
// side again.
|
||||
drop(write_lock);
|
||||
script_hook!(on_remove, old_pokemon,);
|
||||
old_pokemon.set_on_battlefield(false);
|
||||
old_pokemon.set_on_battlefield(false)?;
|
||||
}
|
||||
}
|
||||
|
||||
let pokemon = {
|
||||
let read_lock = self.pokemon.read();
|
||||
&read_lock
|
||||
.get(index as usize)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: index as usize,
|
||||
len: read_lock.len(),
|
||||
})?
|
||||
.clone()
|
||||
&read_lock.get_res(index as usize)?.clone()
|
||||
};
|
||||
if let Some(pokemon) = pokemon {
|
||||
pokemon.set_battle_data(self.battle, self.index);
|
||||
pokemon.set_on_battlefield(true);
|
||||
pokemon.set_on_battlefield(true)?;
|
||||
pokemon.set_battle_index(index);
|
||||
|
||||
let battle = self.battle()?;
|
||||
@@ -252,11 +238,7 @@ impl BattleSide {
|
||||
/// If this happens, the slot can not be used again.
|
||||
pub(crate) fn mark_slot_as_unfillable(&self, index: u8) -> Result<()> {
|
||||
self.fillable_slots
|
||||
.get(index as usize)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: index as usize,
|
||||
len: self.fillable_slots.len(),
|
||||
})?
|
||||
.get_res(index as usize)?
|
||||
.store(false, Ordering::SeqCst);
|
||||
Ok(())
|
||||
}
|
||||
@@ -266,14 +248,7 @@ impl BattleSide {
|
||||
for (i, slot) in self.pokemon.read().iter().enumerate() {
|
||||
if let Some(p) = slot {
|
||||
if std::ptr::eq(p.deref().deref(), pokemon.deref()) {
|
||||
return Ok(self
|
||||
.fillable_slots
|
||||
.get(i)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: i,
|
||||
len: self.fillable_slots.len(),
|
||||
})?
|
||||
.load(Ordering::Relaxed));
|
||||
return Ok(self.fillable_slots.get_res(i)?.load(Ordering::Relaxed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ 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};
|
||||
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
|
||||
/// An individual Pokemon as we know and love them.
|
||||
@@ -595,16 +595,17 @@ impl Pokemon {
|
||||
}
|
||||
|
||||
/// Sets whether or not the Pokemon is on the battlefield.
|
||||
pub fn set_on_battlefield(&self, value: bool) {
|
||||
pub fn set_on_battlefield(&self, value: bool) -> Result<()> {
|
||||
let r = self.battle_data.read();
|
||||
if let Some(data) = &mut r.deref() {
|
||||
data.on_battle_field.store(value, Ordering::SeqCst);
|
||||
if !value {
|
||||
self.volatile.clear();
|
||||
self.volatile.clear()?;
|
||||
self.weight.store(self.form().weight(), Ordering::SeqCst);
|
||||
self.height.store(self.form().height(), Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the index of the slot of the side the Pokemon is on.
|
||||
@@ -676,11 +677,7 @@ impl Pokemon {
|
||||
if !battle.can_slot_be_filled(battle_data.battle_side_index(), battle_data.index()) {
|
||||
battle
|
||||
.sides()
|
||||
.get(battle_data.battle_side_index() as usize)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: battle_data.battle_side_index() as usize,
|
||||
len: battle.sides().len(),
|
||||
})?
|
||||
.get_res(battle_data.battle_side_index() as usize)?
|
||||
.mark_slot_as_unfillable(battle_data.index())?;
|
||||
}
|
||||
|
||||
@@ -721,9 +718,12 @@ impl Pokemon {
|
||||
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) -> Result<()> {
|
||||
let mut learned_moves = self.learned_moves().write();
|
||||
let move_pos = learned_moves.iter().position(|a| a.is_none());
|
||||
if move_pos.is_none() {
|
||||
bail!("No more moves with an empty space found.");
|
||||
}
|
||||
let move_pos = match move_pos {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
bail!("No more moves with an empty space found.");
|
||||
}
|
||||
};
|
||||
let move_data = self
|
||||
.library
|
||||
.static_data()
|
||||
@@ -732,7 +732,9 @@ impl Pokemon {
|
||||
.ok_or(PkmnError::InvalidMoveName {
|
||||
move_name: move_name.clone(),
|
||||
})?;
|
||||
learned_moves[move_pos.unwrap()] = Some(Arc::new(LearnedMove::new(move_data, learn_method)));
|
||||
learned_moves
|
||||
.get_mut_res(move_pos)?
|
||||
.replace(Arc::new(LearnedMove::new(move_data, learn_method)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -805,7 +807,10 @@ impl ScriptSource for Pokemon {
|
||||
let mut c = 3;
|
||||
if let Some(battle_data) = &self.battle_data.read().deref() {
|
||||
if let Some(battle) = battle_data.battle() {
|
||||
c += battle.sides()[battle_data.battle_side_index() as usize].get_script_count()?;
|
||||
c += battle
|
||||
.sides()
|
||||
.get_res(battle_data.battle_side_index() as usize)?
|
||||
.get_script_count()?;
|
||||
}
|
||||
}
|
||||
Ok(c)
|
||||
@@ -826,7 +831,10 @@ impl ScriptSource for Pokemon {
|
||||
self.get_own_scripts(scripts);
|
||||
if let Some(battle_data) = &self.battle_data.read().deref() {
|
||||
if let Some(battle) = battle_data.battle() {
|
||||
battle.sides()[battle_data.battle_side_index() as usize].collect_scripts(scripts)?;
|
||||
battle
|
||||
.sides()
|
||||
.get_res(battle_data.battle_side_index() as usize)?
|
||||
.collect_scripts(scripts)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -862,6 +870,7 @@ pub enum DamageSource {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
pub mod test {
|
||||
use crate::dynamic_data::libraries::test::MockDynamicLibrary;
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::dynamic_data::models::learned_move::MoveLearnMethod;
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::static_data::{AbilityIndex, Gender};
|
||||
use crate::{Random, StringKey};
|
||||
use crate::{PkmnError, Random, StringKey};
|
||||
use anyhow::Result;
|
||||
|
||||
/// This allows for the easy chain building of a Pokemon.
|
||||
@@ -47,7 +47,12 @@ impl PokemonBuilder {
|
||||
Random::default()
|
||||
};
|
||||
|
||||
let species = self.library.static_data().species().get(&self.species).unwrap();
|
||||
let species = self
|
||||
.library
|
||||
.static_data()
|
||||
.species()
|
||||
.get(&self.species)
|
||||
.ok_or(PkmnError::InvalidSpeciesName { species: self.species })?;
|
||||
let form = species.get_default_form();
|
||||
let p = Pokemon::new(
|
||||
self.library,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use parking_lot::lock_api::RwLockReadGuard;
|
||||
use parking_lot::{RawRwLock, RwLock};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use crate::{ValueIdentifiable, ValueIdentifier};
|
||||
use crate::{ValueIdentifiable, ValueIdentifier, VecExt};
|
||||
|
||||
/// A list of Pokemon belonging to a trainer.
|
||||
#[derive(Debug)]
|
||||
@@ -52,14 +53,17 @@ impl PokemonParty {
|
||||
}
|
||||
|
||||
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
|
||||
pub fn swap_into(&self, index: usize, pokemon: Option<Arc<Pokemon>>) -> Option<Arc<Pokemon>> {
|
||||
pub fn swap_into(&self, index: usize, pokemon: Option<Arc<Pokemon>>) -> Result<Option<Arc<Pokemon>>> {
|
||||
let mut party = self.pokemon.write();
|
||||
if index >= party.len() {
|
||||
return pokemon;
|
||||
return Ok(pokemon);
|
||||
}
|
||||
let old = party[index].as_ref().cloned();
|
||||
party[index] = pokemon;
|
||||
old
|
||||
let value = party.get_mut_res(index)?;
|
||||
let old = match pokemon {
|
||||
Some(p) => value.replace(p),
|
||||
None => value.take(),
|
||||
};
|
||||
Ok(old)
|
||||
}
|
||||
|
||||
/// Whether or not the party still has Pokemon that can be used in battle.
|
||||
@@ -83,18 +87,18 @@ impl PokemonParty {
|
||||
}
|
||||
|
||||
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
|
||||
pub fn pack_party(&self) {
|
||||
pub fn pack_party(&self) -> Result<()> {
|
||||
let mut first_empty = None;
|
||||
let mut i = 0;
|
||||
let mut party = self.pokemon.write();
|
||||
loop {
|
||||
if party[i].is_none() {
|
||||
if party.get_res(i)?.is_none() {
|
||||
if first_empty.is_none() {
|
||||
first_empty = Some(i)
|
||||
}
|
||||
} else if first_empty.is_some() {
|
||||
party.swap(first_empty.unwrap(), i);
|
||||
i = first_empty.unwrap();
|
||||
} else if let Some(f) = first_empty {
|
||||
party.swap(f, i);
|
||||
i = f;
|
||||
first_empty = None;
|
||||
}
|
||||
i += 1;
|
||||
@@ -102,6 +106,7 @@ impl PokemonParty {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the party contains a given pokemon.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use crate::VecExt;
|
||||
#[doc(inline)]
|
||||
pub use item_script::*;
|
||||
#[doc(inline)]
|
||||
@@ -27,7 +28,7 @@ mod volatile_scripts_owner;
|
||||
macro_rules! script_hook {
|
||||
($hook_name: ident, $source: expr, $($parameters: expr),*) => {
|
||||
let mut aggregator = $source.get_script_iterator()?;
|
||||
while let Some(script_container) = aggregator.get_next() {
|
||||
while let Some(script_container) = aggregator.get_next()? {
|
||||
let script = script_container.get();
|
||||
if let Some(script) = script {
|
||||
if let Some(script) = script.read().as_deref() {
|
||||
@@ -157,16 +158,16 @@ impl ScriptIterator {
|
||||
}
|
||||
|
||||
/// Move to the next valid value in the scripts.
|
||||
fn increment_to_next_value(&mut self) -> bool {
|
||||
fn increment_to_next_value(&mut self) -> Result<bool> {
|
||||
if self.index != -1 {
|
||||
let wrapper = unsafe { &(*self.scripts)[self.index as usize] };
|
||||
let wrapper = unsafe { &(*self.scripts).get_res(self.index as usize)? };
|
||||
if let ScriptWrapper::Set(set) = wrapper {
|
||||
if let Some(set) = set.upgrade() {
|
||||
self.set_index += 1;
|
||||
if self.set_index as usize >= set.count() {
|
||||
self.set_index = -1;
|
||||
} else {
|
||||
return true;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,41 +176,61 @@ impl ScriptIterator {
|
||||
let len = (unsafe { &*self.scripts }).len() as i32;
|
||||
for index in self.index..len {
|
||||
self.index = index;
|
||||
let wrapper = unsafe { &self.scripts.as_ref().unwrap()[self.index as usize] };
|
||||
let wrapper = unsafe {
|
||||
&self
|
||||
.scripts
|
||||
.as_ref()
|
||||
.ok_or(anyhow!("ScriptIterator scripts pointer is null"))?
|
||||
.get_res(self.index as usize)?
|
||||
};
|
||||
if let ScriptWrapper::Set(s) = wrapper {
|
||||
if let Some(set) = s.upgrade() {
|
||||
if set.count() > 0 {
|
||||
self.set_index = 0;
|
||||
return true;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
} else if let ScriptWrapper::Script(script) = wrapper {
|
||||
if let Some(v) = script.upgrade() {
|
||||
if let Some(..) = v.read().as_ref() {
|
||||
return true;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Gets the next valid script. If none is found, returns None.
|
||||
pub fn get_next(&mut self) -> Option<ScriptContainer> {
|
||||
if !self.increment_to_next_value() {
|
||||
return None;
|
||||
pub fn get_next(&mut self) -> Result<Option<ScriptContainer>> {
|
||||
if !self.increment_to_next_value()? {
|
||||
return Ok(None);
|
||||
}
|
||||
unsafe {
|
||||
return match &self.scripts.as_ref().unwrap()[self.index as usize] {
|
||||
// increment_to_next_value
|
||||
ScriptWrapper::Script(script) => Some(script.upgrade().unwrap().into()),
|
||||
ScriptWrapper::Set(set) => {
|
||||
let set = set.upgrade().unwrap();
|
||||
let sc = set.at(self.set_index as usize);
|
||||
return Some(sc);
|
||||
}
|
||||
};
|
||||
Ok(
|
||||
match &self
|
||||
.scripts
|
||||
.as_ref()
|
||||
.ok_or(anyhow!("ScriptIterator scripts pointer is null"))?
|
||||
.get_res(self.index as usize)?
|
||||
{
|
||||
// increment_to_next_value
|
||||
ScriptWrapper::Script(script) => Some(
|
||||
script
|
||||
.upgrade()
|
||||
.ok_or(anyhow!("Couldn't get a strong reference to a script"))?
|
||||
.into(),
|
||||
),
|
||||
ScriptWrapper::Set(set) => {
|
||||
let set = set
|
||||
.upgrade()
|
||||
.ok_or(anyhow!("Couldn't get a strong reference to a set"))?;
|
||||
let sc = set.at(self.set_index as usize)?;
|
||||
return Ok(Some(sc));
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +242,7 @@ impl ScriptIterator {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
use std::any::Any;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
@@ -291,10 +313,10 @@ mod tests {
|
||||
let script = ScriptContainer::new(Arc::new(TestScript::new()));
|
||||
let scripts = vec![ScriptWrapper::from(&script)];
|
||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
while let Some(v) = aggregator.get_next() {
|
||||
while let Some(v) = aggregator.get_next().unwrap() {
|
||||
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||
}
|
||||
let a = script.get_as::<TestScript>();
|
||||
let a = script.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
||||
}
|
||||
|
||||
@@ -305,10 +327,10 @@ mod tests {
|
||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
for i in 1..11 {
|
||||
aggregator.reset();
|
||||
while let Some(v) = aggregator.get_next() {
|
||||
while let Some(v) = aggregator.get_next().unwrap() {
|
||||
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||
}
|
||||
let a = script.get_as::<TestScript>();
|
||||
let a = script.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
||||
}
|
||||
}
|
||||
@@ -324,14 +346,14 @@ mod tests {
|
||||
ScriptWrapper::from(&script3),
|
||||
];
|
||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
while let Some(v) = aggregator.get_next() {
|
||||
while let Some(v) = aggregator.get_next().unwrap() {
|
||||
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||
}
|
||||
let a = script1.get_as::<TestScript>();
|
||||
let a = script1.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
||||
let a = script2.get_as::<TestScript>();
|
||||
let a = script2.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
||||
let a = script3.get_as::<TestScript>();
|
||||
let a = script3.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
||||
}
|
||||
|
||||
@@ -348,14 +370,14 @@ mod tests {
|
||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
for i in 1..11 {
|
||||
aggregator.reset();
|
||||
while let Some(v) = aggregator.get_next() {
|
||||
while let Some(v) = aggregator.get_next().unwrap() {
|
||||
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||
}
|
||||
let a = script1.get_as::<TestScript>();
|
||||
let a = script1.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
||||
let a = script2.get_as::<TestScript>();
|
||||
let a = script2.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
||||
let a = script3.get_as::<TestScript>();
|
||||
let a = script3.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
||||
}
|
||||
}
|
||||
@@ -371,19 +393,19 @@ mod tests {
|
||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
for i in 1..11 {
|
||||
aggregator.reset();
|
||||
while let Some(v) = aggregator.get_next() {
|
||||
while let Some(v) = aggregator.get_next().unwrap() {
|
||||
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||
}
|
||||
let s = set.at(0);
|
||||
let s = s.get_as::<TestScript>();
|
||||
let s = set.at(0).unwrap();
|
||||
let s = s.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(s.test_count.load(Ordering::Relaxed), i);
|
||||
assert_eq!(s.name().str(), "test_a");
|
||||
let s = set.at(1);
|
||||
let s = s.get_as::<TestScript>();
|
||||
let s = set.at(1).unwrap();
|
||||
let s = s.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(s.test_count.load(Ordering::Relaxed), i);
|
||||
assert_eq!(s.name().str(), "test_b");
|
||||
let s = set.at(2);
|
||||
let s = s.get_as::<TestScript>();
|
||||
let s = set.at(2).unwrap();
|
||||
let s = s.get_as::<TestScript>().unwrap();
|
||||
assert_eq!(s.test_count.load(Ordering::Relaxed), i);
|
||||
assert_eq!(s.name().str(), "test_c");
|
||||
}
|
||||
@@ -402,6 +424,7 @@ mod tests {
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.get()
|
||||
.unwrap()
|
||||
.read()
|
||||
@@ -415,6 +438,7 @@ mod tests {
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.get()
|
||||
.unwrap()
|
||||
.read()
|
||||
@@ -425,8 +449,8 @@ mod tests {
|
||||
"test_b"
|
||||
);
|
||||
|
||||
set.remove(&"test_c".into());
|
||||
assert!(aggregator.get_next().is_none());
|
||||
set.remove(&"test_c".into()).unwrap();
|
||||
assert!(aggregator.get_next().unwrap().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -442,6 +466,7 @@ mod tests {
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.get()
|
||||
.unwrap()
|
||||
.read()
|
||||
@@ -452,12 +477,13 @@ mod tests {
|
||||
"test_a"
|
||||
);
|
||||
|
||||
set.remove(&"test_b".into());
|
||||
set.remove(&"test_b".into()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.get()
|
||||
.unwrap()
|
||||
.read()
|
||||
@@ -467,7 +493,7 @@ mod tests {
|
||||
.str(),
|
||||
"test_c"
|
||||
);
|
||||
assert!(aggregator.get_next().is_none());
|
||||
assert!(aggregator.get_next().unwrap().is_none());
|
||||
}
|
||||
|
||||
pub struct TestScriptSource {
|
||||
@@ -503,10 +529,10 @@ mod tests {
|
||||
|
||||
let mut aggregator = source.get_script_iterator().unwrap();
|
||||
aggregator.reset();
|
||||
assert!(aggregator.get_next().is_none());
|
||||
assert!(aggregator.get_next().unwrap().is_none());
|
||||
aggregator.reset();
|
||||
source.script.set(Arc::new(TestScript::new()));
|
||||
assert!(aggregator.get_next().is_some());
|
||||
assert!(aggregator.get_next().unwrap().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -518,9 +544,9 @@ mod tests {
|
||||
|
||||
let mut aggregator = source.get_script_iterator().unwrap();
|
||||
source.script.set(Arc::new(TestScript::new()));
|
||||
assert!(aggregator.get_next().is_some());
|
||||
assert!(aggregator.get_next().unwrap().is_some());
|
||||
aggregator.reset();
|
||||
source.script.clear();
|
||||
assert!(aggregator.get_next().is_none());
|
||||
assert!(aggregator.get_next().unwrap().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::any::Any;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
@@ -355,12 +356,16 @@ impl ScriptContainer {
|
||||
}
|
||||
|
||||
/// Get the underlying script as the downcasted value.
|
||||
pub fn get_as<T: 'static>(&self) -> MappedRwLockReadGuard<T> {
|
||||
RwLockReadGuard::map(self.script.read(), |a| unsafe {
|
||||
let ptr = a.as_ref().as_ref().unwrap().as_ref() as *const dyn Script;
|
||||
let any = ptr.as_ref().unwrap().as_any();
|
||||
any.downcast_ref::<T>().unwrap()
|
||||
})
|
||||
pub fn get_as<T: 'static>(&self) -> Result<MappedRwLockReadGuard<T>> {
|
||||
let r = RwLockReadGuard::try_map(self.script.read(), |a| unsafe {
|
||||
let ptr = a.as_ref().as_ref()?.as_ref() as *const dyn Script;
|
||||
let any = ptr.as_ref()?.as_any();
|
||||
any.downcast_ref::<T>()
|
||||
});
|
||||
match r {
|
||||
Ok(a) => Ok(a),
|
||||
Err(_) => Err(anyhow!("Could not downcast script to requested type")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use indexmap::IndexMap;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
|
||||
use crate::StringKey;
|
||||
use crate::{PkmnError, StringKey};
|
||||
|
||||
/// A collection of unique scripts.
|
||||
#[derive(Debug, Default)]
|
||||
@@ -29,10 +29,12 @@ impl ScriptSet {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.scripts
|
||||
.write()
|
||||
.insert(script.name().clone(), ScriptContainer::new(script));
|
||||
self.scripts.read().last().unwrap().1.clone()
|
||||
|
||||
// If the existing script does not exist, or is not a script, we can just add the new one.
|
||||
let name = script.name().clone();
|
||||
let container = ScriptContainer::new(script);
|
||||
self.scripts.write().insert(name, container.clone());
|
||||
container
|
||||
}
|
||||
|
||||
/// Adds a script with a name to the set. If the script with that name already exists in this
|
||||
@@ -54,8 +56,8 @@ impl ScriptSet {
|
||||
if let Some(script) = script {
|
||||
let name = script.name().clone();
|
||||
let arc = ScriptContainer::new(script);
|
||||
self.scripts.write().insert(name, arc);
|
||||
Ok(Some(self.scripts.read().last().unwrap().1.clone()))
|
||||
self.scripts.write().insert(name, arc.clone());
|
||||
Ok(Some(arc))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -67,27 +69,34 @@ impl ScriptSet {
|
||||
}
|
||||
|
||||
/// Removes a script from the set using its unique name.
|
||||
pub fn remove(&self, key: &StringKey) {
|
||||
pub fn remove(&self, key: &StringKey) -> Result<()> {
|
||||
let value = self.scripts.write().shift_remove(key);
|
||||
if let Some(script) = value {
|
||||
if let Some(script) = script.get() {
|
||||
let script = script.read();
|
||||
script.as_ref().unwrap().on_remove();
|
||||
script.as_ref().unwrap().mark_for_deletion();
|
||||
script.as_ref().ok_or(PkmnError::UnableToAcquireLock)?.on_remove();
|
||||
script
|
||||
.as_ref()
|
||||
.ok_or(PkmnError::UnableToAcquireLock)?
|
||||
.mark_for_deletion();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears all scripts from the set.
|
||||
pub fn clear(&self) {
|
||||
pub fn clear(&self) -> Result<()> {
|
||||
for script in self.scripts.read().deref() {
|
||||
if let Some(script) = script.1.get() {
|
||||
let script = script.read();
|
||||
script.as_ref().unwrap().on_remove();
|
||||
script.as_ref().unwrap().mark_for_deletion();
|
||||
if let Some(script) = &*script {
|
||||
script.on_remove();
|
||||
script.mark_for_deletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
self.scripts.write().clear();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if the set has a script with the given name.
|
||||
@@ -96,8 +105,17 @@ impl ScriptSet {
|
||||
}
|
||||
|
||||
/// Gets a script from the set at a specific index.
|
||||
pub fn at(&self, index: usize) -> ScriptContainer {
|
||||
self.scripts.read()[index].clone()
|
||||
pub fn at(&self, index: usize) -> Result<ScriptContainer> {
|
||||
Ok(self
|
||||
.scripts
|
||||
.read()
|
||||
.get_index(index)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index,
|
||||
len: self.scripts.read().len(),
|
||||
})?
|
||||
.1
|
||||
.clone())
|
||||
}
|
||||
|
||||
/// Gets the number of scripts in the set.
|
||||
|
||||
@@ -35,7 +35,7 @@ pub trait VolatileScriptsOwner {
|
||||
}
|
||||
|
||||
/// Removes a volatile script by name.
|
||||
fn remove_volatile_script(&self, key: &StringKey) {
|
||||
fn remove_volatile_script(&self, key: &StringKey) -> Result<()> {
|
||||
self.volatile_scripts().remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user