1use {
2 core::convert::Infallible,
3 pbt::{
4 Pbt,
5 sigma::{Predicate, Sigma},
6 },
7};
8
9#[non_exhaustive]
10#[derive(Clone, Debug, Eq, PartialEq, Pbt)]
11pub enum Foo {
12 Bar,
13 Baz { a: u64, b: u64, c: Vec<Foo> },
14}
15
16#[derive(Clone, Debug, Eq, PartialEq, Pbt)]
17pub enum PartiallyInstantiable {
18 Instantiable,
19 Uninstantiable(Infallible),
20}
21
22#[derive(Clone, Debug, Eq, PartialEq, Pbt)]
23pub enum Uninhabited {}
24
25pub type NonAnswer = Sigma<u8, NotTheAnswer>;
26
27pub enum NotTheAnswer {}
28
29impl Foo {
30 #[inline]
31 #[must_use]
32 pub fn bus_factor(&self) -> usize {
33 match *self {
34 Self::Bar => 0,
35 Self::Baz { ref c, .. } => c.len(),
36 }
37 }
38}
39
40impl Predicate<u8> for NotTheAnswer {
41 type Error = String;
42
43 #[inline]
44 fn check(candidate: &u8) -> Result<(), Self::Error> {
45 if *candidate == 42 {
46 Err(format!(
47 "The Answer to the Ultimate Question of Life, the Universe, and Everything is {candidate}",
48 ))
49 } else {
50 Ok(())
51 }
52 }
53}
54
55#[cfg(test)]
56mod test {
57 use {super::*, pbt::search, pretty_assertions::assert_eq};
58
59 const N_CASES: usize = 1_000;
60
61 #[test]
62 fn instantiability_logic() {
63 search::assert_eq(N_CASES, |pi: &PartiallyInstantiable| {
64 (pi.clone(), PartiallyInstantiable::Instantiable)
65 });
66 }
67
68 #[test]
69 fn search_and_minimize() {
70 let maybe_witness: Option<Foo> =
71 search::witness(N_CASES, |foo: &Foo| foo.bus_factor() >= 3);
72 assert_eq!(
73 maybe_witness,
74 Some(Foo::Baz {
75 a: 0,
76 b: 0,
77 c: vec![Foo::Bar, Foo::Bar, Foo::Bar],
78 }),
79 );
80 }
81
82 #[test]
83 fn sigma() {
84 search::assert(N_CASES, |u: &NonAnswer| **u != 42);
85 }
86
87 #[test]
88 fn empty_enum_is_supported() {
89 let maybe_witness: Option<Uninhabited> = search::witness(N_CASES, |_| true);
90 assert_eq!(maybe_witness, None);
91 }
92}