deptypes/
ops.rs

1use crate::term::{Term, Value};
2use core::num::{Wrapping, Saturating};
3
4/// Asserts that all core::ops traits that are implemented are a constant function of the arguments (or panic)
5/// Meaning that for two sequences of arguments which are equal (according to Eq or TotalCmp for floats), then the results are also equal, if neither panics
6pub unsafe trait ConstOps {}
7
8macro_rules! impl_const_ops {
9    ($($T:ty)*) => {
10        $(unsafe impl ConstOps for $T {})*
11    };
12    (@int $($T:ty)*) => {
13        $(impl_const_ops! {$T Wrapping<$T> Saturating<$T>})*
14    }
15}
16
17impl_const_ops! {
18    ()
19    bool char    
20    f32 f64
21}
22
23impl_const_ops! {
24    @int 
25    u8 u16 u32 u64 u128 usize
26    i8 i16 i32 i64 i128 isize
27}
28
29#[cfg(feature = "never")]
30impl_const_ops! {!}
31
32macro_rules! impl_op2 {
33    ($($term:ident = $op:ident::$func:ident)*) => {
34        $(
35            term! {
36                /// Term that represents the arithmetic operation on the base type and whose evalutations just call the base type operation
37                pub fn $term(a, b) -> unsafe <a::Type as core::ops::$op<b::Type>>::Output
38                where a::Type: core::ops::$op<b::Type> + ConstOps {
39                    core::ops::$op::$func(a, b)
40                }
41            }
42
43            impl<A: Term, B: Term> core::ops::$op<Value<B>> for Value<A>
44                where A::Type: core::ops::$op<B::Type> + ConstOps {
45                type Output = Value<$term<A, B>>;
46
47                fn $func(self, b: Value<B>) -> Self::Output {
48                    $term(self, b)
49                }
50            }
51        )*
52    };
53}
54
55macro_rules! impl_op2_overflowing {
56    ($($xterm:ident $term:ident = $op:ident::$func:ident $cop:ident::$cfunc:ident)*) => {
57        $(
58            term! {
59                /// Term that represents the arithmetic operation on the base type and whose evalutations just call the base type operation
60                ///
61                /// For primitive integers, this may be the operation on mathematical integers or on the Z mod 2**b ring depending on whether overflow checks are on or not.
62                pub fn $xterm(a, b) -> unsafe <a::Type as core::ops::$op<b::Type>>::Output
63                where a::Type: core::ops::$op<b::Type> + ConstOps {
64                    core::ops::$op::$func(a, b)
65                }
66            }
67
68            term! {
69                /// Term that represents the arithmetic operation on mathematical integers and whose evaluations always panics on overflow of the base type
70                pub fn $term(a, b) -> unsafe a::Type
71                where b: Term<Type = a::Type>, a::Type: num_traits::ops::checked::$cop + ConstOps {
72                    num_traits::ops::checked::$cop::$cfunc(&a, &b).expect("Overflow in arithmetic operation in term evaluation")
73                }
74            }
75
76            impl<A: Term, B: Term<Type = A::Type>> core::ops::$op<Value<B>> for Value<A>
77                where A::Type: num_traits::ops::checked::$cop + ConstOps {
78                type Output = Value<$term<A, B>>;
79
80                fn $func(self, b: Value<B>) -> Self::Output {
81                    $term(self, b)
82                }
83            }
84        )*
85    };
86}
87
88macro_rules! impl_op1 {
89    ($($op:ident::$func:ident)*) => {
90        $(
91            term! {
92                pub fn $op(a) -> unsafe <a::Type as core::ops::$op>::Output
93                   where a::Type: core::ops::$op + ConstOps {
94                    core::ops::$op::$func(a)
95                }
96            }
97
98            impl<A: Term> core::ops::$op for Value<A>
99                where A::Type: core::ops::$op + ConstOps {
100                type Output = Value<$op<A>>;
101
102                fn $func(self) -> Self::Output {
103                    $op(self)
104                }
105            }
106        )*
107    };
108}
109
110macro_rules! impl_op1_overflowing {
111    ($($xterm:ident $term:ident = $op:ident::$func:ident $cop:ident::$cfunc:ident)*) => {
112        $(
113            term! {
114                /// Term that represents the arithmetic operation on the base type and whose evalutations just call the base type operation
115                ///
116                /// For primitive integers, this may be the operation on mathematical integers or on the Z mod 2**b ring depending on whether overflow checks are on or not.
117                pub fn $xterm(a) -> unsafe <a::Type as core::ops::$op>::Output
118                where a::Type: core::ops::$op + ConstOps {
119                    core::ops::$op::$func(a)
120                }
121            }
122
123            term! {
124                /// Term that represents the arithmetic operation on mathematical integers and whose evaluations always panics on overflow of the base type
125                pub fn $term(a) -> unsafe a::Type
126                where a::Type: num_traits::ops::checked::$cop + ConstOps {
127                    num_traits::ops::checked::$cop::$cfunc(&a).expect("Overflow in arithmetic operation in term evaluation")
128                }
129            }
130
131            impl<A: Term> core::ops::$op for Value<A>
132                where A::Type: num_traits::ops::checked::$cop + ConstOps {
133                type Output = Value<$term<A>>;
134
135                fn $func(self) -> Self::Output {
136                    $term(self)
137                }
138            }
139        )*
140    };
141}
142
143impl_op2_overflowing! {
144    XAdd Add = Add::add CheckedAdd::checked_add
145    XSub Sub = Sub::sub CheckedSub::checked_sub
146    XMul Mul = Mul::mul CheckedMul::checked_mul
147    XDiv Div = Div::div CheckedDiv::checked_div
148    XRem Rem = Rem::rem CheckedRem::checked_rem
149}
150
151impl_op2! {
152    And = BitAnd::bitand
153    Or = BitOr::bitor
154    Xor = BitXor::bitxor
155}
156
157// TODO: shl     XShl Shl = Shl::shl CheckedShl::checked_shl
158// TODO: shr
159
160impl_op1! {
161    Not::not
162}
163
164impl_op1_overflowing! {
165    XNeg Neg = Neg::neg CheckedNeg::checked_neg
166}