iter_utils/
perpetuity.rs

1//! Provides a trait similar to the standard [`Iterator`], but for sequences
2//! that never terminate. In particular, [`Perpetuity::next_item`] returns
3//! `Self::Item`, not `Option<Self::Item>`.  The interface to functions like
4//! `successors` can also be much simpler, as neither the initial value
5//! nor the callback need deal with options.  For example, compare the following
6//! two expressions:
7//!
8//! ```ignore
9//! use std::iter;
10//! use iter_utils::Perpetuity;
11//!
12//! let powers_of_two = iter::successors(Some(1), |a| Some(a * 2));
13//! let powers_of_two = iter_utils::successors(1, |a| a * 2);
14//! ```
15//!
16//! One common form of infinite range is sequences of IDs.  For example:
17//!
18//! ```ignore
19//! let mut ids = 1..;
20//! let thing1 = Thing { id: ids.next().unwrap() };
21//! let thing2 = Thing { id: ids.next().unwrap() };
22//! // ...
23//! ```
24//!
25//! Using Perpetuity, we no longer need to unwrap anything:
26//!
27//! ```ignore
28//! use iter_utils::Perpetuity;
29//!
30//! let mut ids = 1..;
31//! let thing1 = Thing { id: ids.next_item() };
32//! let thing2 = Thing { id: ids.next_item() };
33//! ```
34
35use std::{mem, ops::RangeFrom};
36
37/// Like [`Iterator`], but returns items directly, rather than [`Option`]s.
38pub trait Perpetuity: Sized {
39    type Item;
40
41    fn next_item(&mut self) -> Self::Item;
42
43    fn into_iter(self) -> IntoIter<Self> {
44        IntoIter(self)
45    }
46
47    fn take(self, count: usize) -> Take<Self> {
48        Take { items: self, count }
49    }
50}
51
52/// Returns the specified [`Perpetuity`], erasing any further type information.
53/// ```
54/// let _: Vec<i32> = (0..).take(4).collect();
55/// ```
56/// ```compile_fail
57/// let _: Vec<i32> = iter_utils::assimilate(0..).take(4).collect();
58/// ```
59pub fn assimilate<T>(items: impl Perpetuity<Item = T>) -> impl Perpetuity<Item = T> {
60    items
61}
62
63pub struct IntoIter<I: Perpetuity>(I);
64
65impl<I: Perpetuity> Iterator for IntoIter<I> {
66    type Item = I::Item;
67
68    fn next(&mut self) -> Option<Self::Item> {
69        Some(self.0.next_item())
70    }
71
72    fn size_hint(&self) -> (usize, Option<usize>) {
73        (usize::MAX, None)
74    }
75}
76
77pub struct Take<I: Perpetuity> {
78    items: I,
79    count: usize,
80}
81
82impl<I: Perpetuity> Iterator for Take<I> {
83    type Item = I::Item;
84
85    fn next(&mut self) -> Option<Self::Item> {
86        (self.count > 0).then(|| {
87            self.count -= 1;
88            self.items.next_item()
89        })
90    }
91}
92
93pub struct Successors<T, F: FnMut(&T) -> T> {
94    next: T,
95    succ: F,
96}
97
98impl<T, F: FnMut(&T) -> T> Perpetuity for Successors<T, F> {
99    type Item = T;
100    fn next_item(&mut self) -> Self::Item {
101        let next = (self.succ)(&self.next);
102        mem::replace(&mut self.next, next)
103    }
104}
105
106macro_rules! range_from {
107    ($t:ty) => {
108        impl Perpetuity for RangeFrom<$t> {
109            type Item = $t;
110            fn next_item(&mut self) -> Self::Item {
111                <Self as Iterator>::next(self).unwrap()
112            }
113        }
114    };
115}
116
117range_from!(i8);
118range_from!(i16);
119range_from!(i32);
120range_from!(i64);
121range_from!(i128);
122range_from!(u8);
123range_from!(u16);
124range_from!(u32);
125range_from!(u64);
126range_from!(u128);
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn next_item() {
134        let mut got = Vec::new();
135        let mut count = 0..;
136        for _ in 0..4 {
137            got.push(count.next_item());
138        }
139        assert_eq!(got, [0, 1, 2, 3]);
140    }
141
142    #[test]
143    fn into_iter() {
144        let got: Vec<i32> = assimilate(0..).into_iter().take(4).collect();
145        assert_eq!(got, [0, 1, 2, 3]);
146    }
147
148    #[test]
149    fn take() {
150        let got: Vec<i32> = assimilate(0..).take(4).collect();
151        assert_eq!(got, [0, 1, 2, 3]);
152    }
153}