Skip to content

Commit 568021d

Browse files
committed
Implement two-element 'vector' for flatten_ok test
Previously the test used Option<u8> but the coverage was bad. We cannot use Vec<u8> because it is too slow.
1 parent 10a8bb2 commit 568021d

File tree

1 file changed

+62
-2
lines changed

1 file changed

+62
-2
lines changed

tests/specializations.rs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#![allow(unstable_name_collisions)]
22

33
use itertools::Itertools;
4+
use quickcheck::Arbitrary;
45
use quickcheck::{quickcheck, TestResult};
6+
use rand::Rng;
57
use std::fmt::Debug;
68

79
struct Unspecialized<I>(I);
@@ -452,8 +454,8 @@ quickcheck! {
452454
test_specializations(&v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None }));
453455
}
454456

455-
// `Option<u8>` because `Vec<u8>` would be very slow!! And we can't give `[u8; 3]`.
456-
fn flatten_ok(v: Vec<Result<Option<u8>, char>>) -> () {
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>>) -> () {
457459
let it = v.into_iter().flatten_ok();
458460
test_specializations(&it);
459461
test_double_ended_specializations(&it);
@@ -520,3 +522,61 @@ quickcheck! {
520522
}
521523
}
522524
}
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> {
536+
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+
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+
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> {
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+
}

0 commit comments

Comments
 (0)