Skip to main content

llm_optimizer_processor/aggregation/
trait_.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::Debug;
3
4/// Core trait for all aggregators
5///
6/// This trait defines the interface for incremental aggregation with support for:
7/// - Incremental updates (feed values one at a time)
8/// - Accumulator merging (for distributed processing)
9/// - State serialization (for persistence and recovery)
10pub trait Aggregator: Send + Sync + Debug {
11    /// The type of values this aggregator accepts
12    type Input: Clone;
13
14    /// The type of the final aggregation result
15    type Output: Clone;
16
17    /// The type of the internal accumulator state (must be serializable)
18    type Accumulator: Clone + Serialize + for<'de> Deserialize<'de>;
19
20    /// Create a new aggregator instance
21    fn new() -> Self
22    where
23        Self: Sized;
24
25    /// Update the aggregator with a new value
26    fn update(&mut self, value: Self::Input) -> anyhow::Result<()>;
27
28    /// Update with multiple values at once
29    fn update_batch(&mut self, values: &[Self::Input]) -> anyhow::Result<()> {
30        for value in values {
31            self.update(value.clone())?;
32        }
33        Ok(())
34    }
35
36    /// Compute the final aggregation result
37    fn finalize(&self) -> anyhow::Result<Self::Output>;
38
39    /// Get the current accumulator state (for serialization/merging)
40    fn accumulator(&self) -> Self::Accumulator;
41
42    /// Merge another accumulator into this one (for distributed processing)
43    fn merge(&mut self, other: Self::Accumulator) -> anyhow::Result<()>;
44
45    /// Reset the aggregator to initial state
46    fn reset(&mut self);
47
48    /// Get the number of values processed so far
49    fn count(&self) -> u64;
50
51    /// Check if the aggregator has processed any values
52    fn is_empty(&self) -> bool {
53        self.count() == 0
54    }
55}
56
57/// A trait for aggregators that can be cloned
58pub trait CloneableAggregator: Aggregator {
59    fn clone_box(&self) -> Box<dyn CloneableAggregator<Input = Self::Input, Output = Self::Output, Accumulator = Self::Accumulator>>;
60}
61
62/// Helper trait for converting values to f64 for numeric aggregations
63pub trait ToF64 {
64    fn to_f64(&self) -> f64;
65}
66
67impl ToF64 for f64 {
68    fn to_f64(&self) -> f64 {
69        *self
70    }
71}
72
73impl ToF64 for f32 {
74    fn to_f64(&self) -> f64 {
75        *self as f64
76    }
77}
78
79impl ToF64 for i64 {
80    fn to_f64(&self) -> f64 {
81        *self as f64
82    }
83}
84
85impl ToF64 for i32 {
86    fn to_f64(&self) -> f64 {
87        *self as f64
88    }
89}
90
91impl ToF64 for u64 {
92    fn to_f64(&self) -> f64 {
93        *self as f64
94    }
95}
96
97impl ToF64 for u32 {
98    fn to_f64(&self) -> f64 {
99        *self as f64
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn test_to_f64_conversions() {
109        assert_eq!(42_f64.to_f64(), 42.0);
110        assert_eq!(42_f32.to_f64(), 42.0);
111        assert_eq!(42_i64.to_f64(), 42.0);
112        assert_eq!(42_i32.to_f64(), 42.0);
113        assert_eq!(42_u64.to_f64(), 42.0);
114        assert_eq!(42_u32.to_f64(), 42.0);
115    }
116}