1use crate::errors::FxfsError;
6use anyhow::{ensure, Error};
7use std::fmt::Debug;
8use std::ops::{Range, Rem, Sub};
9
10pub trait RangeExt<T> {
11 fn is_valid(&self) -> bool;
13 fn length(&self) -> Result<T, Error>;
17 fn is_aligned(&self, block_size: impl Into<T>) -> bool;
19
20 fn split(self, split_point: T) -> (Option<Range<T>>, Option<Range<T>>);
25}
26
27impl<T: Sub<Output = T> + Copy + Ord + Debug + Rem<Output = T> + PartialEq + Default> RangeExt<T>
28 for Range<T>
29{
30 fn is_valid(&self) -> bool {
31 self.start <= self.end
32 }
33 fn length(&self) -> Result<T, Error> {
34 ensure!(self.is_valid(), FxfsError::Inconsistent);
35 Ok(self.end - self.start)
36 }
37 fn is_aligned(&self, block_size: impl Into<T>) -> bool {
38 let bs = block_size.into();
39 self.start % bs == T::default() && self.end % bs == T::default()
40 }
41
42 fn split(self, split_point: T) -> (Option<Range<T>>, Option<Range<T>>) {
43 debug_assert!(!self.is_empty());
44 if split_point <= self.start {
45 (None, Some(self))
46 } else if split_point >= self.end {
47 (Some(self), None)
48 } else {
49 (Some(self.start..split_point), Some(split_point..self.end))
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::RangeExt;
57
58 #[test]
59 fn test_split_range() {
60 assert_eq!((10..20).split(0), (None, Some(10..20)));
61 assert_eq!((10..20).split(9), (None, Some(10..20)));
62 assert_eq!((10..20).split(10), (None, Some(10..20)));
63 assert_eq!((10..20).split(11), (Some(10..11), Some(11..20)));
64 assert_eq!((10..20).split(15), (Some(10..15), Some(15..20)));
65 assert_eq!((10..20).split(19), (Some(10..19), Some(19..20)));
66 assert_eq!((10..20).split(20), (Some(10..20), None));
67 assert_eq!((10..20).split(25), (Some(10..20), None));
68 }
69}