ps_range/
partial_range.rs1use std::mem;
2
3use num_traits::{CheckedAdd, One, Zero};
4
5use crate::{Range, RangeEnd, RangeStart};
6
7#[derive(Clone, Debug, Hash, PartialEq, Eq)]
25pub enum PartialRange<Idx> {
26 Empty {
28 idx: Idx,
30 },
31 Exhausted,
33 From {
35 inner: std::ops::RangeFrom<Idx>,
37 },
38 Inclusive {
40 start: Idx,
42 end: Idx,
44 },
45 Exclusive {
47 inner: std::ops::Range<Idx>,
49 },
50}
51
52impl<Idx: Clone + Zero> RangeStart<Idx> for PartialRange<Idx> {
53 #[inline]
54 fn start(&self) -> Idx {
55 match self {
56 Self::Empty { idx } => idx.clone(),
57 Self::Exhausted => Idx::zero(),
58 Self::From { inner } => inner.start.clone(),
59 Self::Inclusive { start, .. } => start.clone(),
60 Self::Exclusive { inner } => inner.start.clone(),
61 }
62 }
63}
64
65impl<Idx: Clone + Ord + Zero> crate::PartialRangeExt<Idx> for PartialRange<Idx> {
66 #[inline]
67 fn end_bound(&self) -> Option<RangeEnd<Idx>> {
68 match self {
69 Self::Empty { idx } => Some(RangeEnd::Exclusive(idx.clone())),
70 Self::Exhausted => Some(RangeEnd::Exclusive(Idx::zero())),
71 Self::From { .. } => None,
72 Self::Inclusive { end, .. } => Some(RangeEnd::Inclusive(end.clone())),
73 Self::Exclusive { inner } => Some(RangeEnd::Exclusive(inner.end.clone())),
74 }
75 }
76}
77
78impl<Idx> Iterator for PartialRange<Idx>
92where
93 Idx: CheckedAdd + Clone + One + PartialOrd,
94{
95 type Item = Idx;
96
97 fn next(&mut self) -> Option<Self::Item> {
98 match self {
99 Self::Exhausted => None,
100
101 Self::Empty { .. } => {
102 *self = Self::Exhausted;
103
104 None
105 }
106
107 Self::From { inner } => match inner.start.checked_add(&Idx::one()) {
108 Some(next) if next > inner.start => Some(mem::replace(&mut inner.start, next)),
109 _ => {
110 let last = inner.start.clone();
111
112 *self = Self::Exhausted;
113
114 Some(last)
115 }
116 },
117
118 Self::Inclusive { start, end } => {
119 if *start <= *end {
120 match start.checked_add(&Idx::one()) {
121 Some(next) if next > *start && next <= *end => {
122 Some(mem::replace(start, next))
123 }
124 _ => {
125 let last = start.clone();
126
127 *self = Self::Exhausted;
128
129 Some(last)
130 }
131 }
132 } else {
133 *self = Self::Exhausted;
134
135 None
136 }
137 }
138
139 Self::Exclusive { inner } => {
140 if inner.start < inner.end {
141 match inner.start.checked_add(&Idx::one()) {
142 Some(next) if next > inner.start && next < inner.end => {
143 Some(mem::replace(&mut inner.start, next))
144 }
145 _ => {
146 let last = inner.start.clone();
147
148 *self = Self::Exhausted;
149
150 Some(last)
151 }
152 }
153 } else {
154 *self = Self::Exhausted;
155
156 None
157 }
158 }
159 }
160 }
161
162 fn size_hint(&self) -> (usize, Option<usize>) {
163 match self {
164 Self::Empty { .. } | Self::Exhausted => (0, Some(0)),
165
166 Self::From { .. } => (1, None),
167
168 Self::Inclusive { start, end } => {
169 if *start <= *end {
170 (1, None)
171 } else {
172 (0, Some(0))
173 }
174 }
175
176 Self::Exclusive { inner } => {
177 if inner.start < inner.end {
178 (1, None)
179 } else {
180 (0, Some(0))
181 }
182 }
183 }
184 }
185}
186
187impl<Idx> std::iter::FusedIterator for PartialRange<Idx> where
188 Idx: CheckedAdd + Clone + One + PartialOrd
189{
190}
191
192impl<Idx> From<std::ops::Range<Idx>> for PartialRange<Idx> {
193 #[inline]
194 fn from(value: std::ops::Range<Idx>) -> Self {
195 Self::Exclusive { inner: value }
196 }
197}
198
199impl<Idx> From<std::ops::RangeFrom<Idx>> for PartialRange<Idx> {
200 #[inline]
201 fn from(value: std::ops::RangeFrom<Idx>) -> Self {
202 Self::From { inner: value }
203 }
204}
205
206impl<Idx: PartialOrd> From<std::ops::RangeInclusive<Idx>> for PartialRange<Idx> {
212 #[inline]
213 fn from(value: std::ops::RangeInclusive<Idx>) -> Self {
214 let empty = value.is_empty();
215 let (start, end) = value.into_inner();
216
217 if empty {
218 Self::Empty { idx: start }
219 } else {
220 Self::Inclusive { start, end }
221 }
222 }
223}
224
225impl<Idx> From<Range<Idx>> for PartialRange<Idx> {
226 #[inline]
227 fn from(value: Range<Idx>) -> Self {
228 match value.end {
229 RangeEnd::Inclusive(end) => Self::Inclusive {
230 start: value.start,
231 end,
232 },
233 RangeEnd::Exclusive(end) => Self::Exclusive {
234 inner: value.start..end,
235 },
236 }
237 }
238}
239
240impl<Idx> IntoIterator for Range<Idx>
241where
242 Idx: CheckedAdd + Clone + One + PartialOrd,
243{
244 type Item = Idx;
245 type IntoIter = PartialRange<Idx>;
246
247 #[inline]
248 fn into_iter(self) -> Self::IntoIter {
249 self.into()
250 }
251}