1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2
3pub enum ZipOptional<A, B> {
4 Some { a: A, b: B },
5 None { a: A },
6}
7
8impl<A, B> Iterator for ZipOptional<A, B>
9where
10 A: Iterator,
11 B: Iterator,
12{
13 type Item = (A::Item, Option<B::Item>);
14
15 fn next(&mut self) -> Option<Self::Item> {
16 match self {
17 Self::None { a } => a.next().map(|a| (a, None)),
18 Self::Some { a, b } => {
19 let a = a.next()?;
20 let b = b.next()?;
21 Some((a, Some(b)))
22 }
23 }
24 }
25}
26
27pub fn zip_optional<A, B>(a: A, b: Option<B>) -> ZipOptional<A::IntoIter, B::IntoIter>
28where
29 A: IntoIterator,
30 B: IntoIterator,
31{
32 match b {
33 Some(b) => ZipOptional::Some {
34 a: a.into_iter(),
35 b: b.into_iter(),
36 },
37 None => ZipOptional::None { a: a.into_iter() },
38 }
39}
40
41pub trait Zippable<B>
42where
43 Self: Sized,
44 B: IntoIterator,
45{
46 fn zip_optional(self, b: Option<B>) -> ZipOptional<Self, B::IntoIter>;
47}
48
49impl<I, B> Zippable<B> for I
50where
51 I: Iterator,
52 B: IntoIterator,
53{
54 fn zip_optional(self, b: Option<B>) -> ZipOptional<Self, B::IntoIter> {
55 crate::zip_optional(self, b)
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn test_zip_optional_some() {
65 let a = vec![1, 2];
66 let b = Some(vec![1, 2]);
67
68 let mut zipped = zip_optional(a, b);
69 assert_eq!(zipped.next().unwrap(), (1, Some(1)));
70 assert_eq!(zipped.next().unwrap(), (2, Some(2)));
71 assert_eq!(zipped.next(), None);
72 }
73
74 #[test]
75 fn test_zip_optional_none() {
76 let a = vec![1, 2];
77
78 let mut zipped = zip_optional(a, None::<Vec<i32>>);
79 assert_eq!(zipped.next().unwrap(), (1, None));
80 assert_eq!(zipped.next().unwrap(), (2, None));
81 assert_eq!(zipped.next(), None);
82 }
83
84 #[test]
85 fn test_zip_optional_empty() {
86 let a = Vec::<i32>::new();
87
88 let mut zipped = zip_optional(a, None::<Vec<i32>>);
89 assert_eq!(zipped.next(), None);
90 }
91
92 #[test]
93 fn test_zip_optional_iter_none() {
94 let mut zipped = vec![1, 2].into_iter().zip_optional(None::<Vec<i32>>);
95 assert_eq!(zipped.next().unwrap(), (1, None));
96 assert_eq!(zipped.next().unwrap(), (2, None));
97 assert_eq!(zipped.next(), None);
98 }
99
100 #[test]
101 fn test_zip_optional_iter_some() {
102 let mut zipped = vec![1, 2].into_iter().zip_optional(Some(vec![1, 2]));
103 assert_eq!(zipped.next().unwrap(), (1, Some(1)));
104 assert_eq!(zipped.next().unwrap(), (2, Some(2)));
105 assert_eq!(zipped.next(), None);
106 }
107
108 #[test]
109 fn test_zip_optional_iter_empty() {
110 let mut zipped = Vec::<i32>::new().into_iter().zip_optional(None::<Vec<i32>>);
111 assert_eq!(zipped.next(), None);
112 }
113
114 #[test]
115 fn test_zip_optional_longer_non_optional() {
116 let mut zipped = vec![1, 2].into_iter().zip_optional(Some(vec![1]));
117 assert_eq!(zipped.next().unwrap(), (1, Some(1)));
118 assert_eq!(zipped.next(), None);
119 }
120
121 #[test]
122 fn test_zip_optional_longer_optional() {
123 let mut zipped = vec![1].into_iter().zip_optional(Some(vec![1, 2]));
124 assert_eq!(zipped.next().unwrap(), (1, Some(1)));
125 assert_eq!(zipped.next(), None);
126 }
127}