Skip to main content

radiate_core/
rate.rs

1use crate::{MetricSet, error::RadiateResult};
2use radiate_error::radiate_bail;
3use radiate_expr::Expr;
4use radiate_utils::SmallStr;
5use smallvec::SmallVec;
6
7const DEFAULT_VALUE: f32 = 1.0;
8
9#[derive(Clone)]
10pub struct RateSet {
11    pub control: Expr,
12    pub internal: Vec<Expr>,
13    pub rate_cache: SmallVec<[f32; 8]>,
14    pub last_update_index: usize,
15    pub has_updated: bool,
16}
17
18impl RateSet {
19    pub fn new(control: impl Into<Expr>) -> Self {
20        Self {
21            control: control.into(),
22            internal: Vec::new(),
23            rate_cache: SmallVec::new(),
24            last_update_index: 0,
25            has_updated: false,
26        }
27    }
28
29    pub fn calculate_rates(
30        &mut self,
31        generation: usize,
32        metrics: &MetricSet,
33    ) -> RadiateResult<&[f32]> {
34        if generation > self.last_update_index || !self.has_updated {
35            self.rate_cache.clear();
36
37            let control_rate = Self::try_eval_rate(metrics, &mut self.control)?;
38            self.rate_cache.push(control_rate);
39
40            for expr in &mut self.internal {
41                let rate = Self::try_eval_rate(metrics, expr)?;
42                self.rate_cache.push(rate);
43            }
44
45            self.last_update_index = generation;
46            self.has_updated = true;
47        }
48
49        Ok(&self.rate_cache)
50    }
51
52    pub fn calculate_control_rate(
53        &mut self,
54        generation: usize,
55        metrics: &MetricSet,
56    ) -> RadiateResult<f32> {
57        self.calculate_rates(generation, metrics)?;
58        Ok(self.rate_cache[0])
59    }
60
61    pub fn rates(&self) -> &[f32] {
62        &self.rate_cache
63    }
64
65    pub fn alias(mut self, name: impl Into<SmallStr>) -> Self {
66        let name = name.into();
67        self.control = self.control.clone().alias(name);
68        self
69    }
70
71    pub fn push(mut self, expr: impl Into<Expr>) -> Self {
72        self.internal.push(expr.into());
73        self
74    }
75
76    fn try_eval_rate(metrics: &MetricSet, expr: &mut Expr) -> RadiateResult<f32> {
77        if let Some(metric) = metrics.get(expr.name()) {
78            return Ok(metric.last_value());
79        }
80
81        let output = expr.evaluate(metrics)?;
82        match output.extract::<f32>() {
83            Some(rate) => Ok(rate),
84            None => {
85                radiate_bail!(Expr:
86                    "Failed to evaluate rate expression for alterer: expected f32 value, got {:?}",
87                    output
88                );
89            }
90        }
91    }
92}
93
94impl Default for RateSet {
95    fn default() -> Self {
96        Self {
97            control: Expr::lit(DEFAULT_VALUE),
98            internal: Vec::new(),
99            rate_cache: SmallVec::new(),
100            last_update_index: 0,
101            has_updated: false,
102        }
103    }
104}
105
106impl From<Expr> for RateSet {
107    fn from(expr: Expr) -> Self {
108        Self::new(expr)
109    }
110}