computation_types/
cmp.rs

1use core::fmt;
2
3use paste::paste;
4
5use crate::{
6    impl_computation_fn_for_binary, impl_computation_fn_for_unary, impl_core_ops,
7    impl_display_for_inline_binary,
8    peano::{Suc, Zero},
9    Computation, ComputationFn, NamedArgs,
10};
11
12macro_rules! impl_cmp_op {
13    ( $op:ident, $where:ident ) => {
14        paste! {
15            #[derive(Clone, Copy, Debug)]
16            pub struct $op<A, B>(pub A, pub B)
17            where
18                Self: Computation;
19
20            impl<A, B> Computation for $op<A, B>
21            where
22                A: Computation<Dim = Zero>,
23                B: Computation<Dim = Zero>,
24                A::Item: $where<B::Item>
25            {
26                type Dim = Zero;
27                type Item = bool;
28            }
29
30            impl_computation_fn_for_binary!($op);
31
32            impl_core_ops!($op<A, B>);
33        }
34    };
35}
36
37impl_cmp_op!(Eq, PartialEq);
38impl_cmp_op!(Ne, PartialEq);
39impl_cmp_op!(Lt, PartialOrd);
40impl_cmp_op!(Le, PartialOrd);
41impl_cmp_op!(Gt, PartialOrd);
42impl_cmp_op!(Ge, PartialOrd);
43
44impl_display_for_inline_binary!(Eq, "==");
45impl_display_for_inline_binary!(Ne, "!=");
46impl_display_for_inline_binary!(Lt, "<");
47impl_display_for_inline_binary!(Le, "<=");
48impl_display_for_inline_binary!(Gt, ">");
49impl_display_for_inline_binary!(Ge, ">=");
50
51#[derive(Clone, Copy, Debug)]
52pub struct Max<A>(pub A)
53where
54    Self: Computation;
55
56impl<A, D> Computation for Max<A>
57where
58    A: Computation<Dim = Suc<D>>,
59    A::Item: PartialOrd,
60{
61    type Dim = Zero;
62    type Item = A::Item;
63}
64
65impl_computation_fn_for_unary!(Max);
66
67impl_core_ops!(Max<A>);
68
69impl<A> fmt::Display for Max<A>
70where
71    Self: Computation,
72    A: fmt::Display,
73{
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        write!(f, "{}.max()", self.0)
76    }
77}
78
79#[derive(Clone, Copy, Debug)]
80pub struct Not<A>(pub A)
81where
82    Self: Computation;
83
84impl<A> Computation for Not<A>
85where
86    A: Computation<Dim = Zero, Item = bool>,
87{
88    type Dim = Zero;
89    type Item = bool;
90}
91
92impl_computation_fn_for_unary!(Not);
93
94impl_core_ops!(Not<A>);
95
96impl<A> fmt::Display for Not<A>
97where
98    Self: Computation,
99    A: fmt::Display,
100{
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "!{}", self.0)
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use proptest::prelude::*;
109    use test_strategy::proptest;
110
111    use crate::{val, val1};
112
113    use super::*;
114
115    macro_rules! test_display {
116        ( $op:ident, $inline:tt ) => {
117            paste! {
118                #[proptest]
119                fn [<$op _should_ display>](x: i32, y: i32) {
120                    prop_assert_eq!(val!(x).$op(val!(y)).to_string(), format!("({} {} {})", x, stringify!($inline), y));
121                }
122            }
123        };
124    }
125
126    test_display!(eq, ==);
127    test_display!(ne, !=);
128    test_display!(lt, <);
129    test_display!(le, <=);
130    test_display!(gt, >);
131    test_display!(ge, >=);
132
133    #[proptest]
134    fn max_should_display(x: i32, y: i32, z: i32) {
135        prop_assert_eq!(
136            val1!([x, y, z]).max().to_string(),
137            format!("{}.max()", val1!([x, y, z]))
138        );
139    }
140
141    #[proptest]
142    fn not_should_display(x: i32, y: i32) {
143        let inp = val!(x).lt(val!(y));
144        prop_assert_eq!(inp.not().to_string(), format!("!{}", inp));
145    }
146}