xpct/matchers/collections/
every.rs

1use std::fmt;
2
3use crate::core::{DynTransformMatch, MatchOutcome, Matcher, TransformMatch};
4use crate::matchers::SomeFailures;
5
6/// The matcher for [`every`].
7///
8/// [`every`]: crate::every
9pub struct EveryMatcher<'a, PosOut, NegOut, IntoIter>
10where
11    IntoIter: IntoIterator + 'a,
12{
13    match_func: Box<dyn Fn() -> Matcher<'a, IntoIter::Item, PosOut, NegOut> + 'a>,
14}
15
16impl<'a, PosOut, NegOut, IntoIter> fmt::Debug for EveryMatcher<'a, PosOut, NegOut, IntoIter>
17where
18    IntoIter: IntoIterator + 'a,
19{
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        f.debug_struct("EveryMatcher").finish_non_exhaustive()
22    }
23}
24
25impl<'a, PosOut, NegOut, IntoIter> EveryMatcher<'a, PosOut, NegOut, IntoIter>
26where
27    IntoIter: IntoIterator + 'a,
28{
29    /// Create a new [`EveryMatcher`] from a function that returns a matcher.
30    pub fn new(match_func: impl Fn() -> Matcher<'a, IntoIter::Item, PosOut, NegOut> + 'a) -> Self {
31        Self {
32            match_func: Box::new(match_func),
33        }
34    }
35}
36
37impl<'a, PosOut, NegOut, IntoIter> TransformMatch for EveryMatcher<'a, PosOut, NegOut, IntoIter>
38where
39    IntoIter: IntoIterator + 'a,
40{
41    type In = IntoIter;
42
43    type PosOut = Vec<PosOut>;
44    type NegOut = Vec<NegOut>;
45
46    type PosFail = SomeFailures;
47    type NegFail = SomeFailures;
48
49    fn match_pos(
50        self,
51        actual: Self::In,
52    ) -> crate::Result<MatchOutcome<Self::PosOut, Self::PosFail>> {
53        let mut failures = Vec::new();
54        let mut successes = Vec::new();
55
56        for input in actual {
57            match Box::new((self.match_func)()).match_pos(input)? {
58                MatchOutcome::Success(success) => {
59                    failures.push(None);
60                    successes.push(success);
61                }
62                MatchOutcome::Fail(fail) => {
63                    failures.push(Some(fail));
64                }
65            }
66        }
67
68        if failures.iter().any(Option::is_some) {
69            return Ok(MatchOutcome::Fail(failures));
70        }
71
72        Ok(MatchOutcome::Success(successes))
73    }
74
75    fn match_neg(
76        self,
77        actual: Self::In,
78    ) -> crate::Result<MatchOutcome<Self::NegOut, Self::NegFail>> {
79        let mut failures = Vec::new();
80        let mut successes = Vec::new();
81
82        for input in actual {
83            match Box::new((self.match_func)()).match_neg(input)? {
84                MatchOutcome::Success(success) => {
85                    failures.push(None);
86                    successes.push(success);
87                }
88                MatchOutcome::Fail(fail) => {
89                    failures.push(Some(fail));
90                }
91            }
92        }
93
94        if failures.iter().any(Option::is_none) {
95            return Ok(MatchOutcome::Success(successes));
96        }
97
98        Ok(MatchOutcome::Fail(failures))
99    }
100}