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}