1use core::{
2 cmp::Ordering,
3 fmt,
4 ops::{Add, AddAssign, Bound, Index, IndexMut, RangeBounds, Sub},
5};
6
7pub trait NumericRangeBound:
8 Add<Output = Self> + AddAssign + Sub<Output = Self> + Copy + PartialEq + Ord
9{
10 const ZERO: Self;
11 const ONE: Self;
12
13 fn saturating_sub(self, rhs: Self) -> Self;
14}
15
16macro_rules! numeric_bound_impl {
17 ($type:ty) => {
18 impl NumericRangeBound for $type {
19 const ZERO: Self = 0;
20 const ONE: Self = 0;
21
22 #[inline(always)]
23 fn saturating_sub(self, rhs: Self) -> Self {
24 <$type>::saturating_sub(self, rhs)
25 }
26 }
27 };
28}
29
30numeric_bound_impl!(usize);
31numeric_bound_impl!(u8);
32numeric_bound_impl!(u16);
33numeric_bound_impl!(u32);
34numeric_bound_impl!(u64);
35
36pub struct Range<T> {
37 pub start: T,
38 pub end: T,
39}
40impl<T: fmt::Debug> fmt::Debug for Range<T> {
41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42 f.debug_struct("Range")
43 .field("start", &self.start)
44 .field("end", &self.end)
45 .finish()
46 }
47}
48impl<T: fmt::Display> fmt::Display for Range<T> {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 write!(f, "{}..{}", &self.start, &self.end)
51 }
52}
53impl<T> core::ops::RangeBounds<T> for Range<T> {
54 #[inline]
55 fn start_bound(&self) -> Bound<&T> {
56 Bound::Included(&self.start)
57 }
58 #[inline]
59 fn end_bound(&self) -> Bound<&T> {
60 Bound::Excluded(&self.end)
61 }
62}
63impl<T: PartialOrd + fmt::Debug> Range<T> {
64 pub fn new(start: T, end: T) -> Self {
65 assert!(
66 start <= end,
67 "invalid range: start {:?} must not be larger than end {:?}",
68 start,
69 end,
70 );
71 Self { start, end }
72 }
73}
74impl<T: PartialOrd> Range<T> {
75 #[inline]
76 pub fn is_empty(&self) -> bool {
77 !matches!(self.start.partial_cmp(&self.end), Some(Ordering::Less))
78 }
79
80 #[inline]
81 pub fn contains<U>(&self, item: &U) -> bool
82 where
83 T: PartialOrd<U>,
84 U: PartialOrd<T> + ?Sized,
85 {
86 <Self as core::ops::RangeBounds<T>>::contains(self, item)
87 }
88}
89impl<T: NumericRangeBound> Range<T> {
90 #[inline(always)]
91 pub fn len(&self) -> T {
92 self.end - self.start
93 }
94
95 #[inline]
97 pub fn pop_front(&mut self) -> Option<T> {
98 let item = self.start;
99 let next = item + <T as NumericRangeBound>::ONE;
100 if next <= self.end {
101 self.start = next;
102 Some(item)
103 } else {
104 None
105 }
106 }
107
108 #[inline]
110 pub fn pop_back(&mut self) -> Option<T> {
111 if self.start == self.end {
112 None
113 } else {
114 let item = self.end.saturating_sub(<T as NumericRangeBound>::ONE);
115 self.end = item;
116 Some(item)
117 }
118 }
119
120 #[inline]
124 pub fn shrink_front(&mut self, n: T) {
125 self.start = core::cmp::min(self.start + n, self.end);
126 }
127
128 #[inline]
134 pub fn truncate(&mut self, new_len: T) {
135 assert!(self.len() > new_len);
136 self.end = self.start + new_len;
137 }
138}
139impl<T: Copy> Copy for Range<T> {}
140impl<T: Clone> Clone for Range<T> {
141 fn clone(&self) -> Self {
142 Self {
143 start: self.start.clone(),
144 end: self.end.clone(),
145 }
146 }
147}
148impl<T: Eq> Eq for Range<T> {}
149impl<T: PartialEq> PartialEq for Range<T> {
150 fn eq(&self, other: &Self) -> bool {
151 self.start.eq(&other.start) && self.end.eq(&other.end)
152 }
153}
154impl<T: PartialOrd> PartialOrd for Range<T> {
155 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
156 self.start.partial_cmp(&other.start).and_then(|o| match o {
157 Ordering::Equal => self.end.partial_cmp(&other.end),
158 o => Some(o),
159 })
160 }
161}
162impl<T: Ord> Ord for Range<T> {
163 fn cmp(&self, other: &Self) -> Ordering {
164 self.start
165 .cmp(&other.start)
166 .then_with(|| self.end.cmp(&other.end))
167 }
168}
169impl From<crate::diagnostics::SourceSpan> for Range<usize> {
170 #[inline]
171 fn from(span: crate::diagnostics::SourceSpan) -> Self {
172 let offset = span.offset();
173 Self::new(offset, offset + span.len())
174 }
175}
176impl From<Range<usize>> for crate::diagnostics::SourceSpan {
177 #[inline]
178 fn from(range: Range<usize>) -> Self {
179 crate::diagnostics::SourceSpan::from(range.start..range.end)
180 }
181}
182impl<T: NumericRangeBound> From<core::ops::Range<T>> for Range<T> {
183 #[inline(always)]
184 fn from(range: core::ops::Range<T>) -> Self {
185 debug_assert!(
186 range.end >= range.start,
187 "invalid range: start must not pass end"
188 );
189 Self {
190 start: range.start,
191 end: range.end,
192 }
193 }
194}
195impl<T: NumericRangeBound> From<Range<T>> for core::ops::Range<T> {
196 #[inline(always)]
197 fn from(range: Range<T>) -> core::ops::Range<T> {
198 range.start..range.end
199 }
200}
201impl<T> Index<Range<usize>> for [T] {
202 type Output = [T];
203
204 #[inline(always)]
205 fn index(&self, idx: Range<usize>) -> &Self::Output {
206 <[T] as Index<core::ops::Range<usize>>>::index(self, idx.start..idx.end)
207 }
208}
209impl<T> IndexMut<Range<usize>> for [T] {
210 #[inline(always)]
211 fn index_mut(&mut self, idx: Range<usize>) -> &mut Self::Output {
212 <[T] as IndexMut<core::ops::Range<usize>>>::index_mut(self, idx.start..idx.end)
213 }
214}
215
216pub fn range_from_bounds<R: RangeBounds<usize>>(
217 range: R,
218 allowed: Range<usize>,
219) -> Result<Range<usize>, Range<usize>> {
220 let start = match range.start_bound() {
221 Bound::Included(&i) => i,
222 Bound::Excluded(&i) => i + 1,
223 Bound::Unbounded => allowed.start,
224 };
225 let end = match range.end_bound() {
226 Bound::Included(&i) => i + 1,
227 Bound::Excluded(&i) => i,
228 Bound::Unbounded => allowed.end,
229 };
230 if start < allowed.start || end > allowed.end {
231 Err(Range::new(start, end))
232 } else {
233 Ok(Range::new(start, end))
234 }
235}
236
237pub fn range_from_bounds_with_defaults<R: RangeBounds<usize>>(
238 range: R,
239 default_start: usize,
240 default_end: usize,
241) -> Range<usize> {
242 let start = match range.start_bound() {
243 Bound::Included(&i) => i,
244 Bound::Excluded(&i) => i + 1,
245 Bound::Unbounded => default_start,
246 };
247 let end = match range.end_bound() {
248 Bound::Included(&i) => i + 1,
249 Bound::Excluded(&i) => i,
250 Bound::Unbounded => default_end,
251 };
252 Range::new(start, end)
253}