Skip to content

Commit d2a73a3

Browse files
committed
fix: zip iter adapter
1 parent 586476e commit d2a73a3

File tree

5 files changed

+122
-78
lines changed

5 files changed

+122
-78
lines changed

corelib/src/iter/adapters.cairo

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pub use map::Map;
33
#[allow(unused_imports)]
44
pub(crate) use map::mapped_iterator;
55

6-
mod zip_adapter;
6+
mod zip;
7+
pub use zip::Zip;
78
#[allow(unused_imports)]
8-
pub(crate) use zip_adapter::zipped_iterator;
9-
pub use zip_adapter::{Zip, zip};
9+
pub(crate) use zip::zipped_iterator;

corelib/src/iter/adapters/zip.cairo

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/// An iterator that iterates two other iterators simultaneously.
2+
///
3+
/// This `struct` is created by [`zip`] or [`Iterator::zip`].
4+
/// See their documentation for more.
5+
///
6+
/// [`Iterator::zip`]: core::iter::Iterator::zip
7+
#[derive(Drop, Clone)]
8+
#[must_use]
9+
pub struct Zip<A, B> {
10+
a: A,
11+
b: B,
12+
}
13+
14+
#[inline]
15+
pub fn zipped_iterator<A, B>(a: A, b: B) -> Zip<A, B> {
16+
Zip { a, b }
17+
}
18+
19+
impl ZipIterator<
20+
A,
21+
B,
22+
impl IterA: Iterator<A>,
23+
impl IterB: Iterator<B>,
24+
+Destruct<A>,
25+
+Destruct<B>,
26+
+Destruct<IterA::Item>,
27+
+Destruct<IterB::Item>,
28+
> of Iterator<Zip<A, B>> {
29+
type Item = (IterA::Item, IterB::Item);
30+
31+
#[inline]
32+
fn next(ref self: Zip<A, B>) -> Option<Self::Item> {
33+
let a = self.a.next()?;
34+
let b = self.b.next()?;
35+
Option::Some((a, b))
36+
}
37+
}

corelib/src/iter/adapters/zip_adapter.cairo

-69
This file was deleted.

corelib/src/iter/traits/iterator.cairo

+76-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::iter::adapters::{Map, mapped_iterator};
1+
use crate::iter::adapters::{Map, Zip, mapped_iterator, zipped_iterator};
22

33
/// A trait for dealing with iterators.
44
///
@@ -93,4 +93,79 @@ pub trait Iterator<T> {
9393
) -> Map<T, F> {
9494
mapped_iterator(self, f)
9595
}
96+
97+
/// 'Zips up' two iterators into a single iterator of pairs.
98+
///
99+
/// `zip()` returns a new iterator that will iterate over two other
100+
/// iterators, returning a tuple where the first element comes from the
101+
/// first iterator, and the second element comes from the second iterator.
102+
///
103+
/// In other words, it zips two iterators together, into a single one.
104+
///
105+
/// If either iterator returns [`Option::None`], [`next`] from the zipped iterator
106+
/// will return [`Option::None`].
107+
/// If the zipped iterator has no more elements to return then each further attempt to advance
108+
/// it will first try to advance the first iterator at most one time and if it still yielded an
109+
/// item try to advance the second iterator at most one time.
110+
///
111+
/// # Examples
112+
///
113+
/// Basic usage:
114+
///
115+
/// ```
116+
/// let a1 = array![1, 2, 3];
117+
/// let a2 = array![4, 5, 6];
118+
///
119+
/// let mut iter = a1.into_iter().zip(a2.into_iter());
120+
///
121+
/// assert_eq!(iter.next(), Option::Some((1, 4)));
122+
/// assert_eq!(iter.next(), Option::Some((2, 5)));
123+
/// assert_eq!(iter.next(), Option::Some((3, 6)));
124+
/// assert_eq!(iter.next(), Option::None);
125+
/// ```
126+
///
127+
/// Since the argument to `zip()` uses [`IntoIterator`], we can pass
128+
/// anything that can be converted into an [`Iterator`], not just an
129+
/// [`Iterator`] itself. For example:
130+
///
131+
/// ```
132+
/// let a1 = array![1, 2, 3];
133+
/// let a2 = array![4, 5, 6];
134+
///
135+
/// let mut iter = a1.into_iter().zip(a2);
136+
///
137+
/// assert_eq!(iter.next(), Option::Some((1, 4)));
138+
/// assert_eq!(iter.next(), Option::Some((2, 5)));
139+
/// assert_eq!(iter.next(), Option::Some((3, 6)));
140+
/// assert_eq!(iter.next(), Option::None);
141+
/// ```
142+
///
143+
/// If both iterators have roughly equivalent syntax, it may be more readable to use [`zip`]:
144+
///
145+
/// ```
146+
/// use core::iter::zip;
147+
///
148+
/// let a = array![1, 2, 3];
149+
/// let b = array![2, 3, 4];
150+
///
151+
/// let mut zipped = zip(a, b);
152+
///
153+
/// assert_eq!(iter.next(), Option::Some((1, 4)));
154+
/// assert_eq!(iter.next(), Option::Some((2, 5)));
155+
/// assert_eq!(iter.next(), Option::Some((3, 6)));
156+
/// assert_eq!(iter.next(), Option::None);
157+
/// );
158+
/// ```
159+
///
160+
/// [`enumerate`]: Iterator::enumerate
161+
/// [`next`]: Iterator::next
162+
/// [`zip`]: core::iter::zip
163+
#[inline]
164+
fn zip<U, +Iterator<U> //, +IntoIterator<U>
165+
>(
166+
self: T, other: U,
167+
) -> Zip<T, U> {
168+
zipped_iterator(self, other //.into_iter()
169+
)
170+
}
96171
}

corelib/src/test/iter_test.cairo

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use core::iter::zip;
2-
31
#[test]
42
fn test_iter_adapter_map() {
53
let mut iter = array![1, 2, 3].into_iter().map(|x| 2 * x);
@@ -12,15 +10,18 @@ fn test_iter_adapter_map() {
1210

1311
#[test]
1412
fn test_iterator_zip() {
15-
let mut iter = zip(array![1, 2, 3], array![4, 5, 6]);
13+
let mut iter = array![1, 2, 3].into_iter().zip(array![4, 5, 6].into_iter());
1614

1715
assert_eq!(iter.next(), Option::Some((1, 4)));
1816
assert_eq!(iter.next(), Option::Some((2, 5)));
1917
assert_eq!(iter.next(), Option::Some((3, 6)));
2018
assert_eq!(iter.next(), Option::None);
2119

22-
// Nested zips are also possible:
23-
let mut iter = zip(zip(array![1, 2, 3], array![4, 5, 6]), array![7, 8, 9]);
20+
// Nested zips
21+
let mut iter = array![1, 2, 3]
22+
.into_iter()
23+
.zip(array![4, 5, 6].into_iter())
24+
.zip(array![7, 8, 9].into_iter());
2425

2526
assert_eq!(iter.next(), Option::Some(((1, 4), 7)));
2627
assert_eq!(iter.next(), Option::Some(((2, 5), 8)));

0 commit comments

Comments
 (0)