checkito/
filter.rs

1use crate::{
2    generate::{self, Generate, State},
3    shrink::Shrink,
4};
5
6#[derive(Clone, Debug)]
7pub struct Filter<G: ?Sized, F> {
8    pub(crate) filter: F,
9    pub(crate) retries: usize,
10    pub(crate) generator: G,
11}
12
13#[derive(Clone, Debug)]
14pub struct Shrinker<S, F> {
15    shrinker: Option<S>,
16    filter: F,
17}
18
19impl<G: Generate + ?Sized, F: Fn(&G::Item) -> bool + Clone> Generate for Filter<G, F> {
20    type Item = Option<G::Item>;
21    type Shrink = Shrinker<G::Shrink, F>;
22
23    fn generate(&self, state: &mut State) -> Self::Shrink {
24        let mut outer = None;
25        let size = state.size;
26        for i in 0..=self.retries {
27            state.size = generate::size(i, self.retries, size);
28            let inner = self.generator.generate(state);
29            let item = inner.item();
30            if (self.filter)(&item) {
31                outer = Some(inner);
32                break;
33            } else if self.constant() {
34                break;
35            }
36        }
37        state.size = size;
38        Shrinker {
39            shrinker: outer,
40            filter: self.filter.clone(),
41        }
42    }
43
44    fn constant(&self) -> bool {
45        self.generator.constant()
46    }
47}
48
49impl<S: Shrink, F: Fn(&S::Item) -> bool + Clone> Shrink for Shrinker<S, F> {
50    type Item = Option<S::Item>;
51
52    fn item(&self) -> Self::Item {
53        let item = self.shrinker.as_ref()?.item();
54        if (self.filter)(&item) {
55            Some(item)
56        } else {
57            None
58        }
59    }
60
61    fn shrink(&mut self) -> Option<Self> {
62        Some(Shrinker {
63            filter: self.filter.clone(),
64            shrinker: Some(self.shrinker.as_mut()?.shrink()?),
65        })
66    }
67}