1 #![allow(unstable_name_collisions)]
2
3 use itertools::Itertools;
4 use quickcheck::Arbitrary;
5 use quickcheck::{quickcheck, TestResult};
6 use rand::Rng;
7 use std::fmt::Debug;
8
9 struct Unspecialized<I>(I);
10
11 impl<I> Iterator for Unspecialized<I>
12 where
13 I: Iterator,
14 {
15 type Item = I::Item;
16
17 #[inline(always)]
next(&mut self) -> Option<Self::Item>18 fn next(&mut self) -> Option<Self::Item> {
19 self.0.next()
20 }
21 }
22
23 impl<I> DoubleEndedIterator for Unspecialized<I>
24 where
25 I: DoubleEndedIterator,
26 {
27 #[inline(always)]
next_back(&mut self) -> Option<Self::Item>28 fn next_back(&mut self) -> Option<Self::Item> {
29 self.0.next_back()
30 }
31 }
32
test_specializations<I>(it: &I) where I::Item: Eq + Debug + Clone, I: Iterator + Clone,33 fn test_specializations<I>(it: &I)
34 where
35 I::Item: Eq + Debug + Clone,
36 I: Iterator + Clone,
37 {
38 macro_rules! check_specialized {
39 ($src:expr, |$it:pat| $closure:expr) => {
40 // Many iterators special-case the first elements, so we test specializations for iterators that have already been advanced.
41 let mut src = $src.clone();
42 for _ in 0..5 {
43 let $it = src.clone();
44 let v1 = $closure;
45 let $it = Unspecialized(src.clone());
46 let v2 = $closure;
47 assert_eq!(v1, v2);
48 src.next();
49 }
50 }
51 }
52 check_specialized!(it, |i| i.count());
53 check_specialized!(it, |i| i.last());
54 check_specialized!(it, |i| i.collect::<Vec<_>>());
55 check_specialized!(it, |i| {
56 let mut parameters_from_fold = vec![];
57 let fold_result = i.fold(vec![], |mut acc, v: I::Item| {
58 parameters_from_fold.push((acc.clone(), v.clone()));
59 acc.push(v);
60 acc
61 });
62 (parameters_from_fold, fold_result)
63 });
64 check_specialized!(it, |mut i| {
65 let mut parameters_from_all = vec![];
66 let first = i.next();
67 let all_result = i.all(|x| {
68 parameters_from_all.push(x.clone());
69 Some(x) == first
70 });
71 (parameters_from_all, all_result)
72 });
73 let size = it.clone().count();
74 for n in 0..size + 2 {
75 check_specialized!(it, |mut i| i.nth(n));
76 }
77 // size_hint is a bit harder to check
78 let mut it_sh = it.clone();
79 for n in 0..size + 2 {
80 let len = it_sh.clone().count();
81 let (min, max) = it_sh.size_hint();
82 assert_eq!(size - n.min(size), len);
83 assert!(min <= len);
84 if let Some(max) = max {
85 assert!(len <= max);
86 }
87 it_sh.next();
88 }
89 }
90
test_double_ended_specializations<I>(it: &I) where I::Item: Eq + Debug + Clone, I: DoubleEndedIterator + Clone,91 fn test_double_ended_specializations<I>(it: &I)
92 where
93 I::Item: Eq + Debug + Clone,
94 I: DoubleEndedIterator + Clone,
95 {
96 macro_rules! check_specialized {
97 ($src:expr, |$it:pat| $closure:expr) => {
98 // Many iterators special-case the first elements, so we test specializations for iterators that have already been advanced.
99 let mut src = $src.clone();
100 for step in 0..8 {
101 let $it = src.clone();
102 let v1 = $closure;
103 let $it = Unspecialized(src.clone());
104 let v2 = $closure;
105 assert_eq!(v1, v2);
106 if step % 2 == 0 {
107 src.next();
108 } else {
109 src.next_back();
110 }
111 }
112 }
113 }
114 check_specialized!(it, |i| {
115 let mut parameters_from_rfold = vec![];
116 let rfold_result = i.rfold(vec![], |mut acc, v: I::Item| {
117 parameters_from_rfold.push((acc.clone(), v.clone()));
118 acc.push(v);
119 acc
120 });
121 (parameters_from_rfold, rfold_result)
122 });
123 let size = it.clone().count();
124 for n in 0..size + 2 {
125 check_specialized!(it, |mut i| i.nth_back(n));
126 }
127 }
128
129 quickcheck! {
130 fn interleave(v: Vec<u8>, w: Vec<u8>) -> () {
131 test_specializations(&v.iter().interleave(w.iter()));
132 }
133
134 fn interleave_shortest(v: Vec<u8>, w: Vec<u8>) -> () {
135 test_specializations(&v.iter().interleave_shortest(w.iter()));
136 }
137
138 fn batching(v: Vec<u8>) -> () {
139 test_specializations(&v.iter().batching(Iterator::next));
140 }
141
142 fn tuple_windows(v: Vec<u8>) -> () {
143 test_specializations(&v.iter().tuple_windows::<(_,)>());
144 test_specializations(&v.iter().tuple_windows::<(_, _)>());
145 test_specializations(&v.iter().tuple_windows::<(_, _, _)>());
146 }
147
148 fn circular_tuple_windows(v: Vec<u8>) -> () {
149 test_specializations(&v.iter().circular_tuple_windows::<(_,)>());
150 test_specializations(&v.iter().circular_tuple_windows::<(_, _)>());
151 test_specializations(&v.iter().circular_tuple_windows::<(_, _, _)>());
152 }
153
154 fn tuples(v: Vec<u8>) -> () {
155 test_specializations(&v.iter().tuples::<(_,)>());
156 test_specializations(&v.iter().tuples::<(_, _)>());
157 test_specializations(&v.iter().tuples::<(_, _, _)>());
158 }
159
160 fn cartesian_product(a: Vec<u8>, b: Vec<u8>) -> TestResult {
161 if a.len() * b.len() > 100 {
162 return TestResult::discard();
163 }
164 test_specializations(&a.iter().cartesian_product(&b));
165 TestResult::passed()
166 }
167
168 fn multi_cartesian_product(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
169 if a.len() * b.len() * c.len() > 100 {
170 return TestResult::discard();
171 }
172 test_specializations(&vec![a, b, c].into_iter().multi_cartesian_product());
173 TestResult::passed()
174 }
175
176 fn coalesce(v: Vec<u8>) -> () {
177 test_specializations(&v.iter().coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) }))
178 }
179
180 fn dedup(v: Vec<u8>) -> () {
181 test_specializations(&v.iter().dedup())
182 }
183
184 fn dedup_by(v: Vec<u8>) -> () {
185 test_specializations(&v.iter().dedup_by(PartialOrd::ge))
186 }
187
188 fn dedup_with_count(v: Vec<u8>) -> () {
189 test_specializations(&v.iter().dedup_with_count())
190 }
191
192 fn dedup_by_with_count(v: Vec<u8>) -> () {
193 test_specializations(&v.iter().dedup_by_with_count(PartialOrd::ge))
194 }
195
196 fn duplicates(v: Vec<u8>) -> () {
197 let it = v.iter().duplicates();
198 test_specializations(&it);
199 test_double_ended_specializations(&it);
200 }
201
202 fn duplicates_by(v: Vec<u8>) -> () {
203 let it = v.iter().duplicates_by(|x| *x % 10);
204 test_specializations(&it);
205 test_double_ended_specializations(&it);
206 }
207
208 fn unique(v: Vec<u8>) -> () {
209 let it = v.iter().unique();
210 test_specializations(&it);
211 test_double_ended_specializations(&it);
212 }
213
214 fn unique_by(v: Vec<u8>) -> () {
215 let it = v.iter().unique_by(|x| *x % 50);
216 test_specializations(&it);
217 test_double_ended_specializations(&it);
218 }
219
220 fn take_while_inclusive(v: Vec<u8>) -> () {
221 test_specializations(&v.iter().copied().take_while_inclusive(|&x| x < 100));
222 }
223
224 fn while_some(v: Vec<u8>) -> () {
225 test_specializations(&v.iter().map(|&x| if x < 100 { Some(2 * x) } else { None }).while_some());
226 }
227
228 fn pad_using(v: Vec<u8>) -> () {
229 use std::convert::TryFrom;
230 let it = v.iter().copied().pad_using(10, |i| u8::try_from(5 * i).unwrap_or(u8::MAX));
231 test_specializations(&it);
232 test_double_ended_specializations(&it);
233 }
234
235 fn with_position(v: Vec<u8>) -> () {
236 test_specializations(&v.iter().with_position());
237 }
238
239 fn positions(v: Vec<u8>) -> () {
240 let it = v.iter().positions(|x| x % 5 == 0);
241 test_specializations(&it);
242 test_double_ended_specializations(&it);
243 }
244
245 fn update(v: Vec<u8>) -> () {
246 let it = v.iter().copied().update(|x| *x = x.wrapping_mul(7));
247 test_specializations(&it);
248 test_double_ended_specializations(&it);
249 }
250
251 fn tuple_combinations(v: Vec<u8>) -> TestResult {
252 if v.len() > 10 {
253 return TestResult::discard();
254 }
255 test_specializations(&v.iter().tuple_combinations::<(_,)>());
256 test_specializations(&v.iter().tuple_combinations::<(_, _)>());
257 test_specializations(&v.iter().tuple_combinations::<(_, _, _)>());
258 TestResult::passed()
259 }
260
261 fn intersperse(v: Vec<u8>) -> () {
262 test_specializations(&v.into_iter().intersperse(0));
263 }
264
265 fn intersperse_with(v: Vec<u8>) -> () {
266 test_specializations(&v.into_iter().intersperse_with(|| 0));
267 }
268
269 fn combinations(a: Vec<u8>, n: u8) -> TestResult {
270 if n > 3 || a.len() > 8 {
271 return TestResult::discard();
272 }
273 test_specializations(&a.iter().combinations(n as usize));
274 TestResult::passed()
275 }
276
277 fn combinations_with_replacement(a: Vec<u8>, n: u8) -> TestResult {
278 if n > 3 || a.len() > 7 {
279 return TestResult::discard();
280 }
281 test_specializations(&a.iter().combinations_with_replacement(n as usize));
282 TestResult::passed()
283 }
284
285 fn permutations(a: Vec<u8>, n: u8) -> TestResult {
286 if n > 3 || a.len() > 8 {
287 return TestResult::discard();
288 }
289 test_specializations(&a.iter().permutations(n as usize));
290 TestResult::passed()
291 }
292
293 fn powerset(a: Vec<u8>) -> TestResult {
294 if a.len() > 6 {
295 return TestResult::discard();
296 }
297 test_specializations(&a.iter().powerset());
298 TestResult::passed()
299 }
300
301 fn zip_longest(a: Vec<u8>, b: Vec<u8>) -> () {
302 let it = a.into_iter().zip_longest(b);
303 test_specializations(&it);
304 test_double_ended_specializations(&it);
305 }
306
307 fn zip_eq(a: Vec<u8>) -> () {
308 test_specializations(&a.iter().zip_eq(a.iter().rev()))
309 }
310
311 fn multizip(a: Vec<u8>) -> () {
312 let it = itertools::multizip((a.iter(), a.iter().rev(), a.iter().take(50)));
313 test_specializations(&it);
314 test_double_ended_specializations(&it);
315 }
316
317 fn izip(a: Vec<u8>, b: Vec<u8>) -> () {
318 test_specializations(&itertools::izip!(b.iter(), a, b.iter().rev()));
319 }
320
321 fn iproduct(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
322 if a.len() * b.len() * c.len() > 200 {
323 return TestResult::discard();
324 }
325 test_specializations(&itertools::iproduct!(a, b.iter(), c));
326 TestResult::passed()
327 }
328
329 fn repeat_n(element: i8, n: u8) -> () {
330 let it = itertools::repeat_n(element, n as usize);
331 test_specializations(&it);
332 test_double_ended_specializations(&it);
333 }
334
335 fn exactly_one_error(v: Vec<u8>) -> TestResult {
336 // Use `at_most_one` would be similar.
337 match v.iter().exactly_one() {
338 Ok(_) => TestResult::discard(),
339 Err(it) => {
340 test_specializations(&it);
341 TestResult::passed()
342 }
343 }
344 }
345 }
346
347 quickcheck! {
348 fn put_back_qc(test_vec: Vec<i32>) -> () {
349 test_specializations(&itertools::put_back(test_vec.iter()));
350 let mut pb = itertools::put_back(test_vec.into_iter());
351 pb.put_back(1);
352 test_specializations(&pb);
353 }
354
355 fn put_back_n(v: Vec<u8>, n: u8) -> () {
356 let mut it = itertools::put_back_n(v);
357 for k in 0..n {
358 it.put_back(k);
359 }
360 test_specializations(&it);
361 }
362
363 fn multipeek(v: Vec<u8>, n: u8) -> () {
364 let mut it = v.into_iter().multipeek();
365 for _ in 0..n {
366 it.peek();
367 }
368 test_specializations(&it);
369 }
370
371 fn peek_nth_with_peek(v: Vec<u8>, n: u8) -> () {
372 let mut it = itertools::peek_nth(v);
373 for _ in 0..n {
374 it.peek();
375 }
376 test_specializations(&it);
377 }
378
379 fn peek_nth_with_peek_nth(v: Vec<u8>, n: u8) -> () {
380 let mut it = itertools::peek_nth(v);
381 it.peek_nth(n as usize);
382 test_specializations(&it);
383 }
384
385 fn peek_nth_with_peek_mut(v: Vec<u8>, n: u8) -> () {
386 let mut it = itertools::peek_nth(v);
387 for _ in 0..n {
388 if let Some(x) = it.peek_mut() {
389 *x = x.wrapping_add(50);
390 }
391 }
392 test_specializations(&it);
393 }
394
395 fn peek_nth_with_peek_nth_mut(v: Vec<u8>, n: u8) -> () {
396 let mut it = itertools::peek_nth(v);
397 if let Some(x) = it.peek_nth_mut(n as usize) {
398 *x = x.wrapping_add(50);
399 }
400 test_specializations(&it);
401 }
402 }
403
404 quickcheck! {
405 fn merge(a: Vec<u8>, b: Vec<u8>) -> () {
406 test_specializations(&a.into_iter().merge(b))
407 }
408
409 fn merge_by(a: Vec<u8>, b: Vec<u8>) -> () {
410 test_specializations(&a.into_iter().merge_by(b, PartialOrd::ge))
411 }
412
413 fn merge_join_by_ordering(i1: Vec<u8>, i2: Vec<u8>) -> () {
414 test_specializations(&i1.into_iter().merge_join_by(i2, Ord::cmp));
415 }
416
417 fn merge_join_by_bool(i1: Vec<u8>, i2: Vec<u8>) -> () {
418 test_specializations(&i1.into_iter().merge_join_by(i2, PartialOrd::ge));
419 }
420
421 fn kmerge(a: Vec<i8>, b: Vec<i8>, c: Vec<i8>) -> () {
422 test_specializations(&vec![a, b, c]
423 .into_iter()
424 .map(|v| v.into_iter().sorted())
425 .kmerge());
426 }
427
428 fn kmerge_by(a: Vec<i8>, b: Vec<i8>, c: Vec<i8>) -> () {
429 test_specializations(&vec![a, b, c]
430 .into_iter()
431 .map(|v| v.into_iter().sorted_by_key(|a| a.abs()))
432 .kmerge_by(|a, b| a.abs() < b.abs()));
433 }
434 }
435
436 quickcheck! {
437 fn map_into(v: Vec<u8>) -> () {
438 let it = v.into_iter().map_into::<u32>();
439 test_specializations(&it);
440 test_double_ended_specializations(&it);
441 }
442
443 fn map_ok(v: Vec<Result<u8, char>>) -> () {
444 let it = v.into_iter().map_ok(|u| u.checked_add(1));
445 test_specializations(&it);
446 test_double_ended_specializations(&it);
447 }
448
449 fn filter_ok(v: Vec<Result<u8, char>>) -> () {
450 test_specializations(&v.into_iter().filter_ok(|&i| i < 20));
451 }
452
453 fn filter_map_ok(v: Vec<Result<u8, char>>) -> () {
454 test_specializations(&v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None }));
455 }
456
457 // `SmallIter2<u8>` because `Vec<u8>` is too slow and we get bad coverage from a singleton like Option<u8>
458 fn flatten_ok(v: Vec<Result<SmallIter2<u8>, char>>) -> () {
459 let it = v.into_iter().flatten_ok();
460 test_specializations(&it);
461 test_double_ended_specializations(&it);
462 }
463 }
464
465 quickcheck! {
466 // TODO Replace this function by a normal call to test_specializations
467 fn process_results(v: Vec<Result<u8, u8>>) -> () {
468 helper(v.iter().copied());
469 helper(v.iter().copied().filter(Result::is_ok));
470
471 fn helper(it: impl DoubleEndedIterator<Item = Result<u8, u8>> + Clone) {
472 macro_rules! check_results_specialized {
473 ($src:expr, |$it:pat| $closure:expr) => {
474 assert_eq!(
475 itertools::process_results($src.clone(), |$it| $closure),
476 itertools::process_results($src.clone(), |i| {
477 let $it = Unspecialized(i);
478 $closure
479 }),
480 )
481 }
482 }
483
484 check_results_specialized!(it, |i| i.count());
485 check_results_specialized!(it, |i| i.last());
486 check_results_specialized!(it, |i| i.collect::<Vec<_>>());
487 check_results_specialized!(it, |i| i.rev().collect::<Vec<_>>());
488 check_results_specialized!(it, |i| {
489 let mut parameters_from_fold = vec![];
490 let fold_result = i.fold(vec![], |mut acc, v| {
491 parameters_from_fold.push((acc.clone(), v));
492 acc.push(v);
493 acc
494 });
495 (parameters_from_fold, fold_result)
496 });
497 check_results_specialized!(it, |i| {
498 let mut parameters_from_rfold = vec![];
499 let rfold_result = i.rfold(vec![], |mut acc, v| {
500 parameters_from_rfold.push((acc.clone(), v));
501 acc.push(v);
502 acc
503 });
504 (parameters_from_rfold, rfold_result)
505 });
506 check_results_specialized!(it, |mut i| {
507 let mut parameters_from_all = vec![];
508 let first = i.next();
509 let all_result = i.all(|x| {
510 parameters_from_all.push(x);
511 Some(x)==first
512 });
513 (parameters_from_all, all_result)
514 });
515 let size = it.clone().count();
516 for n in 0..size + 2 {
517 check_results_specialized!(it, |mut i| i.nth(n));
518 }
519 for n in 0..size + 2 {
520 check_results_specialized!(it, |mut i| i.nth_back(n));
521 }
522 }
523 }
524 }
525
526 /// Like `VecIntoIter<T>` with maximum 2 elements.
527 #[derive(Debug, Clone, Default)]
528 enum SmallIter2<T> {
529 #[default]
530 Zero,
531 One(T),
532 Two(T, T),
533 }
534
535 impl<T: Arbitrary> Arbitrary for SmallIter2<T> {
arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self536 fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
537 match g.gen_range(0u8, 3) {
538 0 => Self::Zero,
539 1 => Self::One(T::arbitrary(g)),
540 2 => Self::Two(T::arbitrary(g), T::arbitrary(g)),
541 _ => unreachable!(),
542 }
543 }
544 // maybe implement shrink too, maybe not
545 }
546
547 impl<T> Iterator for SmallIter2<T> {
548 type Item = T;
549
next(&mut self) -> Option<Self::Item>550 fn next(&mut self) -> Option<Self::Item> {
551 match std::mem::take(self) {
552 Self::Zero => None,
553 Self::One(val) => Some(val),
554 Self::Two(val, second) => {
555 *self = Self::One(second);
556 Some(val)
557 }
558 }
559 }
560
size_hint(&self) -> (usize, Option<usize>)561 fn size_hint(&self) -> (usize, Option<usize>) {
562 let len = match self {
563 Self::Zero => 0,
564 Self::One(_) => 1,
565 Self::Two(_, _) => 2,
566 };
567 (len, Some(len))
568 }
569 }
570
571 impl<T> DoubleEndedIterator for SmallIter2<T> {
next_back(&mut self) -> Option<Self::Item>572 fn next_back(&mut self) -> Option<Self::Item> {
573 match std::mem::take(self) {
574 Self::Zero => None,
575 Self::One(val) => Some(val),
576 Self::Two(first, val) => {
577 *self = Self::One(first);
578 Some(val)
579 }
580 }
581 }
582 }
583