argumentation_weighted/
types.rs1use crate::error::Error;
9
10#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
16pub struct AttackWeight(f64);
17
18impl AttackWeight {
19 pub fn new(value: f64) -> Result<Self, Error> {
21 if !value.is_finite() || value < 0.0 {
22 return Err(Error::InvalidWeight { weight: value });
23 }
24 Ok(Self(value))
25 }
26
27 #[must_use]
30 pub fn value(self) -> f64 {
31 self.0
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
39pub struct Budget(f64);
40
41impl Budget {
42 pub fn new(value: f64) -> Result<Self, Error> {
44 if !value.is_finite() || value < 0.0 {
45 return Err(Error::InvalidBudget { budget: value });
46 }
47 Ok(Self(value))
48 }
49
50 #[must_use]
52 pub fn value(self) -> f64 {
53 self.0
54 }
55
56 #[must_use]
59 pub fn zero() -> Self {
60 Self(0.0)
61 }
62}
63
64#[derive(Debug, Clone, PartialEq)]
73pub struct WeightedAttack<A: Clone + Eq> {
74 pub attacker: A,
76 pub target: A,
78 pub weight: AttackWeight,
80}
81
82impl<A: Clone + Eq> WeightedAttack<A> {
83 pub fn new(attacker: A, target: A, weight: f64) -> Result<Self, Error> {
85 Ok(Self {
86 attacker,
87 target,
88 weight: AttackWeight::new(weight)?,
89 })
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn attack_weight_accepts_valid_values() {
99 assert!(AttackWeight::new(0.0).is_ok());
100 assert!(AttackWeight::new(0.5).is_ok());
101 assert!(AttackWeight::new(100.0).is_ok());
102 }
103
104 #[test]
105 fn attack_weight_rejects_nan() {
106 let err = AttackWeight::new(f64::NAN).unwrap_err();
107 assert!(matches!(err, Error::InvalidWeight { .. }));
108 }
109
110 #[test]
111 fn attack_weight_rejects_infinity() {
112 assert!(AttackWeight::new(f64::INFINITY).is_err());
113 assert!(AttackWeight::new(f64::NEG_INFINITY).is_err());
114 }
115
116 #[test]
117 fn attack_weight_rejects_negative() {
118 assert!(AttackWeight::new(-0.1).is_err());
119 }
120
121 #[test]
122 fn budget_zero_is_valid() {
123 assert_eq!(Budget::zero().value(), 0.0);
124 assert!(Budget::new(0.0).is_ok());
125 }
126
127 #[test]
128 fn budget_rejects_invalid_values() {
129 assert!(Budget::new(-1.0).is_err());
130 assert!(Budget::new(f64::NAN).is_err());
131 assert!(Budget::new(f64::INFINITY).is_err());
132 }
133
134 #[test]
135 fn weighted_attack_new_validates_weight() {
136 assert!(WeightedAttack::new("a", "b", 0.5).is_ok());
137 assert!(WeightedAttack::new("a", "b", -0.5).is_err());
138 }
139}