Skip to main content

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}