iop_morpheus_node/
time_series.rs1use super::*;
2
3#[derive(Debug, Clone)]
4struct TimeSeriesPoint<T> {
5 height: BlockHeight,
6 value: T,
7}
8
9#[derive(Debug, Clone)]
10pub struct TimeSeries<T: fmt::Display + PartialEq<T>> {
11 initial_value: T,
12 points: Vec<TimeSeriesPoint<T>>,
13}
14
15impl<T: fmt::Display + PartialEq<T>> TimeSeries<T> {
16 pub fn new(initial_value: T) -> Self {
17 Self { initial_value, points: Default::default() }
18 }
19
20 pub fn iter(&self) -> impl Iterator<Item = (Option<BlockHeight>, &T)> {
21 std::iter::once((None, &self.initial_value))
22 .chain(self.points.iter().map(|p| (Some(p.height), &p.value)))
23 }
24
25 pub fn get(&self, height: BlockHeight) -> &T {
26 self.points
27 .iter()
28 .rev()
29 .find(|p| p.height <= height)
30 .map(|p| &p.value)
31 .unwrap_or_else(|| &self.initial_value)
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.points.is_empty()
36 }
37
38 pub fn latest_value(&self) -> &T {
39 self.points.last().map(|p| &p.value).unwrap_or_else(|| &self.initial_value)
40 }
41
42 pub fn latest_height(&self) -> Option<BlockHeight> {
43 self.points.last().map(|p| p.height)
44 }
45
46 pub fn apply<D: fmt::Display>(
47 &mut self, height: BlockHeight, value: T, context: impl FnOnce() -> D,
48 ) -> Result<()> {
49 if let Some(last) = self.points.last() {
50 ensure!(last.height < height, "{} was already set at height {}", context(), height);
51 }
52 ensure!(
53 self.latest_value() != &value,
54 "{} was already set to {} at height {}",
55 context(),
56 value,
57 height
58 );
59 self.points.push(TimeSeriesPoint { height, value });
60 Ok(())
61 }
62
63 pub fn revert<D: fmt::Display>(
64 &mut self, height: BlockHeight, value: T, context: impl FnOnce() -> D,
65 ) -> Result<()> {
66 if let Some(last) = self.points.pop() {
67 ensure!(
68 last.height == height,
69 "{} was set at height {}, cannot unset at height {}",
70 context(),
71 last.height,
72 height
73 );
74 ensure!(
75 last.value == value,
76 "{} was set to {} at height {}, cannot unset it from {}",
77 context(),
78 last.value,
79 last.height,
80 value
81 );
82 Ok(())
83 } else {
84 bail!("{} has nothing to unset", context());
85 }
86 }
87}