Skip to main content

interval_rbtree/
range.rs

1use std::{
2    cmp::Ordering,
3    fmt::Debug,
4    ops::{Bound, Range, RangeBounds},
5};
6
7/// a half-open interval in ℕ, [start, end)
8#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
9pub struct TextRange {
10    pub start: usize,
11    pub end: usize,
12}
13
14impl Ord for TextRange {
15    fn cmp(&self, other: &Self) -> Ordering {
16        match self.start.cmp(&other.start) {
17            Ordering::Less => Ordering::Less,
18            Ordering::Equal => self.end.cmp(&other.end),
19            Ordering::Greater => Ordering::Greater,
20        }
21    }
22}
23
24impl RangeBounds<usize> for TextRange {
25    fn start_bound(&self) -> Bound<&usize> {
26        Bound::Included(&self.start)
27    }
28
29    fn end_bound(&self) -> Bound<&usize> {
30        Bound::Excluded(&self.start)
31    }
32}
33
34impl<T: Into<usize>> From<Range<T>> for TextRange {
35    fn from(range: Range<T>) -> Self {
36        Self {
37            start: range.start.into(),
38            end: range.end.into(),
39        }
40    }
41}
42impl<T: Into<usize>> From<(T, T)> for TextRange {
43    fn from((start, end): (T, T)) -> Self {
44        Self {
45            start: start.into(),
46            end: end.into(),
47        }
48    }
49}
50
51impl TextRange {
52    /// caller should check that start < end
53    pub fn new(start: usize, end: usize) -> Self {
54        if start <= end {
55            Self { start, end }
56        } else {
57            Self {
58                start: end,
59                end: start,
60            }
61        }
62    }
63
64    pub fn as_range(&self) -> Range<usize> {
65        self.start..self.end
66    }
67
68    pub fn contains(&self, pos: usize) -> bool {
69        self.start <= pos && pos < self.end
70    }
71
72    pub fn strict_order(&self, other: &Self) -> Option<Ordering> {
73        if self.end <= other.start {
74            return Some(Ordering::Less);
75        }
76        if self.start >= other.end {
77            return Some(Ordering::Greater);
78        }
79        None
80    }
81    /// split self, return the split out interval.
82    /// if `left` is true, the left part is split out and returned.
83    /// This function does not check whether `position` is valid.
84    pub fn split_at(&mut self, position: usize, left: bool) -> Self {
85        if left {
86            let start = self.start;
87            self.start = position;
88            Self::new(start, position)
89        } else {
90            let end = self.end;
91            self.end = position;
92            Self::new(position, end)
93        }
94    }
95
96    pub fn intersects(&self, other: Self) -> bool {
97        self.end > other.start && self.start < other.end
98    }
99    pub fn intersection_uncheck(&self, other: Self) -> Self {
100        Self::new(self.start.max(other.start), self.end.min(other.end))
101    }
102    pub fn intersection(&self, other: Self) -> Option<Self> {
103        self.intersects(other)
104            .then(|| self.intersection_uncheck(other))
105    }
106
107    pub fn advance(&mut self, offset: usize) {
108        self.start += offset;
109        self.end += offset;
110    }
111    pub fn move_back(&self, offset: usize) -> Self {
112        Self::new(self.start + offset, self.end + offset)
113    }
114}