lit_vek/
iter.rs

1/** Iterator type returned by `cycle_n()` */
2#[derive(Clone, Debug)]
3pub struct CycleN<I> {
4    // Both `orig` and `iter` are in Option so that we don't have to
5    // call into_iter() or clone() more than necessary.
6    orig: Option<I>,
7    iter: Option<I>,
8    n: usize,
9}
10
11/** Iterator adaptor that repeats a sequence n times.
12
13    use lit_vek::cycle_n;
14
15    assert!(cycle_n([1, 2, 3], 2).eq([1, 2, 3, 1, 2, 3]));
16
17The sequence must be `IntoIter`, and the iterator must be `Clone`.
18
19This is mostly to enable the `vek![...elems, n]` syntax.
20*/
21pub fn cycle_n<I: IntoIterator>(it: I, n: usize) -> CycleN<I::IntoIter>
22where
23    I::IntoIter: Clone,
24{
25    match n {
26        0 => CycleN {
27            orig: None,
28            iter: None,
29            n,
30        },
31        1 => {
32            let it = it.into_iter();
33            CycleN {
34                orig: None,
35                iter: Some(it),
36                n,
37            }
38        }
39        _ => {
40            let i1 = it.into_iter();
41            let i2 = i1.clone();
42            CycleN {
43                orig: Some(i1),
44                iter: Some(i2),
45                n,
46            }
47        }
48    }
49}
50
51impl<I: Iterator + Clone> Iterator for CycleN<I> {
52    type Item = I::Item;
53
54    fn next(&mut self) -> Option<Self::Item> {
55        while let Some(it) = &mut self.iter {
56            if let Some(x) = it.next() {
57                return Some(x);
58            }
59            self.n -= 1;
60            if self.n < 2 {
61                self.iter = self.orig.take();
62            } else {
63                self.iter = self.orig.clone();
64            }
65        }
66        None
67    }
68}
69
70/**
71Chain one more elements or iterables together into one sequence, using "spread"
72syntax.
73
74    # use {lit_vek::iter, std::array};
75
76    let arr = [1, 2, 3];
77    let vec = vec![8, 9, 10];
78
79    assert!(
80        iter![...arr, 4, ...(5..7), 7, ...vec]
81        .eq([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
82
83`iter![a, b, c]` simply returns an iterator over those elements, exactly like
84`[a, b, c].into_iter()`. But elements can be prefixed with `...` to indicate
85a "spread": they are chained into the resulting iterator with
86`std::iter::chain()`.
87
88See `[lit_vek::vek]` in this crate for more explanation of the syntax.
89
90# Examples
91
92    use {lit_vek::{iter, CycleN}, std::{array, iter}};
93    let ints = [1, 2, 3];
94
95    // Empty invocations of iter! expand to [std::iter::empty].
96    let _: iter::Empty<i32> = iter![];
97
98    // One or more arguments expand to Array::IntoIter.
99    let _: array::IntoIter<_, 1> = iter![1];
100    let _: array::IntoIter<_, 3> = iter![1, 2, 3];
101
102    // The `[x; n]` syntax expands to [std::iter::repeat(x).take(n)]
103    let _: iter::Take<iter::Repeat<_>> = iter![0; 5];
104
105    // The `[...x; n]` syntax expands to [`cycle_n`] from this crate
106    let _: CycleN<_> = iter![...ints; 3];
107
108    // And chaining expands to [std::iter::Chain]
109    let _: iter::Chain<_, _> = iter![...ints, ...ints];
110
111# See also
112
113The `vek![]` macro in this crate is a drop-in replacement for `vec![]`,
114but enables the same spread syntax. It is equivalent to
115`iter![].collect::<Vec<_>>()`.
116
117The `itertools::chain!` macro is similar, except it takes only iterable
118arguments rather than a mix of iterables and single elements.
119
120```ignore
121    chain![a, b, iter::once(c)] == iter![...a, ...b, c]
122```
123*/
124#[macro_export]
125macro_rules! iter {
126    // empty
127    () => { ::std::iter::empty() };
128
129    // [x; n]
130    ($x:tt; $n:expr) => {
131        ::std::iter::repeat($x).take($n)
132    };
133
134    // [...x; n]
135    (...$x:tt; $n:expr) => {
136        $crate::cycle_n($x, $n)
137    };
138
139    // [...[x; n] at start
140    (...[...$xs:expr; $n:expr] $($tail:tt)*) => {
141        $crate::iter![...$crate::cycle_n($xs, $n) $($tail)*]
142    };
143
144    // simple array at start
145    (...$some:tt $(,)? ) => {
146        ::std::iter::IntoIterator::into_iter($some)
147    };
148
149    // ...[...x; n] in second item; convert to repeat_n
150    (...$some:tt, ...[...$x:tt; $n:expr] $($tail:tt)*) => {
151        $crate::iter![...$some, ...$crate::cycle_n($x, $n) $($tail)*]
152    };
153
154    // ...[x; n] in second item; convert to simple expr
155    (...$some:tt, ...[$x:tt; $n:expr] $($tail:tt)*) => {
156        $crate::iter![...$some, ...std::iter::repeat($x).take($n) $($tail)*]
157    };
158
159    // ...xs in second item and nothing else; final chain()
160    (...$some:tt, ...$xs:expr $(,)?) => {
161        ::std::iter::Iterator::chain(
162            ::std::iter::IntoIterator::into_iter($some),
163            $xs)
164    };
165
166    // ...xs in second item followed by more; continue chain()
167    (...$some:tt, ...$xs:expr, $($tail:tt)*) => {
168        $crate::iter![
169            ... ::std::iter::Iterator::chain(
170                ::std::iter::IntoIterator::into_iter($some),
171                $xs),
172            $($tail)*
173        ]
174    };
175
176    // shift a single elem into the starting literal
177    (...[$($some:tt)*], $x:tt $(, $($tail:tt)*)?) => {
178        $crate::iter![...[$($some)*, $x], $($($tail)*)?]
179    };
180
181    // first element is a (non-literal) spread
182    (...$xs:expr $(, $($tail:tt)*)?) => {
183        ::std::iter::Iterator::chain(
184            ::std::iter::IntoIterator::into_iter($xs),
185            $crate::iter![ $($($tail)*)? ])
186    };
187
188    // shift a single elem into a new starting literal
189    ($x:expr $(, $($tail:tt)*)?) => {
190        $crate::iter![...[$x], $($($tail)*)? ]
191    };
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    #[test]
199    fn test_cycle_n() {
200        assert!(cycle_n(1..4, 0).eq([]));
201        assert!(cycle_n(1..4, 1).eq([1, 2, 3]));
202        assert!(cycle_n(1..4, 2).eq([1, 2, 3, 1, 2, 3]));
203
204        assert!(cycle_n(0..0, 10).eq([]));
205    }
206
207    #[test]
208    fn test_iter() {
209        assert_eq!(Vec::<u32>::new(), iter![].collect::<Vec<_>>());
210
211        assert_eq!(vec![1], iter![1].collect::<Vec<_>>());
212        assert_eq!(vec![1, 2], iter![1, 2].collect::<Vec<_>>());
213        assert_eq!(vec![1, 2, 3], iter![1, 2, 3].collect::<Vec<_>>());
214
215        assert_eq!(vec![1], iter![...[1]].collect::<Vec<_>>());
216        assert_eq!(vec![1, 2], iter![...[1,2]].collect::<Vec<_>>());
217
218        assert_eq!(vec![1, 2], iter![1,...[2]].collect::<Vec<_>>());
219        assert_eq!(vec![1, 2, 3], iter![...[1], ...[2,3]].collect::<Vec<_>>());
220        assert_eq!(
221            vec![1, 2, 3, 4, 5, 6],
222            iter![1, ...[2,3], 4, ...[], 5, ...[6]].collect::<Vec<_>>()
223        );
224    }
225}