use crate::context::StatContext;
use crate::numeric::{StatNumeric, StatValue};
use crate::stat_id::StatId;
use rustc_hash::FxHashMap;
pub trait StatSource: Send + Sync + std::fmt::Debug {
fn get_value(&self, stat_id: &StatId, context: &StatContext) -> StatValue;
}
#[derive(Debug, Clone)]
pub struct ConstantSource(pub f64);
impl StatSource for ConstantSource {
fn get_value(&self, _stat_id: &StatId, _context: &StatContext) -> StatValue {
StatValue::from_f64(self.0)
}
}
#[derive(Debug, Clone)]
pub struct MapSource {
values: FxHashMap<StatId, f64>,
}
impl MapSource {
pub fn new<I: IntoIterator<Item = (StatId, f64)>>(values: I) -> Self {
Self {
values: values.into_iter().collect(),
}
}
pub fn empty() -> Self {
Self {
values: FxHashMap::default(),
}
}
pub fn insert(&mut self, stat_id: StatId, value: f64) {
self.values.insert(stat_id, value);
}
}
impl StatSource for MapSource {
fn get_value(&self, stat_id: &StatId, _context: &StatContext) -> StatValue {
StatValue::from_f64(self.values.get(stat_id).copied().unwrap_or(0.0))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant_source() {
let source = ConstantSource(100.0);
let context = StatContext::new();
let stat_id = StatId::from("HP");
assert_eq!(
source.get_value(&stat_id, &context),
StatValue::from_f64(100.0)
);
}
#[test]
fn test_map_source() {
let mut source = MapSource::empty();
let hp_id = StatId::from("HP");
let atk_id = StatId::from("ATK");
source.insert(hp_id.clone(), 100.0);
source.insert(atk_id.clone(), 50.0);
let context = StatContext::new();
assert_eq!(
source.get_value(&hp_id, &context),
StatValue::from_f64(100.0)
);
assert_eq!(
source.get_value(&atk_id, &context),
StatValue::from_f64(50.0)
);
assert_eq!(
source.get_value(&StatId::from("MISSING"), &context),
StatValue::from_f64(0.0)
);
}
#[test]
fn test_map_source_new() {
use std::collections::HashMap;
let mut values = HashMap::new();
values.insert(StatId::from("HP"), 100.0);
values.insert(StatId::from("MP"), 50.0);
let source = MapSource::new(values);
let context = StatContext::new();
assert_eq!(
source.get_value(&StatId::from("HP"), &context),
StatValue::from_f64(100.0)
);
assert_eq!(
source.get_value(&StatId::from("MP"), &context),
StatValue::from_f64(50.0)
);
}
#[test]
fn test_map_source_insert_overwrite() {
let mut source = MapSource::empty();
let hp_id = StatId::from("HP");
source.insert(hp_id.clone(), 100.0);
let context = StatContext::new();
assert_eq!(
source.get_value(&hp_id, &context),
StatValue::from_f64(100.0)
);
source.insert(hp_id.clone(), 200.0);
assert_eq!(
source.get_value(&hp_id, &context),
StatValue::from_f64(200.0)
);
}
#[test]
fn test_map_source_empty() {
let source = MapSource::empty();
let context = StatContext::new();
assert_eq!(
source.get_value(&StatId::from("ANY"), &context),
StatValue::from_f64(0.0)
);
}
#[test]
fn test_constant_source_negative() {
let source = ConstantSource(-50.0);
let context = StatContext::new();
let stat_id = StatId::from("HP");
assert_eq!(
source.get_value(&stat_id, &context),
StatValue::from_f64(-50.0)
);
}
#[test]
fn test_constant_source_zero() {
let source = ConstantSource(0.0);
let context = StatContext::new();
let stat_id = StatId::from("HP");
assert_eq!(
source.get_value(&stat_id, &context),
StatValue::from_f64(0.0)
);
}
#[test]
fn test_constant_source_clone() {
let source1 = ConstantSource(100.0);
let source2 = source1.clone();
let context = StatContext::new();
let stat_id = StatId::from("HP");
assert_eq!(
source1.get_value(&stat_id, &context),
StatValue::from_f64(100.0)
);
assert_eq!(
source2.get_value(&stat_id, &context),
StatValue::from_f64(100.0)
);
}
}