Repository: bluss/rust-itertools (rust)

Issue:
izip!(): Use just a.zip(b) if there are only two input parameters
Currently, `izip!()` always uses a map. It's redundant when we only have two input parameters.

Use simpler type or use more consistent type? The map closure's type is always anonymous anyway, so it can't be used for much.

Pull request:
Let the resulting type of izip!(i, j) be std::iter::Zip<i, j>
* Use the regular `Zip` iterator (without a .map()) when there are just
two inputs to `izip!()`.
* Use the regular iterator when there is just one input.

Fixes #229 

Patch:
diff --git a/src/lib.rs b/src/lib.rs
index c6518ff..7c044f6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -210,12 +210,15 @@ macro_rules! iproduct {
 /// returns `None`.
 ///
 /// This is a version of the standard ``.zip()`` that's supporting more than
-/// two iterators. The iterator elment type is a tuple with one element
+/// two iterators. The iterator element type is a tuple with one element
 /// from each of the input iterators. Just like ``.zip()``, the iteration stops
 /// when the shortest of the inputs reaches its end.
 ///
-/// **Note:** The result of this macro is an iterator composed of
-/// repeated `.zip()` and a `.map()`; it has an anonymous type.
+/// **Note:** The result of this macro is in the general case an iterator
+/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type.
+/// The special cases of one and two arguments produce the equivalent of
+/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively.
+///
 /// Prefer this macro `izip!()` over [`multizip`] for the performance benefits
 /// of using the standard library `.zip()`.
 ///
@@ -257,8 +260,20 @@ macro_rules! izip {
         izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*)
     };
 
-    ( $first:expr $( , $rest:expr )* $(,)* ) => {
+    // unary
+    ($first:expr $(,)*) => {
         $crate::__std_iter::IntoIterator::into_iter($first)
+    };
+
+    // binary
+    ($first:expr, $second:expr $(,)*) => {
+        izip!($first)
+            .zip($second)
+    };
+
+    // n-ary where n > 2
+    ( $first:expr $( , $rest:expr )* $(,)* ) => {
+        izip!($first)
             $(
                 .zip($rest)
             )*


Test patch:
diff --git a/tests/test_core.rs b/tests/test_core.rs
index e215255..dfc068d 100644
--- a/tests/test_core.rs
+++ b/tests/test_core.rs
@@ -7,6 +7,8 @@
 
 #[macro_use] extern crate itertools as it;
 
+use core::iter;
+
 use it::flatten;
 use it::Itertools;
 use it::interleave;
@@ -54,8 +56,23 @@ fn izip_macro() {
     assert!(zip.next().is_none());
 }
 
+#[test]
+fn izip2() {
+    let _zip1: iter::Zip<_, _> = izip!(1.., 2..);
+    let _zip2: iter::Zip<_, _> = izip!(1.., 2.., );
+}
+
 #[test]
 fn izip3() {
+    let mut zip: iter::Map<iter::Zip<_, _>, _> = izip!(0..3, 0..2, 0..2i8);
+    for i in 0..2 {
+        assert!((i as usize, i, i as i8) == zip.next().unwrap());
+    }
+    assert!(zip.next().is_none());
+}
+
+#[test]
+fn multizip3() {
     let mut zip = multizip((0..3, 0..2, 0..2i8));
     for i in 0..2 {
         assert!((i as usize, i, i as i8) == zip.next().unwrap());