alternating_iter/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3#![deny(rustdoc::broken_intra_doc_links)]
4#![deny(rustdoc::invalid_rust_codeblocks)]
5#![deny(rustdoc::missing_crate_level_docs)]
6#![warn(rustdoc::invalid_codeblock_attributes)]
7
8mod alternating;
9mod alternating_all;
10mod alternating_no_remainder;
11mod utils;
12
13pub use alternating::Alternating;
14pub use alternating_all::AlternatingAll;
15pub use alternating_no_remainder::AlternatingNoRemainder;
16
17/// Extension trait that provides methods for creating alternating iterators.
18///
19/// This trait can be `use`d to add the `alternate_with*` family of methods
20/// to any iterator, allowing iteration over two iterators in an alternating fashion.
21pub trait AlternatingExt: Iterator {
22    /// Takes two iterators and creates a new iterator over both in an alternating fashion.
23    ///
24    /// The left iterator will be the first in the sequence.
25    /// Alternation continues even if one of the iterators is exhausted.
26    ///
27    /// Note that both iterators must have the same [`Item`](Iterator::Item) type.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use alternating_iter::AlternatingExt;
33    ///
34    /// let a = [1, 2];
35    /// let b = [3, 4, 5];
36    ///
37    /// let mut iter = a.iter().alternate_with(b.iter());
38    ///
39    /// assert_eq!(iter.next(), Some(&1)); // `a` first
40    /// assert_eq!(iter.next(), Some(&3)); // `b`
41    /// assert_eq!(iter.next(), Some(&2)); // `a`
42    /// assert_eq!(iter.next(), Some(&4)); // `b`
43    /// assert_eq!(iter.next(), None);     // `a` exhausted
44    /// assert_eq!(iter.next(), Some(&5)); // `b`
45    /// assert_eq!(iter.next(), None);     // `b` exhausted
46    /// ```
47    fn alternate_with<I>(self, other: I) -> Alternating<Self, I::IntoIter>
48    where
49        Self: Sized,
50        I: IntoIterator<Item = Self::Item>,
51    {
52        Alternating::new(self, other)
53    }
54
55    /// Takes two iterators and creates a new iterator over both in an alternating fashion,
56    /// while handling size differences.
57    ///
58    /// The left iterator will be the first in the sequence.
59    /// Once one of the iterators is exhausted,
60    /// the remaining items from the other iterator will be returned without interruption.
61    ///
62    /// Note that both iterators must have the same [`Item`](Iterator::Item) type.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use alternating_iter::AlternatingExt;
68    ///
69    /// let a = [1, 2];
70    /// let b = [3, 4, 5];
71    ///
72    /// let mut iter = a.iter().alternate_with_all(b.iter());
73    ///
74    /// assert_eq!(iter.next(), Some(&1)); // `a` first
75    /// assert_eq!(iter.next(), Some(&3)); // `b`
76    /// assert_eq!(iter.next(), Some(&2)); // `a`
77    /// assert_eq!(iter.next(), Some(&4)); // `b`
78    /// assert_eq!(iter.next(), Some(&5)); // also `b`
79    /// assert_eq!(iter.next(), None);
80    /// ```
81    fn alternate_with_all<I>(self, other: I) -> AlternatingAll<Self, I::IntoIter>
82    where
83        Self: Sized,
84        I: IntoIterator<Item = Self::Item>,
85    {
86        AlternatingAll::new(self, other)
87    }
88
89    /// Takes two iterators and creates a new iterator over both in an alternating fashion,
90    /// with no remainder from the exhausted iterator.
91    ///
92    /// Different from [`alternate_with`][AlternatingExt::alternate_with] in that
93    /// when one of the iterators is exhausted, only a single item from the other iterator
94    /// is returned.
95    ///
96    /// Note that both iterators must have the same [`Item`](Iterator::Item) type.
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use alternating_iter::AlternatingExt;
102    ///
103    /// let a = [1, 2];
104    /// let b = [3, 4, 5];
105    ///
106    /// let mut iter = a.iter().alternate_with_no_remainder(b.iter());
107    ///
108    /// assert_eq!(iter.next(), Some(&1)); // `a` first
109    /// assert_eq!(iter.next(), Some(&3)); // `b`
110    /// assert_eq!(iter.next(), Some(&2)); // `a`
111    /// assert_eq!(iter.next(), Some(&4)); // `b`
112    /// assert_eq!(iter.next(), None);     // remaining items from `b` are not returned
113    /// ```
114    ///
115    /// Importantly, the order of the iterators matters to the overall length:
116    /// ```
117    /// # use std::iter;
118    /// # use alternating_iter::AlternatingExt;
119    ///
120    /// let small = [1, 2];
121    /// let big = [3, 4, 5];
122    ///
123    /// assert_eq!(small.iter().alternate_with_no_remainder(big.iter()).count(), 4);
124    /// assert_eq!(big.iter().alternate_with_no_remainder(small.iter()).count(), 5);
125    /// ```
126    ///
127    /// This behavior can be depicted as follows:
128    ///
129    /// Here is when `small` is on the left:
130    /// ```txt
131    /// small: 1 2 None
132    ///        |/|/
133    ///   big: 3 4
134    /// ```
135    /// And here is when `big` is on the left:
136    /// ```txt
137    /// small: 3 4 5
138    ///        |/|/|
139    ///   big: 1 2 None
140    /// ```
141    fn alternate_with_no_remainder<I>(self, other: I) -> AlternatingNoRemainder<Self, I::IntoIter>
142    where
143        Self: Sized,
144        I: IntoIterator<Item = Self::Item>,
145    {
146        AlternatingNoRemainder::new(self, other)
147    }
148}
149
150impl<I> AlternatingExt for I where I: Iterator {}