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