1 use itertools::Itertools;
2 use std::fmt::Debug;
3 use quickcheck::quickcheck;
4 
5 struct Unspecialized<I>(I);
6 impl<I> Iterator for Unspecialized<I>
7 where
8     I: Iterator,
9 {
10     type Item = I::Item;
11 
12     #[inline(always)]
next(&mut self) -> Option<Self::Item>13     fn next(&mut self) -> Option<Self::Item> {
14         self.0.next()
15     }
16 }
17 
18 macro_rules! check_specialized {
19     ($src:expr, |$it:pat| $closure:expr) => {
20         let $it = $src.clone();
21         let v1 = $closure;
22 
23         let $it = Unspecialized($src.clone());
24         let v2 = $closure;
25 
26         assert_eq!(v1, v2);
27     }
28 }
29 
test_specializations<IterItem, Iter>( it: &Iter, ) where IterItem: Eq + Debug + Clone, Iter: Iterator<Item = IterItem> + Clone,30 fn test_specializations<IterItem, Iter>(
31     it: &Iter,
32 ) where
33     IterItem: Eq + Debug + Clone,
34     Iter: Iterator<Item = IterItem> + Clone,
35 {
36     check_specialized!(it, |i| i.count());
37     check_specialized!(it, |i| i.last());
38     check_specialized!(it, |i| i.collect::<Vec<_>>());
39     check_specialized!(it, |i| {
40         let mut parameters_from_fold = vec![];
41         let fold_result = i.fold(vec![], |mut acc, v: IterItem| {
42             parameters_from_fold.push((acc.clone(), v.clone()));
43             acc.push(v);
44             acc
45         });
46         (parameters_from_fold, fold_result)
47     });
48     check_specialized!(it, |mut i| {
49         let mut parameters_from_all = vec![];
50         let first = i.next();
51         let all_result = i.all(|x| {
52             parameters_from_all.push(x.clone());
53             Some(x)==first
54         });
55         (parameters_from_all, all_result)
56     });
57     let size = it.clone().count();
58     for n in 0..size + 2 {
59         check_specialized!(it, |mut i| i.nth(n));
60     }
61     // size_hint is a bit harder to check
62     let mut it_sh = it.clone();
63     for n in 0..size + 2 {
64         let len = it_sh.clone().count();
65         let (min, max) = it_sh.size_hint();
66         assert_eq!(size - n.min(size), len);
67         assert!(min <= len);
68         if let Some(max) = max {
69             assert!(len <= max);
70         }
71         it_sh.next();
72     }
73 }
74 
75 quickcheck! {
76     fn intersperse(v: Vec<u8>) -> () {
77         test_specializations(&v.into_iter().intersperse(0));
78     }
79 }
80 
81 quickcheck! {
82     fn put_back_qc(test_vec: Vec<i32>) -> () {
83         test_specializations(&itertools::put_back(test_vec.iter()));
84         let mut pb = itertools::put_back(test_vec.into_iter());
85         pb.put_back(1);
86         test_specializations(&pb);
87     }
88 }
89 
90 quickcheck! {
91     fn merge_join_by_qc(i1: Vec<usize>, i2: Vec<usize>) -> () {
92         test_specializations(&i1.into_iter().merge_join_by(i2.into_iter(), std::cmp::Ord::cmp));
93     }
94 }
95 
96 quickcheck! {
97     fn map_into(v: Vec<u8>) -> () {
98         test_specializations(&v.into_iter().map_into::<u32>());
99     }
100 }
101 
102 quickcheck! {
103     fn map_ok(v: Vec<Result<u8, char>>) -> () {
104         test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1)));
105     }
106 }
107 
108 quickcheck! {
109     fn process_results(v: Vec<Result<u8, u8>>) -> () {
110         helper(v.iter().copied());
111         helper(v.iter().copied().filter(Result::is_ok));
112 
113         fn helper(it: impl Iterator<Item = Result<u8, u8>> + Clone) {
114             macro_rules! check_results_specialized {
115                 ($src:expr, |$it:pat| $closure:expr) => {
116                     assert_eq!(
117                         itertools::process_results($src.clone(), |$it| $closure),
118                         itertools::process_results($src.clone(), |i| {
119                             let $it = Unspecialized(i);
120                             $closure
121                         }),
122                     )
123                 }
124             }
125 
126             check_results_specialized!(it, |i| i.count());
127             check_results_specialized!(it, |i| i.last());
128             check_results_specialized!(it, |i| i.collect::<Vec<_>>());
129             check_results_specialized!(it, |i| {
130                 let mut parameters_from_fold = vec![];
131                 let fold_result = i.fold(vec![], |mut acc, v| {
132                     parameters_from_fold.push((acc.clone(), v.clone()));
133                     acc.push(v);
134                     acc
135                 });
136                 (parameters_from_fold, fold_result)
137             });
138             check_results_specialized!(it, |mut i| {
139                 let mut parameters_from_all = vec![];
140                 let first = i.next();
141                 let all_result = i.all(|x| {
142                     parameters_from_all.push(x.clone());
143                     Some(x)==first
144                 });
145                 (parameters_from_all, all_result)
146             });
147             let size = it.clone().count();
148             for n in 0..size + 2 {
149                 check_results_specialized!(it, |mut i| i.nth(n));
150             }
151         }
152     }
153 }
154