Skip to content

Commit 435c45e

Browse files
committed
Add a chain! macro.
The chain! macro creates an iterator running multiple iterators sequentially.
1 parent 853f064 commit 435c45e

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/lib.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,40 @@ macro_rules! izip {
346346
};
347347
}
348348

349+
#[macro_export]
350+
/// Create an iterator running multiple iterators sequentially.
351+
///
352+
/// This is a version of the standard ``.chain()`` that's supporting more than
353+
/// two iterators. `chain!` takes `IntoIterator` arguments.
354+
/// Alternatively, this is an alternative to the standard ``.flatten()`` for a
355+
/// fixed number of iterators of distinct sizes.
356+
///
357+
/// **Note:** The result of this macro is in the general case an iterator
358+
/// composed of repeated `.chain()`.
359+
/// The special case of one arguments produce $a.into_iter().
360+
///
361+
///
362+
/// ```
363+
/// # use itertools::chain;
364+
/// #
365+
/// # fn main() {
366+
///
367+
/// // chain three sequences
368+
/// let chained: Vec<i32> = chain!(0..=3, 4..6, vec![6, 7]).collect();
369+
/// assert_eq!(chained, (0..=7).collect::<Vec<i32>>());
370+
/// # }
371+
/// ```
372+
macro_rules! chain {
373+
( $first:expr $(, $rest:expr )* $(,)*) => {
374+
core::iter::IntoIterator::into_iter($first)
375+
$(
376+
.chain(
377+
core::iter::IntoIterator::into_iter($rest)
378+
)
379+
)*
380+
};
381+
}
382+
349383
/// An [`Iterator`] blanket implementation that provides extra adaptors and
350384
/// methods.
351385
///

tests/quick.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use itertools::{
1515
EitherOrBoth,
1616
iproduct,
1717
izip,
18+
chain,
1819
};
1920
use itertools::free::{
2021
cloned,
@@ -526,6 +527,11 @@ quickcheck! {
526527
correct_size_hint(izip!(filt, b.clone(), c.clone())) &&
527528
exact_size(izip!(a, b, c))
528529
}
530+
531+
fn size_chain_macro(a: Iter<i16, Exact>, b: Iter<i16, Exact>, c: Iter<i16, Exact>) -> bool {
532+
correct_size_hint(chain!(a.clone(), b.clone(), c.clone()))
533+
}
534+
529535
fn equal_kmerge(a: Vec<i16>, b: Vec<i16>, c: Vec<i16>) -> bool {
530536
use itertools::free::kmerge;
531537
let mut sa = a.clone();

tests/test_core.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::it::multizip;
1313
use crate::it::free::put_back;
1414
use crate::it::iproduct;
1515
use crate::it::izip;
16+
use crate::it::chain;
1617

1718
#[test]
1819
fn product2() {
@@ -87,6 +88,25 @@ fn multizip3() {
8788
}
8889
}
8990

91+
#[test]
92+
fn chain_macro() {
93+
let mut chain = chain!(2..3);
94+
assert!(chain.next() == Some(2));
95+
assert!(chain.next().is_none());
96+
97+
let mut chain = chain!(0..2, 2..3, 3..5i8);
98+
for i in 0..5i8 {
99+
assert_eq!(Some(i), chain.next());
100+
}
101+
assert!(chain.next().is_none());
102+
}
103+
104+
#[test]
105+
fn chain2() {
106+
let _ = chain!(1.., 2..);
107+
let _ = chain!(1.., 2.., );
108+
}
109+
90110
#[test]
91111
fn write_to() {
92112
let xs = [7, 9, 8];

0 commit comments

Comments
 (0)