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