use crate::state::StateValue;
use crate::types::Duration;
const PERCEIVED_RISK_DECAY_HALF_LIFE: Duration = Duration::days(7);
const DEFAULT_BASE: f32 = 0.3;
#[derive(Debug, Clone, PartialEq)]
pub struct PerceivedRisk {
risk: StateValue,
}
impl PerceivedRisk {
#[must_use]
pub fn new() -> Self {
PerceivedRisk {
risk: StateValue::new(DEFAULT_BASE)
.with_bounds(0.0, 1.0)
.with_decay_half_life(PERCEIVED_RISK_DECAY_HALF_LIFE),
}
}
#[must_use]
pub fn with_base(base: f32) -> Self {
PerceivedRisk {
risk: StateValue::new(base)
.with_bounds(0.0, 1.0)
.with_decay_half_life(PERCEIVED_RISK_DECAY_HALF_LIFE),
}
}
#[must_use]
pub fn effective(&self) -> f32 {
self.risk.effective()
}
#[must_use]
pub fn base(&self) -> f32 {
self.risk.base()
}
#[must_use]
pub fn delta(&self) -> f32 {
self.risk.delta()
}
#[must_use]
pub fn state_value(&self) -> &StateValue {
&self.risk
}
pub fn state_value_mut(&mut self) -> &mut StateValue {
&mut self.risk
}
pub fn add_delta(&mut self, amount: f32) {
self.risk.add_delta(amount);
}
pub fn set_delta(&mut self, delta: f32) {
self.risk.set_delta(delta);
}
pub fn set_base(&mut self, base: f32) {
self.risk.set_base(base);
}
pub fn apply_decay(&mut self, elapsed: Duration) {
self.risk.apply_decay(elapsed);
}
pub fn reset_delta(&mut self) {
self.risk.reset_delta();
}
}
impl Default for PerceivedRisk {
fn default() -> Self {
PerceivedRisk::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_creates_default_values() {
let risk = PerceivedRisk::new();
assert!((risk.effective() - DEFAULT_BASE).abs() < f32::EPSILON);
}
#[test]
fn with_base_creates_custom_value() {
let risk = PerceivedRisk::with_base(0.5);
assert!((risk.effective() - 0.5).abs() < f32::EPSILON);
}
#[test]
fn base_accessor() {
let risk = PerceivedRisk::with_base(0.6);
assert!((risk.base() - 0.6).abs() < f32::EPSILON);
}
#[test]
fn delta_accessor() {
let mut risk = PerceivedRisk::new();
risk.add_delta(0.2);
assert!((risk.delta() - 0.2).abs() < f32::EPSILON);
}
#[test]
fn state_value_accessor() {
let risk = PerceivedRisk::new();
assert!((risk.state_value().effective() - DEFAULT_BASE).abs() < f32::EPSILON);
}
#[test]
fn state_value_mut_accessor() {
let mut risk = PerceivedRisk::new();
risk.state_value_mut().add_delta(0.1);
assert!((risk.delta() - 0.1).abs() < f32::EPSILON);
}
#[test]
fn add_delta() {
let mut risk = PerceivedRisk::new();
risk.add_delta(0.2);
assert!((risk.effective() - 0.5).abs() < f32::EPSILON);
}
#[test]
fn set_delta() {
let mut risk = PerceivedRisk::new();
risk.set_delta(0.3);
assert!((risk.delta() - 0.3).abs() < f32::EPSILON);
}
#[test]
fn set_base() {
let mut risk = PerceivedRisk::new();
risk.set_base(0.7);
assert!((risk.base() - 0.7).abs() < f32::EPSILON);
}
#[test]
fn decay_over_7_days() {
let mut risk = PerceivedRisk::new();
risk.add_delta(0.4);
risk.apply_decay(Duration::days(7));
assert!((risk.delta() - 0.2).abs() < 0.01);
}
#[test]
fn reset_delta() {
let mut risk = PerceivedRisk::new();
risk.add_delta(0.5);
risk.reset_delta();
assert!(risk.delta().abs() < f32::EPSILON);
}
#[test]
fn default_equals_new() {
let d = PerceivedRisk::default();
let n = PerceivedRisk::new();
assert_eq!(d, n);
}
#[test]
fn clone_and_equality() {
let r1 = PerceivedRisk::with_base(0.5);
let r2 = r1.clone();
assert_eq!(r1, r2);
}
#[test]
fn debug_format() {
let risk = PerceivedRisk::new();
let debug = format!("{:?}", risk);
assert!(debug.contains("PerceivedRisk"));
}
}