snops_common/format/
impl_checkpoint.rs

1use std::io::{Read, Write};
2
3use snops_checkpoint::{RetentionPolicy, RetentionRule, RetentionSpan};
4
5use super::{DataFormat, DataFormatReader, DataHeaderOf, DataReadError, DataWriteError};
6
7impl DataFormat for RetentionSpan {
8    type Header = u8;
9    const LATEST_HEADER: Self::Header = 1;
10
11    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
12        match self {
13            RetentionSpan::Unlimited => 0u8.write_data(writer),
14            RetentionSpan::Minute(b) => {
15                1u8.write_data(writer)?;
16                b.write_data(writer)
17            }
18            RetentionSpan::Hour(b) => {
19                2u8.write_data(writer)?;
20                b.write_data(writer)
21            }
22            RetentionSpan::Day(b) => {
23                3u8.write_data(writer)?;
24                b.write_data(writer)
25            }
26            RetentionSpan::Week(b) => {
27                4u8.write_data(writer)?;
28                b.write_data(writer)
29            }
30            RetentionSpan::Month(b) => {
31                5u8.write_data(writer)?;
32                b.write_data(writer)
33            }
34            RetentionSpan::Year(b) => {
35                6u8.write_data(writer)?;
36                b.write_data(writer)
37            }
38        }
39    }
40
41    fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
42        if *header != Self::LATEST_HEADER {
43            return Err(DataReadError::unsupported(
44                "RetentionSpan",
45                Self::LATEST_HEADER,
46                *header,
47            ));
48        }
49        match reader.read_data(&())? {
50            0u8 => Ok(RetentionSpan::Unlimited),
51            1u8 => Ok(RetentionSpan::Minute(reader.read_data(&())?)),
52            2u8 => Ok(RetentionSpan::Hour(reader.read_data(&())?)),
53            3u8 => Ok(RetentionSpan::Day(reader.read_data(&())?)),
54            4u8 => Ok(RetentionSpan::Week(reader.read_data(&())?)),
55            5u8 => Ok(RetentionSpan::Month(reader.read_data(&())?)),
56            6u8 => Ok(RetentionSpan::Year(reader.read_data(&())?)),
57            n => Err(DataReadError::Custom(format!(
58                "invalid RetentionSpan discrminant: {n}",
59            ))),
60        }
61    }
62}
63
64impl DataFormat for RetentionPolicy {
65    type Header = (u8, DataHeaderOf<RetentionSpan>);
66
67    const LATEST_HEADER: Self::Header = (1, RetentionSpan::LATEST_HEADER);
68
69    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
70        let rules = self
71            .rules
72            .iter()
73            .map(|r| (r.duration, r.keep))
74            .collect::<Vec<_>>();
75        rules.write_data(writer)
76    }
77
78    fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
79        if header.0 != Self::LATEST_HEADER.0 {
80            return Err(DataReadError::unsupported(
81                "RetentionPolicy",
82                Self::LATEST_HEADER.0,
83                header.0,
84            ));
85        }
86
87        let rules =
88            Vec::<(RetentionSpan, RetentionSpan)>::read_data(reader, &(header.1, header.1))?;
89        Ok(RetentionPolicy {
90            rules: rules
91                .into_iter()
92                .map(|(duration, keep)| RetentionRule { duration, keep })
93                .collect(),
94        })
95    }
96}
97
98#[cfg(test)]
99#[rustfmt::skip]
100mod test {
101    use crate::format::DataFormat;
102    use snops_checkpoint::{RetentionPolicy, RetentionSpan};
103
104
105    macro_rules! case {
106        ($name:ident, $ty:ty, $a:expr, $b:expr) => {
107            #[test]
108            fn $name() {
109                let mut data = Vec::new();
110                let value: $ty = $a.parse().unwrap();
111                value.write_data(&mut data).unwrap();
112                assert_eq!(data, $b);
113
114                let mut reader = &data[..];
115                let read_value = <$ty>::read_data(&mut reader, &<$ty as DataFormat>::LATEST_HEADER).unwrap();
116                assert_eq!(read_value, value);
117
118            }
119
120        };
121    }
122
123    case!(retention_span_unlimited, RetentionSpan, "U", [0]);
124    case!(retention_span_minute, RetentionSpan, "1m", [1, 1]);
125    case!(retention_span_hour, RetentionSpan, "1h", [2, 1]);
126    case!(retention_span_day, RetentionSpan, "1D", [3, 1]);
127    case!(retention_span_week, RetentionSpan, "1W", [4, 1]);
128    case!(retention_span_month, RetentionSpan, "1M", [5, 1]);
129    case!(retention_span_year, RetentionSpan, "1Y", [6, 1]);
130
131    case!(retention_policy, RetentionPolicy, "1m:1m,1h:1h,1D:1D,1W:1W,1M:1M,1Y:1Y", [
132        1, 6,
133        1, 1, 1, 1,
134        2, 1, 2, 1,
135        3, 1, 3, 1,
136        4, 1, 4, 1,
137        5, 1, 5, 1,
138        6, 1, 6, 1
139    ]);
140
141    case!(retention_policy_u_u, RetentionPolicy, "U:U", [
142        1, 1,
143        0, 0
144    ]);
145
146    case!(retention_policy_u_1y, RetentionPolicy, "U:1Y", [
147        1, 1,
148        0, 6, 1
149    ]);
150}