use super::metrics::Metrics;
use super::Observation;
use crate::time::TimeSpan;
#[derive(Debug, Clone)]
pub struct Aggregation<V, M>
where
M: Metrics<V> + From<V>,
{
metrics: M,
pub count: usize,
pub timespan: TimeSpan,
_phantom: std::marker::PhantomData<V>,
}
impl<V, M> From<Observation<V>> for Aggregation<V, M>
where
M: Metrics<V> + From<V> + Clone,
{
fn from(sample: Observation<V>) -> Self {
let timespan = TimeSpan::new(sample.timestamp.clone(), sample.timestamp.clone());
let metrics = M::from(sample.value);
Aggregation::new(timespan, metrics, 1)
}
}
impl<V, M> From<&Aggregation<V, M>> for Aggregation<V, M>
where
M: Metrics<V> + From<V> + Clone,
{
fn from(reference: &Aggregation<V, M>) -> Self {
let timespan = reference.timespan.clone();
let metrics = reference.metrics.clone();
Aggregation::new(timespan, metrics, 1)
}
}
impl<V, M> Aggregation<V, M>
where
M: Metrics<V> + From<V> + Clone,
{
pub fn new(timespan: TimeSpan, metrics: M, count: usize) -> Self {
Aggregation {
metrics,
timespan,
count,
_phantom: Default::default(),
}
}
pub fn from_aggregations(aggregations: &[Aggregation<V, M>]) -> Option<Self> {
if aggregations.is_empty() {
None
} else {
let (first, rest) = aggregations.split_first().unwrap();
let mut merged_aggregations: Aggregation<V, M> = Aggregation::from(first);
for aggregation in rest {
merged_aggregations.include(aggregation);
}
Some(merged_aggregations)
}
}
pub fn update(&mut self, sample: &Observation<V>) {
self.metrics.update(&sample.value);
self.count += 1;
self.timespan.extend_to_include(&sample.timestamp);
}
pub fn include(&mut self, aggregation: &Aggregation<V, M>) {
self.metrics.include(&aggregation.metrics);
self.count += aggregation.count;
self.timespan.extend_to_include_span(&aggregation.timespan);
}
pub fn metrics(&self) -> &M {
&self.metrics
}
}
#[cfg(test)]
mod tests {
use super::super::sample::{Sample, SampleMetrics};
use super::{Aggregation, Observation};
use crate::time::{TimeSpan, TimeStamp};
#[test]
fn metric_updates() {
let t1 = TimeStamp::from_seconds(3);
let t2 = TimeStamp::from_seconds(8);
let t3 = TimeStamp::from_seconds(18);
let sample1 = Sample::new(2.2);
let sample2 = Sample::new(5.2);
let sample3 = Sample::new(-9.0);
let observation1 = Observation::new(t1.clone(), sample1);
let observation2 = Observation::new(t2.clone(), sample2);
let observation3 = Observation::new(t3.clone(), sample3);
let mut aggregation = Aggregation::<Sample, SampleMetrics>::from(observation1);
aggregation.update(&observation2);
aggregation.update(&observation3);
assert_eq!(aggregation.count, 3);
assert_eq!(aggregation.metrics().max, 5.2);
assert_eq!(aggregation.metrics().min, -9.0);
assert_eq!(aggregation.timespan, TimeSpan::new(t1, t3));
}
}