From 66832632bb7eabf70d5af0f9e02e5ebb3f5ffff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Cassiers?= Date: Thu, 4 Feb 2021 18:28:28 +0100 Subject: [PATCH] Add a chain! macro. The chain! macro creates an iterator running multiple iterators sequentially. --- src/lib.rs | 37 +++++++++++++++++++++++++++++++++++++ tests/test_core.rs | 23 +++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4db8f5d40..1cb21d7a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -346,6 +346,43 @@ macro_rules! izip { }; } +#[macro_export] +/// Create an iterator running multiple iterators sequentially. +/// +/// This is a version of the standard ``.chain()`` that's supporting more than +/// two iterators. `chain!` takes `IntoIterator` arguments. +/// Alternatively, this is an alternative to the standard ``.flatten()`` for a +/// fixed number of iterators of distinct sizes. +/// +/// **Note:** The result of this macro is in the general case an iterator +/// composed of repeated `.chain()`. +/// The special case of one arguments produce $a.into_iter(). +/// +/// +/// ``` +/// # use itertools::chain; +/// # +/// # fn main() { +/// +/// // chain three sequences +/// let chained: Vec = chain!(0..=3, 4..6, vec![6, 7]).collect(); +/// assert_eq!(chained, (0..=7).collect::>()); +/// # } +/// ``` +macro_rules! chain { + () => { + core::iter::empty() + }; + ( $first:expr $(, $rest:expr )* $(,)*) => { + core::iter::IntoIterator::into_iter($first) + $( + .chain( + core::iter::IntoIterator::into_iter($rest) + ) + )* + }; +} + /// An [`Iterator`] blanket implementation that provides extra adaptors and /// methods. /// diff --git a/tests/test_core.rs b/tests/test_core.rs index 5861653da..3d0295825 100644 --- a/tests/test_core.rs +++ b/tests/test_core.rs @@ -13,6 +13,7 @@ use crate::it::multizip; use crate::it::free::put_back; use crate::it::iproduct; use crate::it::izip; +use crate::it::chain; #[test] fn product2() { @@ -87,6 +88,28 @@ fn multizip3() { } } +#[test] +fn chain_macro() { + let mut chain = chain!(2..3); + assert!(chain.next() == Some(2)); + assert!(chain.next().is_none()); + + let mut chain = chain!(0..2, 2..3, 3..5i8); + for i in 0..5i8 { + assert_eq!(Some(i), chain.next()); + } + assert!(chain.next().is_none()); + + let mut chain = chain!(); + assert_eq!(chain.next(), Option::<()>::None); +} + +#[test] +fn chain2() { + let _ = chain!(1.., 2..); + let _ = chain!(1.., 2.., ); +} + #[test] fn write_to() { let xs = [7, 9, 8];