PkmnLib_rs/src/static_data/species_data/learnable_moves.rs

104 lines
3.5 KiB
Rust
Executable File

use anyhow_ext::Result;
use indexmap::IndexSet;
use parking_lot::RwLock;
use std::fmt::Debug;
use crate::defines::LevelInt;
use crate::{StringKey, VecExt};
/// The storage of the moves a Pokemon can learn.
pub trait LearnableMoves: Debug {
/// Adds a new level move the Pokemon can learn.
fn add_level_move(&self, level: LevelInt, m: &StringKey) -> Result<()>;
/// Gets all moves a Pokemon can learn when leveling up to a specific level.
fn get_learned_by_level(&self, level: LevelInt) -> Option<Vec<StringKey>>;
/// Gets the distinct moves a Pokemon can learn through leveling up.
fn get_distinct_level_moves(&self) -> IndexSet<StringKey>;
}
/// The storage of the moves a Pokemon can learn.
#[derive(Debug)]
pub struct LearnableMovesImpl {
/// A map of the moves a Pokemon can learn per level.
learned_by_level: RwLock<Vec<Vec<StringKey>>>,
/// A list of the distinct moves a Pokemon can learn through leveling up.
distinct_level_moves: RwLock<IndexSet<StringKey>>,
}
impl LearnableMovesImpl {
/// Instantiates a new object to store the moves a Pokemon can learn.
pub fn new(max_level: LevelInt) -> Self {
Self {
learned_by_level: RwLock::new(vec![Vec::new(); (max_level + 1) as usize]),
distinct_level_moves: Default::default(),
}
}
}
impl LearnableMoves for LearnableMovesImpl {
/// Adds a new level move the Pokemon can learn.
fn add_level_move(&self, level: LevelInt, m: &StringKey) -> Result<()> {
self.learned_by_level
.write()
.get_mut_res(level as usize)?
.push(m.clone());
self.distinct_level_moves.write().insert(m.clone());
Ok(())
}
/// Gets all moves a Pokemon can learn when leveling up to a specific level.
fn get_learned_by_level(&self, level: LevelInt) -> Option<Vec<StringKey>> {
self.learned_by_level.read().get(level as usize).cloned()
}
/// Gets the distinct moves a Pokemon can learn through leveling up.
fn get_distinct_level_moves(&self) -> IndexSet<StringKey> {
self.distinct_level_moves.read().clone()
}
}
#[cfg(test)]
#[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)]
pub(crate) mod tests {
use super::*;
#[test]
fn adds_level_moves() {
let moves = LearnableMovesImpl::new(100);
moves.add_level_move(1, &"foo".into()).unwrap();
moves.add_level_move(1, &"bar".into()).unwrap();
let m = moves.get_learned_by_level(1u8).unwrap();
assert_eq!(m.len(), 2);
assert_eq!(m[0], "foo".into());
assert_eq!(m[1], "bar".into());
}
#[test]
fn adds_two_same_moves_at_different_level() {
let moves = LearnableMovesImpl::new(100);
moves.add_level_move(1, &"foo".into()).unwrap();
moves.add_level_move(5, &"foo".into()).unwrap();
let m = moves.get_learned_by_level(1u8).unwrap();
assert_eq!(m.len(), 1);
assert_eq!(m[0], "foo".into());
let m2 = moves.get_learned_by_level(5u8).unwrap();
assert_eq!(m2.len(), 1);
assert_eq!(m2[0], "foo".into());
let distinct = moves.get_distinct_level_moves();
assert_eq!(distinct.len(), 1);
assert_eq!(distinct[0], "foo".into());
}
mockall::mock! {
pub LearnableMoves {
fn add_level_move(&mut self, level: LevelInt, m: &StringKey);
fn get_learned_by_level<'a>(&'a self, level: LevelInt) -> Option<&'a Vec<StringKey>>;
fn get_distinct_level_moves(&self) -> &Vec<StringKey>;
}
}
}