Skip to main content

newtype_tools/
iter.rs

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