surrealdb_common/
range.rs1use std::cmp::Ordering;
7use std::ops::{Bound, RangeBounds};
8
9#[derive(Debug, Eq, PartialEq, Clone, Hash)]
12#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
13pub struct TypedRange<T> {
14 pub start: Bound<T>,
15 pub end: Bound<T>,
16}
17
18impl<T: PartialOrd> PartialOrd for TypedRange<T> {
19 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
20 fn compare_bounds<T: PartialOrd>(a: &Bound<T>, b: &Bound<T>) -> Option<Ordering> {
21 match a {
22 Bound::Unbounded => match b {
23 Bound::Unbounded => Some(Ordering::Equal),
24 _ => Some(Ordering::Less),
25 },
26 Bound::Included(a) => match b {
27 Bound::Unbounded => Some(Ordering::Greater),
28 Bound::Included(b) => a.partial_cmp(b),
29 Bound::Excluded(_) => Some(Ordering::Less),
30 },
31 Bound::Excluded(a) => match b {
32 Bound::Excluded(b) => a.partial_cmp(b),
33 _ => Some(Ordering::Greater),
34 },
35 }
36 }
37
38 match compare_bounds(&self.start, &other.start) {
39 Some(Ordering::Equal) => compare_bounds(&self.end, &other.end),
40 x => x,
41 }
42 }
43}
44
45impl<T: Clone> TypedRange<T> {
46 pub fn from_range<R: RangeBounds<T>>(r: R) -> Self {
47 TypedRange {
48 start: r.start_bound().map(|x| x.clone()),
49 end: r.end_bound().map(|x| x.clone()),
50 }
51 }
52}
53
54impl TypedRange<i64> {
55 pub fn iter(self) -> IntegerRangeIter {
57 let cur = match self.start {
58 Bound::Included(x) => x,
59 Bound::Excluded(x) => match x.checked_add(1) {
60 Some(x) => x,
61 None => {
63 return IntegerRangeIter {
64 cur: i64::MAX,
65 end: Some(i64::MIN),
66 };
67 }
68 },
69 Bound::Unbounded => i64::MIN,
70 };
71
72 match self.end {
73 Bound::Included(x) => IntegerRangeIter {
74 cur,
75 end: x.checked_add(1),
76 },
77 Bound::Excluded(x) => IntegerRangeIter {
78 cur,
79 end: Some(x),
80 },
81 Bound::Unbounded => IntegerRangeIter {
82 cur,
83 end: None,
84 },
85 }
86 }
87
88 pub fn slice<'a, T>(&self, s: &'a [T]) -> Option<&'a [T]> {
89 let r = match self.end {
90 Bound::Included(x) => s.get(..=(x as usize))?,
91 Bound::Excluded(x) => s.get(..(x as usize))?,
92 Bound::Unbounded => s,
93 };
94 match self.start {
95 Bound::Included(x) => r.get((x as usize)..),
96 Bound::Excluded(x) => {
97 let x = (x as usize).checked_add(1)?;
98 r.get(x..)
99 }
100 Bound::Unbounded => Some(r),
101 }
102 }
103
104 pub fn slice_mut<'a, T>(&self, s: &'a mut [T]) -> Option<&'a mut [T]> {
105 let r = match self.end {
106 Bound::Included(x) => s.get_mut(..=(x as usize))?,
107 Bound::Excluded(x) => s.get_mut(..(x as usize))?,
108 Bound::Unbounded => s,
109 };
110 match self.start {
111 Bound::Included(x) => r.get_mut((x as usize)..),
112 Bound::Excluded(x) => {
113 let x = (x as usize).checked_add(1)?;
114 r.get_mut(x..)
115 }
116 Bound::Unbounded => Some(r),
117 }
118 }
119
120 #[allow(clippy::len_without_is_empty)]
123 pub fn len(&self) -> Option<usize> {
124 let end = match self.end {
125 Bound::Unbounded => return None,
126 Bound::Included(x) => x,
127 Bound::Excluded(x) => match x.checked_sub(1) {
128 Some(x) => x,
129 None => return Some(0),
130 },
131 };
132
133 let start = match self.start {
134 Bound::Unbounded => return None,
135 Bound::Included(x) => x,
136 Bound::Excluded(x) => match x.checked_add(1) {
137 Some(x) => x,
138 None => return Some(0),
139 },
140 };
141
142 if start > end {
143 return Some(0);
144 }
145
146 usize::try_from(start.abs_diff(end)).ok()
147 }
148}
149
150pub struct IntegerRangeIter {
152 cur: i64,
153 end: Option<i64>,
157}
158
159impl Iterator for IntegerRangeIter {
160 type Item = i64;
161
162 fn next(&mut self) -> Option<i64> {
163 let cur = self.cur;
164 if let Some(end) = self.end
165 && cur >= end
166 {
167 return None;
168 }
169 if let Some(x) = cur.checked_add(1) {
170 self.cur = x
171 } else {
172 self.end = Some(i64::MIN)
174 }
175
176 Some(cur)
177 }
178
179 fn size_hint(&self) -> (usize, Option<usize>) {
180 let len = if let Some(x) = self.end {
181 if self.cur >= x {
182 return (0, Some(0));
183 }
184 self.cur.abs_diff(x) - 1
185 } else {
186 self.cur.abs_diff(i64::MAX)
187 };
188 let upper: Option<usize> = len.try_into().ok();
190 (upper.unwrap_or(usize::MAX), upper)
191 }
192}