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