use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PolicyId(String);
impl PolicyId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for PolicyId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<String> for PolicyId {
fn from(s: String) -> Self {
Self(s)
}
}
impl From<&str> for PolicyId {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum AggregationStrategy {
#[default]
Multiply,
Add,
Max,
Min,
}
impl AggregationStrategy {
pub fn initial_value(&self) -> f32 {
match self {
Self::Multiply => 1.0,
Self::Add => 0.0,
Self::Max => f32::MIN,
Self::Min => f32::MAX,
}
}
pub fn aggregate(&self, current: f32, value: f32) -> f32 {
match self {
Self::Multiply => current * value,
Self::Add => current + value,
Self::Max => current.max(value),
Self::Min => current.min(value),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Policy {
pub id: PolicyId,
pub name: String,
pub description: String,
pub effects: HashMap<String, f32>,
#[serde(default)]
pub metadata: serde_json::Value,
}
impl Policy {
pub fn new(
id: impl Into<String>,
name: impl Into<String>,
description: impl Into<String>,
) -> Self {
Self {
id: PolicyId::new(id),
name: name.into(),
description: description.into(),
effects: HashMap::new(),
metadata: serde_json::Value::Null,
}
}
pub fn with_effects(mut self, effects: HashMap<String, f32>) -> Self {
self.effects = effects;
self
}
pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
self.metadata = metadata;
self
}
pub fn add_effect(mut self, name: impl Into<String>, value: f32) -> Self {
self.effects.insert(name.into(), value);
self
}
pub fn get_effect(&self, name: &str) -> Option<f32> {
self.effects.get(name).copied()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_policy_id_creation() {
let id = PolicyId::new("test_policy");
assert_eq!(id.as_str(), "test_policy");
assert_eq!(id.to_string(), "test_policy");
}
#[test]
fn test_policy_id_from_string() {
let id: PolicyId = "test_policy".into();
assert_eq!(id.as_str(), "test_policy");
}
#[test]
fn test_aggregation_strategy_initial_values() {
assert_eq!(AggregationStrategy::Multiply.initial_value(), 1.0);
assert_eq!(AggregationStrategy::Add.initial_value(), 0.0);
assert_eq!(AggregationStrategy::Max.initial_value(), f32::MIN);
assert_eq!(AggregationStrategy::Min.initial_value(), f32::MAX);
}
#[test]
fn test_aggregation_strategy_multiply() {
let strategy = AggregationStrategy::Multiply;
assert_eq!(strategy.aggregate(1.2, 1.1), 1.32);
}
#[test]
fn test_aggregation_strategy_add() {
let strategy = AggregationStrategy::Add;
assert_eq!(strategy.aggregate(10.0, 5.0), 15.0);
}
#[test]
fn test_aggregation_strategy_max() {
let strategy = AggregationStrategy::Max;
assert_eq!(strategy.aggregate(1.2, 1.1), 1.2);
assert_eq!(strategy.aggregate(1.1, 1.2), 1.2);
}
#[test]
fn test_aggregation_strategy_min() {
let strategy = AggregationStrategy::Min;
assert_eq!(strategy.aggregate(0.9, 0.8), 0.8);
assert_eq!(strategy.aggregate(0.8, 0.9), 0.8);
}
#[test]
fn test_policy_creation() {
let policy = Policy::new("test", "Test Policy", "A test policy");
assert_eq!(policy.id.as_str(), "test");
assert_eq!(policy.name, "Test Policy");
assert_eq!(policy.description, "A test policy");
assert!(policy.effects.is_empty());
}
#[test]
fn test_policy_with_effects() {
let mut effects = HashMap::new();
effects.insert("income_multiplier".into(), 1.2);
effects.insert("attack_bonus".into(), 10.0);
let policy = Policy::new("test", "Test", "Test").with_effects(effects);
assert_eq!(policy.get_effect("income_multiplier"), Some(1.2));
assert_eq!(policy.get_effect("attack_bonus"), Some(10.0));
assert_eq!(policy.get_effect("nonexistent"), None);
}
#[test]
fn test_policy_add_effect() {
let policy = Policy::new("test", "Test", "Test")
.add_effect("income_multiplier", 1.2)
.add_effect("attack_bonus", 10.0);
assert_eq!(policy.get_effect("income_multiplier"), Some(1.2));
assert_eq!(policy.get_effect("attack_bonus"), Some(10.0));
}
}