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}