newtype_tools/iter.rs
1/// Blanket `Step` implementation for all `Newtype`s.
2impl<T> Step for T
3where
4 T: crate::Newtype + Clone + PartialOrd + MinMax,
5 T::Inner: Step,
6{
7 #[inline]
8 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
9 <T::Inner as Step>::steps_between(start.as_ref(), end.as_ref())
10 }
11
12 #[inline]
13 fn forward_checked(start: Self, count: usize) -> Option<Self> {
14 <T::Inner as Step>::forward_checked(start.as_ref().clone(), count).map(T::from)
15 }
16
17 #[inline]
18 fn backward_checked(start: Self, count: usize) -> Option<Self> {
19 <T::Inner as Step>::backward_checked(start.as_ref().clone(), count).map(Self::from)
20 }
21}
22
23/// Blanket `Iterator` implementation for all `Newtype`s.
24#[derive(Clone)]
25pub struct Iterator<T>
26where
27 T: crate::Newtype,
28{
29 start: T::Inner,
30 last: T::Inner,
31}
32
33impl<T> Iterator<T>
34where
35 T: crate::Newtype,
36 T::Inner: Step,
37{
38 /// Returns `true` if the iterator is empty.
39 #[inline]
40 pub fn is_empty(&self) -> bool {
41 self.start > self.last
42 }
43
44 /// Creates a new `Iterator` instance based on the given range.
45 /// The internal `Newtype` representation must implement `Step` trait.
46 ///
47 /// # Example
48 /// ```
49 /// # #[cfg(feature = "derive")]
50 /// # {
51 /// #[derive(Debug, newtype_tools::Newtype, PartialEq)]
52 /// struct Apples(u64);
53 /// let range = Apples(1)..Apples(3);
54 /// let mut iter = newtype_tools::Iterator::from(&range);
55 /// assert_eq!(iter.len(), 2);
56 /// assert_eq!(iter.next(), Some(Apples(1)));
57 /// assert_eq!(iter.next(), Some(Apples(2)));
58 /// assert_eq!(iter.next(), None);
59 /// # }
60 /// ```
61 #[inline]
62 pub fn from<R: std::ops::RangeBounds<T>>(range: &R) -> Self {
63 use crate::iter::Step;
64 use std::ops::Bound;
65 let start = match range.start_bound() {
66 Bound::Included(s) => s.as_ref().clone(),
67 Bound::Excluded(s) => Step::forward(s.as_ref().clone(), 1),
68 Bound::Unbounded => T::Inner::MIN,
69 };
70 let last = match range.end_bound() {
71 Bound::Included(e) => e.as_ref().clone(),
72 Bound::Excluded(e) => Step::backward(e.as_ref().clone(), 1),
73 Bound::Unbounded => T::Inner::MAX,
74 };
75 Self { start, last }
76 }
77}
78
79impl<T> std::iter::Iterator for Iterator<T>
80where
81 T: crate::Newtype + From<T::Inner>,
82 T::Inner: Step + std::fmt::Debug,
83{
84 type Item = T;
85
86 #[inline]
87 fn next(&mut self) -> Option<Self::Item> {
88 if Iterator::is_empty(self) {
89 return None;
90 }
91
92 let next = crate::iter::Step::forward_checked(self.start.clone(), 1)?;
93 Some(T::from(core::mem::replace(&mut self.start, next)))
94 }
95
96 #[inline]
97 fn size_hint(&self) -> (usize, Option<usize>) {
98 if self.is_empty() {
99 return (0, Some(0));
100 }
101
102 let hint = Step::steps_between(&self.start, &self.last);
103 (
104 hint.0.saturating_add(1),
105 hint.1.and_then(|steps| steps.checked_add(1)),
106 )
107 }
108
109 #[inline]
110 fn count(self) -> usize {
111 if self.is_empty() {
112 return 0;
113 }
114
115 crate::iter::Step::steps_between(&self.start, &self.last)
116 .1
117 .and_then(|steps| steps.checked_add(1))
118 .expect("count overflowed usize")
119 }
120
121 #[inline]
122 fn is_sorted(self) -> bool {
123 true
124 }
125}
126
127impl<T> DoubleEndedIterator for Iterator<T>
128where
129 T: crate::Newtype + From<T::Inner>,
130 T::Inner: Step + std::fmt::Debug,
131{
132 fn next_back(&mut self) -> Option<Self::Item> {
133 if Iterator::is_empty(self) {
134 return None;
135 }
136 let next = crate::iter::Step::backward_checked(self.last.clone(), 1)?;
137 Some(T::from(core::mem::replace(&mut self.last, next)))
138 }
139}
140
141impl<T> ExactSizeIterator for Iterator<T>
142where
143 T: crate::Newtype + From<T::Inner>,
144 T::Inner: Step + std::fmt::Debug,
145{
146}
147
148impl<T> std::iter::FusedIterator for Iterator<T>
149where
150 T: crate::Newtype + From<T::Inner>,
151 T::Inner: Step + std::fmt::Debug,
152{
153}
154
155////////////////////////////////////////////////////////////////////////
156// The following complexity should go away once the `Step` trait is stable.
157// Mostly it's a copy-paste from the unstable `std::iter::Step` trait.
158
159/// A helper trait to support inner values ranges.
160pub trait MinMax {
161 const MAX: Self;
162 const MIN: Self;
163}
164
165macro_rules! impl_min_max {
166 ($($t:ty),*) => {
167 $(
168 impl MinMax for $t {
169 const MAX: Self = <$t>::MAX;
170 const MIN: Self = <$t>::MIN;
171 }
172 )+
173 };
174}
175
176impl_min_max!(
177 u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize
178);
179
180/// A copy of the unstable `std::iter::Step` trait required for the `iter`
181/// derive.
182pub trait Step: Clone + PartialOrd + MinMax + Sized {
183 /// Returns the bounds on the number of *successor* steps required to get from `start` to `end`
184 /// like [`Iterator::size_hint()`][Iterator::size_hint()].
185 ///
186 /// Returns `(usize::MAX, None)` if the number of steps would overflow `usize`, or is infinite.
187 ///
188 /// # Invariants
189 ///
190 /// For any `a`, `b`, and `n`:
191 ///
192 /// * `steps_between(&a, &b) == (n, Some(n))` \
193 /// if and only if `Step::forward_checked(&a, n) == Some(b)`
194 /// * `steps_between(&a, &b) == (n, Some(n))` \
195 /// if and only if `Step::backward_checked(&b, n) == Some(a)`
196 /// * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b`
197 /// * Corollary: `steps_between(&a, &b) == (0, Some(0))` if and only if `a == b`
198 /// * `steps_between(&a, &b) == (0, None)` if `a > b`
199 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>);
200
201 /// Returns the value that would be obtained by taking the *successor*
202 /// of `self` `count` times.
203 ///
204 /// If this would overflow the range of values supported by `Self`, returns `None`.
205 ///
206 /// # Invariants
207 ///
208 /// For any `a`, `n`, and `m`:
209 ///
210 /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) \
211 /// == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))`
212 /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) \
213 /// == try { Step::forward_checked(a, n.checked_add(m)) }`
214 ///
215 /// For any `a` and `n`:
216 ///
217 /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
218 /// * Corollary: `Step::forward_checked(a, 0) == Some(a)`
219 fn forward_checked(start: Self, count: usize) -> Option<Self>;
220
221 /// Returns the value that would be obtained by taking the *successor*
222 /// of `self` `count` times.
223 ///
224 /// If this would overflow the range of values supported by `Self`,
225 /// this function is allowed to panic, wrap, or saturate.
226 /// The suggested behavior is to panic when debug assertions are enabled,
227 /// and to wrap or saturate otherwise.
228 ///
229 /// # Invariants
230 ///
231 /// For any `a`, `n`, and `m`, where no overflow occurs:
232 ///
233 /// * `Step::forward(Step::forward(a, n), m) == Step::forward(a, n + m)`
234 ///
235 /// For any `a` and `n`, where no overflow occurs:
236 ///
237 /// * `Step::forward_checked(a, n) == Some(Step::forward(a, n))`
238 /// * `Step::forward(a, n) == (0..n).fold(a, |x, _| Step::forward(x, 1))`
239 /// * Corollary: `Step::forward(a, 0) == a`
240 /// * `Step::forward(a, n) >= a`
241 /// * `Step::backward(Step::forward(a, n), n) == a`
242 fn forward(start: Self, count: usize) -> Self {
243 Step::forward_checked(start, count).expect("overflow in `Step::forward`")
244 }
245
246 /// Returns the value that would be obtained by taking the *predecessor*
247 /// of `self` `count` times.
248 ///
249 /// If this would overflow the range of values supported by `Self`, returns `None`.
250 ///
251 /// # Invariants
252 ///
253 /// For any `a`, `n`, and `m`:
254 ///
255 /// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) \
256 /// == n.checked_add(m).and_then(|x| Step::backward_checked(a, x))`
257 /// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) \
258 /// == try { Step::backward_checked(a, n.checked_add(m)?) }`
259 ///
260 /// For any `a` and `n`:
261 ///
262 /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(x, 1))`
263 /// * Corollary: `Step::backward_checked(a, 0) == Some(a)`
264 fn backward_checked(start: Self, count: usize) -> Option<Self>;
265
266 /// Returns the value that would be obtained by taking the *predecessor*
267 /// of `self` `count` times.
268 ///
269 /// If this would overflow the range of values supported by `Self`,
270 /// this function is allowed to panic, wrap, or saturate.
271 /// The suggested behavior is to panic when debug assertions are enabled,
272 /// and to wrap or saturate otherwise.
273 ///
274 /// # Invariants
275 ///
276 /// For any `a`, `n`, and `m`, where no overflow occurs:
277 ///
278 /// * `Step::backward(Step::backward(a, n), m) == Step::backward(a, n + m)`
279 ///
280 /// For any `a` and `n`, where no overflow occurs:
281 ///
282 /// * `Step::backward_checked(a, n) == Some(Step::backward(a, n))`
283 /// * `Step::backward(a, n) == (0..n).fold(a, |x, _| Step::backward(x, 1))`
284 /// * Corollary: `Step::backward(a, 0) == a`
285 /// * `Step::backward(a, n) <= a`
286 /// * `Step::forward(Step::backward(a, n), n) == a`
287 fn backward(start: Self, count: usize) -> Self {
288 Step::backward_checked(start, count).expect("overflow in `Step::backward`")
289 }
290}
291
292// These are still macro-generated because the integer literals resolve to different types.
293macro_rules! step_identical_methods {
294 () => {
295 #[inline]
296 #[allow(arithmetic_overflow)]
297 fn forward(start: Self, n: usize) -> Self {
298 // In debug builds, trigger a panic on overflow.
299 // This should optimize completely out in release builds.
300 if Self::forward_checked(start, n).is_none() {
301 let _ = Self::MAX + 1;
302 }
303 // Do wrapping math to allow e.g. `Step::forward(-128i8, 255)`.
304 start.wrapping_add(n as Self)
305 }
306
307 #[inline]
308 #[allow(arithmetic_overflow)]
309 fn backward(start: Self, n: usize) -> Self {
310 // In debug builds, trigger a panic on overflow.
311 // This should optimize completely out in release builds.
312 if Self::backward_checked(start, n).is_none() {
313 let _ = Self::MIN - 1;
314 }
315 // Do wrapping math to allow e.g. `Step::backward(127i8, 255)`.
316 start.wrapping_sub(n as Self)
317 }
318 };
319}
320
321macro_rules! step_integer_impls {
322 {
323 [ $( [ $u_narrower:ident $i_narrower:ident ] ),+ ] <= usize <
324 [ $( [ $u_wider:ident $i_wider:ident ] ),+ ]
325 } => {
326 $(
327 #[allow(unreachable_patterns)]
328 impl Step for $u_narrower {
329 step_identical_methods!();
330
331 #[inline]
332 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
333 if *start <= *end {
334 // This relies on $u_narrower <= usize
335 let steps = (*end - *start) as usize;
336 (steps, Some(steps))
337 } else {
338 (0, None)
339 }
340 }
341
342 #[inline]
343 fn forward_checked(start: Self, n: usize) -> Option<Self> {
344 match Self::try_from(n) {
345 Ok(n) => start.checked_add(n),
346 Err(_) => None, // if n is out of range, `unsigned_start + n` is too
347 }
348 }
349
350 #[inline]
351 fn backward_checked(start: Self, n: usize) -> Option<Self> {
352 match Self::try_from(n) {
353 Ok(n) => start.checked_sub(n),
354 Err(_) => None, // if n is out of range, `unsigned_start - n` is too
355 }
356 }
357 }
358
359 #[allow(unreachable_patterns)]
360 impl Step for $i_narrower {
361 step_identical_methods!();
362
363 #[inline]
364 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
365 if *start <= *end {
366 // This relies on $i_narrower <= usize
367 //
368 // Casting to isize extends the width but preserves the sign.
369 // Use wrapping_sub in isize space and cast to usize to compute
370 // the difference that might not fit inside the range of isize.
371 let steps = (*end as isize).wrapping_sub(*start as isize) as usize;
372 (steps, Some(steps))
373 } else {
374 (0, None)
375 }
376 }
377
378 #[inline]
379 fn forward_checked(start: Self, n: usize) -> Option<Self> {
380 match $u_narrower::try_from(n) {
381 Ok(n) => {
382 // Wrapping handles cases like
383 // `Step::forward(-120_i8, 200) == Some(80_i8)`,
384 // even though 200 is out of range for i8.
385 let wrapped = start.wrapping_add(n as Self);
386 if wrapped >= start {
387 Some(wrapped)
388 } else {
389 None // Addition overflowed
390 }
391 }
392 // If n is out of range of e.g. u8,
393 // then it is bigger than the entire range for i8 is wide
394 // so `any_i8 + n` necessarily overflows i8.
395 Err(_) => None,
396 }
397 }
398
399 #[inline]
400 fn backward_checked(start: Self, n: usize) -> Option<Self> {
401 match $u_narrower::try_from(n) {
402 Ok(n) => {
403 // Wrapping handles cases like
404 // `Step::forward(-120_i8, 200) == Some(80_i8)`,
405 // even though 200 is out of range for i8.
406 let wrapped = start.wrapping_sub(n as Self);
407 if wrapped <= start {
408 Some(wrapped)
409 } else {
410 None // Subtraction overflowed
411 }
412 }
413 // If n is out of range of e.g. u8,
414 // then it is bigger than the entire range for i8 is wide
415 // so `any_i8 - n` necessarily overflows i8.
416 Err(_) => None,
417 }
418 }
419 }
420 )+
421
422 $(
423 #[allow(unreachable_patterns)]
424 impl Step for $u_wider {
425 step_identical_methods!();
426
427 #[inline]
428 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
429 if *start <= *end {
430 if let Ok(steps) = usize::try_from(*end - *start) {
431 (steps, Some(steps))
432 } else {
433 (usize::MAX, None)
434 }
435 } else {
436 (0, None)
437 }
438 }
439
440 #[inline]
441 fn forward_checked(start: Self, n: usize) -> Option<Self> {
442 start.checked_add(n as Self)
443 }
444
445 #[inline]
446 fn backward_checked(start: Self, n: usize) -> Option<Self> {
447 start.checked_sub(n as Self)
448 }
449 }
450
451 #[allow(unreachable_patterns)]
452 impl Step for $i_wider {
453 step_identical_methods!();
454
455 #[inline]
456 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
457 if *start <= *end {
458 match end.checked_sub(*start) {
459 Some(result) => {
460 if let Ok(steps) = usize::try_from(result) {
461 (steps, Some(steps))
462 } else {
463 (usize::MAX, None)
464 }
465 }
466 // If the difference is too big for e.g. i128,
467 // it's also gonna be too big for usize with fewer bits.
468 None => (usize::MAX, None),
469 }
470 } else {
471 (0, None)
472 }
473 }
474
475 #[inline]
476 fn forward_checked(start: Self, n: usize) -> Option<Self> {
477 start.checked_add(n as Self)
478 }
479
480 #[inline]
481 fn backward_checked(start: Self, n: usize) -> Option<Self> {
482 start.checked_sub(n as Self)
483 }
484 }
485 )+
486 };
487}
488
489#[cfg(target_pointer_width = "64")]
490step_integer_impls! {
491 [ [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize] ] <= usize < [ [u128 i128] ]
492}
493
494#[cfg(target_pointer_width = "32")]
495step_integer_impls! {
496 [ [u8 i8], [u16 i16], [u32 i32], [usize isize] ] <= usize < [ [u64 i64], [u128 i128] ]
497}
498
499#[cfg(target_pointer_width = "16")]
500step_integer_impls! {
501 [ [u8 i8], [u16 i16], [usize isize] ] <= usize < [ [u32 i32], [u64 i64], [u128 i128] ]
502}