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}