overture_core/
zip_suites.rs

1// Zip sequence utilities for higher-arity operations
2// Equivalent to Swift's zip functions for sequences
3
4use std::iter::{Iterator, IntoIterator};
5
6/// Creates a zip iterator from 3 sequences.
7/// Equivalent to Swift's zip<A, B, C>(_ a: A, _ b: B, _ c: C) -> Zip3Sequence<A, B, C>
8///
9/// # Examples
10/// ```
11/// use overture_core::zip_suites::zip3;
12/// 
13/// let a = vec![1, 2, 3];
14/// let b = vec![4, 5, 6];
15/// let c = vec![7, 8, 9];
16/// 
17/// let zipped: Vec<_> = zip3(a, b, c).collect();
18/// assert_eq!(zipped, vec![(1, 4, 7), (2, 5, 8), (3, 6, 9)]);
19/// ```
20pub fn zip3<A, B, C>(a: A, b: B, c: C) -> Zip3Iterator<A::IntoIter, B::IntoIter, C::IntoIter>
21where
22    A: IntoIterator,
23    B: IntoIterator,
24    C: IntoIterator,
25{
26    Zip3Iterator {
27        a: a.into_iter(),
28        b: b.into_iter(),
29        c: c.into_iter(),
30    }
31}
32
33/// Creates a zip iterator from 3 sequences with a transform function.
34/// Equivalent to Swift's zip<A, B, C, Z>(with transform: (A.Element, B.Element, C.Element) -> Z, _ a: A, _ b: B, _ c: C) -> [Z]
35///
36/// # Examples
37/// ```
38/// use overture_core::zip_suites::zip3_with;
39/// 
40/// let a = vec![1, 2, 3];
41/// let b = vec![4, 5, 6];
42/// let c = vec![7, 8, 9];
43/// 
44/// let result = zip3_with(|x, y, z| x + y + z, a, b, c);
45/// assert_eq!(result, vec![12, 15, 18]);
46/// ```
47pub fn zip3_with<A, B, C, Z, F>(transform: F, a: A, b: B, c: C) -> Vec<Z>
48where
49    A: IntoIterator,
50    B: IntoIterator,
51    C: IntoIterator,
52    F: Fn(A::Item, B::Item, C::Item) -> Z,
53{
54    zip3(a, b, c).map(|(a, b, c)| transform(a, b, c)).collect()
55}
56
57/// Creates a zip iterator from 4 sequences.
58pub fn zip4<A, B, C, D>(a: A, b: B, c: C, d: D) -> Zip4Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter>
59where
60    A: IntoIterator,
61    B: IntoIterator,
62    C: IntoIterator,
63    D: IntoIterator,
64{
65    Zip4Iterator {
66        a: a.into_iter(),
67        b: b.into_iter(),
68        c: c.into_iter(),
69        d: d.into_iter(),
70    }
71}
72
73/// Creates a zip iterator from 4 sequences with a transform function.
74pub fn zip4_with<A, B, C, D, Z, F>(transform: F, a: A, b: B, c: C, d: D) -> Vec<Z>
75where
76    A: IntoIterator,
77    B: IntoIterator,
78    C: IntoIterator,
79    D: IntoIterator,
80    F: Fn(A::Item, B::Item, C::Item, D::Item) -> Z,
81{
82    zip4(a, b, c, d).map(|(a, b, c, d)| transform(a, b, c, d)).collect()
83}
84
85/// Creates a zip iterator from 5 sequences.
86pub fn zip5<A, B, C, D, E>(a: A, b: B, c: C, d: D, e: E) -> Zip5Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter, E::IntoIter>
87where
88    A: IntoIterator,
89    B: IntoIterator,
90    C: IntoIterator,
91    D: IntoIterator,
92    E: IntoIterator,
93{
94    Zip5Iterator {
95        a: a.into_iter(),
96        b: b.into_iter(),
97        c: c.into_iter(),
98        d: d.into_iter(),
99        e: e.into_iter(),
100    }
101}
102
103/// Creates a zip iterator from 5 sequences with a transform function.
104pub fn zip5_with<A, B, C, D, E, Z, F>(transform: F, a: A, b: B, c: C, d: D, e: E) -> Vec<Z>
105where
106    A: IntoIterator,
107    B: IntoIterator,
108    C: IntoIterator,
109    D: IntoIterator,
110    E: IntoIterator,
111    F: Fn(A::Item, B::Item, C::Item, D::Item, E::Item) -> Z,
112{
113    zip5(a, b, c, d, e).map(|(a, b, c, d, e)| transform(a, b, c, d, e)).collect()
114}
115
116/// Creates a zip iterator from 6 sequences.
117pub fn zip6<A, B, C, D, E, F>(a: A, b: B, c: C, d: D, e: E, f: F) -> Zip6Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter, E::IntoIter, F::IntoIter>
118where
119    A: IntoIterator,
120    B: IntoIterator,
121    C: IntoIterator,
122    D: IntoIterator,
123    E: IntoIterator,
124    F: IntoIterator,
125{
126    Zip6Iterator {
127        a: a.into_iter(),
128        b: b.into_iter(),
129        c: c.into_iter(),
130        d: d.into_iter(),
131        e: e.into_iter(),
132        f: f.into_iter(),
133    }
134}
135
136/// Creates a zip iterator from 6 sequences with a transform function.
137pub fn zip6_with<A, B, C, D, E, F, Z, G>(transform: G, a: A, b: B, c: C, d: D, e: E, f: F) -> Vec<Z>
138where
139    A: IntoIterator,
140    B: IntoIterator,
141    C: IntoIterator,
142    D: IntoIterator,
143    E: IntoIterator,
144    F: IntoIterator,
145    G: Fn(A::Item, B::Item, C::Item, D::Item, E::Item, F::Item) -> Z,
146{
147    zip6(a, b, c, d, e, f).map(|(a, b, c, d, e, f)| transform(a, b, c, d, e, f)).collect()
148}
149
150/// Creates a zip iterator from 7 sequences.
151pub fn zip7<A, B, C, D, E, F, G>(a: A, b: B, c: C, d: D, e: E, f: F, g: G) -> Zip7Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter, E::IntoIter, F::IntoIter, G::IntoIter>
152where
153    A: IntoIterator,
154    B: IntoIterator,
155    C: IntoIterator,
156    D: IntoIterator,
157    E: IntoIterator,
158    F: IntoIterator,
159    G: IntoIterator,
160{
161    Zip7Iterator {
162        a: a.into_iter(),
163        b: b.into_iter(),
164        c: c.into_iter(),
165        d: d.into_iter(),
166        e: e.into_iter(),
167        f: f.into_iter(),
168        g: g.into_iter(),
169    }
170}
171
172/// Creates a zip iterator from 7 sequences with a transform function.
173pub fn zip7_with<A, B, C, D, E, F, G, Z, H>(transform: H, a: A, b: B, c: C, d: D, e: E, f: F, g: G) -> Vec<Z>
174where
175    A: IntoIterator,
176    B: IntoIterator,
177    C: IntoIterator,
178    D: IntoIterator,
179    E: IntoIterator,
180    F: IntoIterator,
181    G: IntoIterator,
182    H: Fn(A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item) -> Z,
183{
184    zip7(a, b, c, d, e, f, g).map(|(a, b, c, d, e, f, g)| transform(a, b, c, d, e, f, g)).collect()
185}
186
187/// Creates a zip iterator from 8 sequences.
188pub fn zip8<A, B, C, D, E, F, G, H>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) -> Zip8Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter, E::IntoIter, F::IntoIter, G::IntoIter, H::IntoIter>
189where
190    A: IntoIterator,
191    B: IntoIterator,
192    C: IntoIterator,
193    D: IntoIterator,
194    E: IntoIterator,
195    F: IntoIterator,
196    G: IntoIterator,
197    H: IntoIterator,
198{
199    Zip8Iterator {
200        a: a.into_iter(),
201        b: b.into_iter(),
202        c: c.into_iter(),
203        d: d.into_iter(),
204        e: e.into_iter(),
205        f: f.into_iter(),
206        g: g.into_iter(),
207        h: h.into_iter(),
208    }
209}
210
211/// Creates a zip iterator from 8 sequences with a transform function.
212pub fn zip8_with<A, B, C, D, E, F, G, H, Z, I>(transform: I, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) -> Vec<Z>
213where
214    A: IntoIterator,
215    B: IntoIterator,
216    C: IntoIterator,
217    D: IntoIterator,
218    E: IntoIterator,
219    F: IntoIterator,
220    G: IntoIterator,
221    H: IntoIterator,
222    I: Fn(A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item, H::Item) -> Z,
223{
224    zip8(a, b, c, d, e, f, g, h).map(|(a, b, c, d, e, f, g, h)| transform(a, b, c, d, e, f, g, h)).collect()
225}
226
227/// Creates a zip iterator from 9 sequences.
228pub fn zip9<A, B, C, D, E, F, G, H, I>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) -> Zip9Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter, E::IntoIter, F::IntoIter, G::IntoIter, H::IntoIter, I::IntoIter>
229where
230    A: IntoIterator,
231    B: IntoIterator,
232    C: IntoIterator,
233    D: IntoIterator,
234    E: IntoIterator,
235    F: IntoIterator,
236    G: IntoIterator,
237    H: IntoIterator,
238    I: IntoIterator,
239{
240    Zip9Iterator {
241        a: a.into_iter(),
242        b: b.into_iter(),
243        c: c.into_iter(),
244        d: d.into_iter(),
245        e: e.into_iter(),
246        f: f.into_iter(),
247        g: g.into_iter(),
248        h: h.into_iter(),
249        i: i.into_iter(),
250    }
251}
252
253/// Creates a zip iterator from 9 sequences with a transform function.
254pub fn zip9_with<A, B, C, D, E, F, G, H, I, Z, J>(transform: J, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) -> Vec<Z>
255where
256    A: IntoIterator,
257    B: IntoIterator,
258    C: IntoIterator,
259    D: IntoIterator,
260    E: IntoIterator,
261    F: IntoIterator,
262    G: IntoIterator,
263    H: IntoIterator,
264    I: IntoIterator,
265    J: Fn(A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item, H::Item, I::Item) -> Z,
266{
267    zip9(a, b, c, d, e, f, g, h, i).map(|(a, b, c, d, e, f, g, h, i)| transform(a, b, c, d, e, f, g, h, i)).collect()
268}
269
270/// Creates a zip iterator from 10 sequences.
271pub fn zip10<A, B, C, D, E, F, G, H, I, J>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) -> Zip10Iterator<A::IntoIter, B::IntoIter, C::IntoIter, D::IntoIter, E::IntoIter, F::IntoIter, G::IntoIter, H::IntoIter, I::IntoIter, J::IntoIter>
272where
273    A: IntoIterator,
274    B: IntoIterator,
275    C: IntoIterator,
276    D: IntoIterator,
277    E: IntoIterator,
278    F: IntoIterator,
279    G: IntoIterator,
280    H: IntoIterator,
281    I: IntoIterator,
282    J: IntoIterator,
283{
284    Zip10Iterator {
285        a: a.into_iter(),
286        b: b.into_iter(),
287        c: c.into_iter(),
288        d: d.into_iter(),
289        e: e.into_iter(),
290        f: f.into_iter(),
291        g: g.into_iter(),
292        h: h.into_iter(),
293        i: i.into_iter(),
294        j: j.into_iter(),
295    }
296}
297
298/// Creates a zip iterator from 10 sequences with a transform function.
299pub fn zip10_with<A, B, C, D, E, F, G, H, I, J, Z, K>(transform: K, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) -> Vec<Z>
300where
301    A: IntoIterator,
302    B: IntoIterator,
303    C: IntoIterator,
304    D: IntoIterator,
305    E: IntoIterator,
306    F: IntoIterator,
307    G: IntoIterator,
308    H: IntoIterator,
309    I: IntoIterator,
310    J: IntoIterator,
311    K: Fn(A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item, H::Item, I::Item, J::Item) -> Z,
312{
313    zip10(a, b, c, d, e, f, g, h, i, j).map(|(a, b, c, d, e, f, g, h, i, j)| transform(a, b, c, d, e, f, g, h, i, j)).collect()
314}
315
316// Iterator implementations
317
318/// Iterator for zipping 3 sequences.
319pub struct Zip3Iterator<A, B, C> {
320    a: A,
321    b: B,
322    c: C,
323}
324
325impl<A, B, C> Iterator for Zip3Iterator<A, B, C>
326where
327    A: Iterator,
328    B: Iterator,
329    C: Iterator,
330{
331    type Item = (A::Item, B::Item, C::Item);
332
333    fn next(&mut self) -> Option<Self::Item> {
334        match (self.a.next(), self.b.next(), self.c.next()) {
335            (Some(a), Some(b), Some(c)) => Some((a, b, c)),
336            _ => None,
337        }
338    }
339}
340
341/// Iterator for zipping 4 sequences.
342pub struct Zip4Iterator<A, B, C, D> {
343    a: A,
344    b: B,
345    c: C,
346    d: D,
347}
348
349impl<A, B, C, D> Iterator for Zip4Iterator<A, B, C, D>
350where
351    A: Iterator,
352    B: Iterator,
353    C: Iterator,
354    D: Iterator,
355{
356    type Item = (A::Item, B::Item, C::Item, D::Item);
357
358    fn next(&mut self) -> Option<Self::Item> {
359        match (self.a.next(), self.b.next(), self.c.next(), self.d.next()) {
360            (Some(a), Some(b), Some(c), Some(d)) => Some((a, b, c, d)),
361            _ => None,
362        }
363    }
364}
365
366/// Iterator for zipping 5 sequences.
367pub struct Zip5Iterator<A, B, C, D, E> {
368    a: A,
369    b: B,
370    c: C,
371    d: D,
372    e: E,
373}
374
375impl<A, B, C, D, E> Iterator for Zip5Iterator<A, B, C, D, E>
376where
377    A: Iterator,
378    B: Iterator,
379    C: Iterator,
380    D: Iterator,
381    E: Iterator,
382{
383    type Item = (A::Item, B::Item, C::Item, D::Item, E::Item);
384
385    fn next(&mut self) -> Option<Self::Item> {
386        match (self.a.next(), self.b.next(), self.c.next(), self.d.next(), self.e.next()) {
387            (Some(a), Some(b), Some(c), Some(d), Some(e)) => Some((a, b, c, d, e)),
388            _ => None,
389        }
390    }
391}
392
393/// Iterator for zipping 6 sequences.
394pub struct Zip6Iterator<A, B, C, D, E, F> {
395    a: A,
396    b: B,
397    c: C,
398    d: D,
399    e: E,
400    f: F,
401}
402
403impl<A, B, C, D, E, F> Iterator for Zip6Iterator<A, B, C, D, E, F>
404where
405    A: Iterator,
406    B: Iterator,
407    C: Iterator,
408    D: Iterator,
409    E: Iterator,
410    F: Iterator,
411{
412    type Item = (A::Item, B::Item, C::Item, D::Item, E::Item, F::Item);
413
414    fn next(&mut self) -> Option<Self::Item> {
415        match (self.a.next(), self.b.next(), self.c.next(), self.d.next(), self.e.next(), self.f.next()) {
416            (Some(a), Some(b), Some(c), Some(d), Some(e), Some(f)) => Some((a, b, c, d, e, f)),
417            _ => None,
418        }
419    }
420}
421
422/// Iterator for zipping 7 sequences.
423pub struct Zip7Iterator<A, B, C, D, E, F, G> {
424    a: A,
425    b: B,
426    c: C,
427    d: D,
428    e: E,
429    f: F,
430    g: G,
431}
432
433impl<A, B, C, D, E, F, G> Iterator for Zip7Iterator<A, B, C, D, E, F, G>
434where
435    A: Iterator,
436    B: Iterator,
437    C: Iterator,
438    D: Iterator,
439    E: Iterator,
440    F: Iterator,
441    G: Iterator,
442{
443    type Item = (A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item);
444
445    fn next(&mut self) -> Option<Self::Item> {
446        match (self.a.next(), self.b.next(), self.c.next(), self.d.next(), self.e.next(), self.f.next(), self.g.next()) {
447            (Some(a), Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => Some((a, b, c, d, e, f, g)),
448            _ => None,
449        }
450    }
451}
452
453/// Iterator for zipping 8 sequences.
454pub struct Zip8Iterator<A, B, C, D, E, F, G, H> {
455    a: A,
456    b: B,
457    c: C,
458    d: D,
459    e: E,
460    f: F,
461    g: G,
462    h: H,
463}
464
465impl<A, B, C, D, E, F, G, H> Iterator for Zip8Iterator<A, B, C, D, E, F, G, H>
466where
467    A: Iterator,
468    B: Iterator,
469    C: Iterator,
470    D: Iterator,
471    E: Iterator,
472    F: Iterator,
473    G: Iterator,
474    H: Iterator,
475{
476    type Item = (A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item, H::Item);
477
478    fn next(&mut self) -> Option<Self::Item> {
479        match (self.a.next(), self.b.next(), self.c.next(), self.d.next(), self.e.next(), self.f.next(), self.g.next(), self.h.next()) {
480            (Some(a), Some(b), Some(c), Some(d), Some(e), Some(f), Some(g), Some(h)) => Some((a, b, c, d, e, f, g, h)),
481            _ => None,
482        }
483    }
484}
485
486/// Iterator for zipping 9 sequences.
487pub struct Zip9Iterator<A, B, C, D, E, F, G, H, I> {
488    a: A,
489    b: B,
490    c: C,
491    d: D,
492    e: E,
493    f: F,
494    g: G,
495    h: H,
496    i: I,
497}
498
499impl<A, B, C, D, E, F, G, H, I> Iterator for Zip9Iterator<A, B, C, D, E, F, G, H, I>
500where
501    A: Iterator,
502    B: Iterator,
503    C: Iterator,
504    D: Iterator,
505    E: Iterator,
506    F: Iterator,
507    G: Iterator,
508    H: Iterator,
509    I: Iterator,
510{
511    type Item = (A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item, H::Item, I::Item);
512
513    fn next(&mut self) -> Option<Self::Item> {
514        match (self.a.next(), self.b.next(), self.c.next(), self.d.next(), self.e.next(), self.f.next(), self.g.next(), self.h.next(), self.i.next()) {
515            (Some(a), Some(b), Some(c), Some(d), Some(e), Some(f), Some(g), Some(h), Some(i)) => Some((a, b, c, d, e, f, g, h, i)),
516            _ => None,
517        }
518    }
519}
520
521/// Iterator for zipping 10 sequences.
522pub struct Zip10Iterator<A, B, C, D, E, F, G, H, I, J> {
523    a: A,
524    b: B,
525    c: C,
526    d: D,
527    e: E,
528    f: F,
529    g: G,
530    h: H,
531    i: I,
532    j: J,
533}
534
535impl<A, B, C, D, E, F, G, H, I, J> Iterator for Zip10Iterator<A, B, C, D, E, F, G, H, I, J>
536where
537    A: Iterator,
538    B: Iterator,
539    C: Iterator,
540    D: Iterator,
541    E: Iterator,
542    F: Iterator,
543    G: Iterator,
544    H: Iterator,
545    I: Iterator,
546    J: Iterator,
547{
548    type Item = (A::Item, B::Item, C::Item, D::Item, E::Item, F::Item, G::Item, H::Item, I::Item, J::Item);
549
550    fn next(&mut self) -> Option<Self::Item> {
551        match (self.a.next(), self.b.next(), self.c.next(), self.d.next(), self.e.next(), self.f.next(), self.g.next(), self.h.next(), self.i.next(), self.j.next()) {
552            (Some(a), Some(b), Some(c), Some(d), Some(e), Some(f), Some(g), Some(h), Some(i), Some(j)) => Some((a, b, c, d, e, f, g, h, i, j)),
553            _ => None,
554        }
555    }
556}
557
558#[cfg(test)]
559mod tests {
560    use super::*;
561
562    #[test]
563    fn test_zip3() {
564        let a = vec![1, 2, 3];
565        let b = vec![4, 5, 6];
566        let c = vec![7, 8, 9];
567        
568        let zipped: Vec<_> = zip3(a, b, c).collect();
569        assert_eq!(zipped, vec![(1, 4, 7), (2, 5, 8), (3, 6, 9)]);
570    }
571
572    #[test]
573    fn test_zip3_with() {
574        let a = vec![1, 2, 3];
575        let b = vec![4, 5, 6];
576        let c = vec![7, 8, 9];
577        
578        let result = zip3_with(|x, y, z| x + y + z, a, b, c);
579        assert_eq!(result, vec![12, 15, 18]);
580    }
581
582    #[test]
583    fn test_zip4() {
584        let a = vec![1, 2, 3];
585        let b = vec![4, 5, 6];
586        let c = vec![7, 8, 9];
587        let d = vec![10, 11, 12];
588        
589        let zipped: Vec<_> = zip4(a, b, c, d).collect();
590        assert_eq!(zipped, vec![(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]);
591    }
592
593    #[test]
594    fn test_zip4_with() {
595        let a = vec![1, 2, 3];
596        let b = vec![4, 5, 6];
597        let c = vec![7, 8, 9];
598        let d = vec![10, 11, 12];
599        
600        let result = zip4_with(|w, x, y, z| w + x + y + z, a, b, c, d);
601        assert_eq!(result, vec![22, 26, 30]);
602    }
603
604    #[test]
605    fn test_zip5() {
606        let a = vec![1, 2, 3];
607        let b = vec![4, 5, 6];
608        let c = vec![7, 8, 9];
609        let d = vec![10, 11, 12];
610        let e = vec![13, 14, 15];
611        
612        let zipped: Vec<_> = zip5(a, b, c, d, e).collect();
613        assert_eq!(zipped, vec![(1, 4, 7, 10, 13), (2, 5, 8, 11, 14), (3, 6, 9, 12, 15)]);
614    }
615
616    #[test]
617    fn test_zip5_with() {
618        let a = vec![1, 2, 3];
619        let b = vec![4, 5, 6];
620        let c = vec![7, 8, 9];
621        let d = vec![10, 11, 12];
622        let e = vec![13, 14, 15];
623        
624        let result = zip5_with(|v, w, x, y, z| v + w + x + y + z, a, b, c, d, e);
625        assert_eq!(result, vec![35, 40, 45]);
626    }
627
628    #[test]
629    fn test_zip_different_lengths() {
630        let a = vec![1, 2, 3, 4];
631        let b = vec![5, 6];
632        let c = vec![7, 8, 9];
633        
634        let zipped: Vec<_> = zip3(a, b, c).collect();
635        assert_eq!(zipped, vec![(1, 5, 7), (2, 6, 8)]);
636    }
637
638    #[test]
639    fn test_zip_with_strings() {
640        let names = vec!["Alice", "Bob", "Charlie"];
641        let ages = vec![25, 30, 35];
642        let cities = vec!["New York", "London", "Tokyo"];
643        
644        let result = zip3_with(|name, age, city| format!("{} is {} years old and lives in {}", name, age, city), names, ages, cities);
645        assert_eq!(result, vec![
646            "Alice is 25 years old and lives in New York",
647            "Bob is 30 years old and lives in London",
648            "Charlie is 35 years old and lives in Tokyo"
649        ]);
650    }
651}