frequenz_resampling/
resampling_function.rs

1// License: MIT
2// Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3
4//! Resampling functions for time series data.
5
6use crate::Sample;
7use std::{fmt::Debug, ops::Div};
8
9// This trait can't directly have `Clone` as a supertrait because
10// then it wouldn't be dyn-compatible.
11//
12// Instead, we make a blanket implementation for all FnMut that implement
13// `Clone`, which will be dispatched statically.
14pub trait ClonableFnMut<S, T>: FnMut(&[&S]) -> Option<T> + Send + Sync {
15    fn clone_box(&self) -> Box<dyn ClonableFnMut<S, T>>;
16}
17
18impl<S, T, F> ClonableFnMut<S, T> for F
19where
20    F: FnMut(&[&S]) -> Option<T> + Send + Sync + Clone + 'static,
21{
22    fn clone_box(&self) -> Box<dyn ClonableFnMut<S, T>> {
23        Box::new(self.clone())
24    }
25}
26
27/// The ResamplingFunction enum represents the different resampling functions
28/// that can be used to resample a channel.
29#[derive(Default)]
30pub enum ResamplingFunction<
31    T: Div<Output = T> + std::iter::Sum + Default + Debug,
32    S: Sample<Value = T>,
33> {
34    /// Calculates the average of all samples in the time step (ignoring None
35    /// values)
36    #[default]
37    Average,
38    /// Calculates the sum of all samples in the time step (ignoring None
39    /// values)
40    Sum,
41    /// Calculates the maximum value of all samples in the time step (ignoring
42    /// None values)
43    Max,
44    /// Calculates the minimum value of all samples in the time step (ignoring
45    /// None values)
46    Min,
47    /// Uses the first sample in the time step. If the first sample is None, the
48    /// resampling function will return None.
49    First,
50    /// Uses the last sample in the time step. If the last sample is None, the
51    /// resampling function will return None.
52    Last,
53    /// Returns the first non-None sample in the time step. If all samples are
54    /// None, the resampling function will return None.
55    Coalesce,
56    /// Counts the number of samples in the time step (ignoring None values)
57    Count,
58    /// A custom resampling function that takes a closure that takes a slice of
59    /// samples and returns an optional value.
60    Custom(Box<dyn ClonableFnMut<S, T>>),
61}
62
63impl<T, S> Clone for ResamplingFunction<T, S>
64where
65    T: Div<Output = T> + std::iter::Sum + Default + Debug,
66    S: Sample<Value = T>,
67{
68    fn clone(&self) -> Self {
69        match self {
70            Self::Average => Self::Average,
71            Self::Sum => Self::Sum,
72            Self::Max => Self::Max,
73            Self::Min => Self::Min,
74            Self::First => Self::First,
75            Self::Last => Self::Last,
76            Self::Coalesce => Self::Coalesce,
77            Self::Count => Self::Count,
78            Self::Custom(f) => Self::Custom(f.clone_box()),
79        }
80    }
81}