mithril_client/cardano_database_client/
immutable_file_range.rs

1use std::ops::RangeInclusive;
2
3use anyhow::anyhow;
4
5use mithril_common::{entities::ImmutableFileNumber, StdResult};
6
7/// Immutable file range representation
8#[derive(Debug, Eq, PartialEq)]
9pub enum ImmutableFileRange {
10    /// From the first (included) to the last immutable file number (included)
11    Full,
12
13    /// From a specific immutable file number (included) to the last immutable file number (included)
14    From(ImmutableFileNumber),
15
16    /// From a specific immutable file number (included) to another specific immutable file number (included)
17    Range(ImmutableFileNumber, ImmutableFileNumber),
18
19    /// From the first immutable file number (included) up to a specific immutable file number (included)
20    UpTo(ImmutableFileNumber),
21}
22
23impl ImmutableFileRange {
24    /// Returns the range of immutable file numbers
25    pub fn to_range_inclusive(
26        &self,
27        last_immutable_file_number: ImmutableFileNumber,
28    ) -> StdResult<RangeInclusive<ImmutableFileNumber>> {
29        const FIRST_IMMUTABLE_FILE_NUMBER: ImmutableFileNumber = 0;
30        let full_range = FIRST_IMMUTABLE_FILE_NUMBER..=last_immutable_file_number;
31
32        match self {
33            ImmutableFileRange::Full => Ok(full_range),
34            ImmutableFileRange::From(from) if full_range.contains(from) => {
35                Ok(*from..=last_immutable_file_number)
36            }
37            ImmutableFileRange::Range(from, to)
38                if full_range.contains(from)
39                    && full_range.contains(to)
40                    && !(*from..=*to).is_empty() =>
41            {
42                Ok(*from..=*to)
43            }
44            ImmutableFileRange::UpTo(to) if full_range.contains(to) => {
45                Ok(FIRST_IMMUTABLE_FILE_NUMBER..=*to)
46            }
47            _ => Err(anyhow!("Invalid immutable file range: {self:?}")),
48        }
49    }
50
51    /// Returns the length of the immutable file range
52    pub fn length(&self, last_immutable_file_number: ImmutableFileNumber) -> u64 {
53        match self {
54            ImmutableFileRange::Full => last_immutable_file_number,
55            ImmutableFileRange::From(from) => last_immutable_file_number - from + 1,
56            ImmutableFileRange::Range(from, to) => to - from + 1,
57            ImmutableFileRange::UpTo(to) => *to,
58        }
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn to_range_inclusive_with_full() {
68        let immutable_file_range = ImmutableFileRange::Full;
69        let last_immutable_file_number = 10;
70
71        let result = immutable_file_range
72            .to_range_inclusive(last_immutable_file_number)
73            .unwrap();
74        assert_eq!(0..=10, result);
75    }
76
77    #[test]
78    fn to_range_inclusive_with_from() {
79        let immutable_file_range = ImmutableFileRange::From(5);
80
81        let last_immutable_file_number = 10;
82        let result = immutable_file_range
83            .to_range_inclusive(last_immutable_file_number)
84            .unwrap();
85        assert_eq!(5..=10, result);
86
87        let last_immutable_file_number = 3;
88        immutable_file_range
89            .to_range_inclusive(last_immutable_file_number)
90            .expect_err("should fail: given last immutable should be greater than range start");
91    }
92
93    #[test]
94    fn to_range_inclusive_with_range() {
95        let immutable_file_range = ImmutableFileRange::Range(5, 8);
96
97        let last_immutable_file_number = 10;
98        let result = immutable_file_range
99            .to_range_inclusive(last_immutable_file_number)
100            .unwrap();
101        assert_eq!(5..=8, result);
102
103        let last_immutable_file_number = 7;
104        immutable_file_range
105            .to_range_inclusive(last_immutable_file_number)
106            .expect_err(
107                "should fail: given last immutable should be greater or equal range max bound",
108            );
109
110        let immutable_file_range = ImmutableFileRange::Range(10, 8);
111        immutable_file_range
112            .to_range_inclusive(last_immutable_file_number)
113            .expect_err("should fail: range start should be lower than range end");
114    }
115
116    #[test]
117    fn to_range_inclusive_with_up_to() {
118        let immutable_file_range = ImmutableFileRange::UpTo(8);
119
120        let last_immutable_file_number = 10;
121        let result = immutable_file_range
122            .to_range_inclusive(last_immutable_file_number)
123            .unwrap();
124        assert_eq!(0..=8, result);
125
126        let last_immutable_file_number = 7;
127        immutable_file_range
128            .to_range_inclusive(last_immutable_file_number)
129            .expect_err(
130                "should fail: given last immutable should be greater or equal range max bound",
131            );
132    }
133
134    #[test]
135    fn length() {
136        let last_immutable_file_number = 10;
137
138        let immutable_file_range = ImmutableFileRange::Full;
139        assert_eq!(
140            last_immutable_file_number,
141            immutable_file_range.length(last_immutable_file_number)
142        );
143
144        let immutable_file_range = ImmutableFileRange::From(5);
145        assert_eq!(6, immutable_file_range.length(last_immutable_file_number));
146
147        let immutable_file_range = ImmutableFileRange::Range(5, 8);
148        assert_eq!(4, immutable_file_range.length(last_immutable_file_number));
149
150        let immutable_file_range = ImmutableFileRange::UpTo(8);
151        assert_eq!(8, immutable_file_range.length(last_immutable_file_number));
152    }
153}