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 {}