acme_core/ops/kinds/binary/
arithmetic.rs1use super::{BinOp, BinaryAssignOp};
6use num::traits::{NumAssignOps, NumOps, Pow};
7
8macro_rules! impl_binary_op {
9 ($($operand:ident($($p:ident)::*.$op:ident)),*) => {
10 $(
11 impl_binary_op!(@loop $operand, $($p)::*.$op);
12 )*
13 };
14 (std $(($op:ident, $bound:ident, $operator:tt)),*) => {
15 $(
16 impl_binary_op!(@loop $op, core::ops::$bound, $operator);
17 )*
18 };
19 (@loop $operand:ident, $($p:ident)::*.$op:ident) => {
20 impl<A, B, C> BinOp<A, B> for $operand
21 where
22 A: $($p)::*<B, Output = C>,
23 {
24 type Output = C;
25
26 fn eval(&self, lhs: A, rhs: B) -> Self::Output {
27 $($p)::*::$op(lhs, rhs)
28 }
29 }
30 };
31 (@loop $(($op:ident, $($p:ident)::*, $operator:tt)),*) => {
32 $(
33 impl_binary_op!($op, $($p)::*, $operator);
34 )*
35
36 };
37 (@loop $operand:ident, $($p:ident)::*, $op:tt) => {
38 operator!($operand, Binary);
39
40 impl<A, B, C> BinOp<A, B> for $operand
41 where
42 A: $($p)::*<B, Output = C>,
43 {
44 type Output = C;
45
46 fn eval(&self, lhs: A, rhs: B) -> Self::Output {
47 lhs $op rhs
48 }
49 }
50 };
51}
52
53macro_rules! impl_binary_assign {
54 ($($operand:ident($($p:ident)::*.$op:ident)),*) => {
55 $(
56 impl_binary_assign!(@impl $operand($($p)::*.$op));
57 )*
58 };
59 (@impl $operand:ident($($p:ident)::*.$op:ident)) => {
60
61 impl<A, B> BinOp<A, B> for $operand
62 where
63 A: $($p)::*<B>,
64 {
65 type Output = A;
66
67 fn eval(&self, lhs: A, rhs: B) -> Self::Output {
68 let mut lhs = lhs;
69 $($p)::*::$op(&mut lhs, rhs);
70 lhs
71 }
72 }
73
74 impl<A, B> BinaryAssignOp<A, B> for $operand
75 where
76 A: $($p)::*<B>,
77 {
78 fn eval(&self, mut lhs: A, rhs: B) {
79 $($p)::*::$op(&mut lhs, rhs);
80 }
81 }
82 };
83}
84
85impl_binary_op!(
86 Addition(core::ops::Add.add),
87 Division(core::ops::Div.div),
88 Multiplication(core::ops::Mul.mul),
89 Remainder(core::ops::Rem.rem),
90 Subtraction(core::ops::Sub.sub),
91 Power(num::traits::Pow.pow)
92);
93
94impl_binary_assign!(
95 AddAssign(core::ops::AddAssign.add_assign),
96 DivAssign(core::ops::DivAssign.div_assign),
97 MulAssign(core::ops::MulAssign.mul_assign),
98 RemAssign(core::ops::RemAssign.rem_assign),
99 SubAssign(core::ops::SubAssign.sub_assign)
100);
101
102operations!(Arithmetic<Binary> {
111 Add(Addition): add,
112 Div(Division): div,
113 Mul(Multiplication): mul,
114 Pow(Power): pow,
115 Rem(Remainder): rem,
116 Sub(Subtraction): sub
117});
118
119operations!(ArithmeticAssign<Binary> {
120 AddAssign(AddAssign): add_assign,
121 DivAssign(DivAssign): div_assign,
122 MulAssign(MulAssign): mul_assign,
123 RemAssign(RemAssign): rem_assign,
124 SubAssign(SubAssign): sub_assign
125});
126
127impl Arithmetic {
128 pub fn new(op: Arithmetic) -> Self {
129 op
130 }
131
132 pub fn is_commutative(&self) -> bool {
133 match self {
134 Arithmetic::Add(_) | Arithmetic::Mul(_) => true,
135 _ => false,
136 }
137 }
138
139 pub fn binop<A, B, C>(&self) -> Box<dyn BinOp<A, B, Output = C>>
140 where
141 A: NumOps<B, C> + Pow<B, Output = C>,
142 {
143 match *self {
144 Arithmetic::Add(op) => Box::new(op),
145 Arithmetic::Div(op) => Box::new(op),
146 Arithmetic::Mul(op) => Box::new(op),
147 Arithmetic::Pow(op) => Box::new(op),
148 Arithmetic::Rem(op) => Box::new(op),
149 Arithmetic::Sub(op) => Box::new(op),
150 }
151 }
152}
153
154impl ArithmeticAssign {
155 pub fn new(op: ArithmeticAssign) -> Self {
156 op
157 }
158
159 pub fn assign_op<A, B>(&self) -> Box<dyn BinaryAssignOp<A, B>>
160 where
161 A: NumAssignOps<B>,
162 {
163 match *self {
164 ArithmeticAssign::AddAssign(op) => Box::new(op),
165 ArithmeticAssign::DivAssign(op) => Box::new(op),
166 ArithmeticAssign::MulAssign(op) => Box::new(op),
167 ArithmeticAssign::RemAssign(op) => Box::new(op),
168 ArithmeticAssign::SubAssign(op) => Box::new(op),
169 }
170 }
171
172 pub fn bin_op<A, B>(&self) -> Box<dyn BinOp<A, B, Output = A>>
173 where
174 A: NumAssignOps<B>,
175 {
176 match *self {
177 ArithmeticAssign::AddAssign(op) => Box::new(op),
178 ArithmeticAssign::DivAssign(op) => Box::new(op),
179 ArithmeticAssign::MulAssign(op) => Box::new(op),
180 ArithmeticAssign::RemAssign(op) => Box::new(op),
181 ArithmeticAssign::SubAssign(op) => Box::new(op),
182 }
183 }
184}
185
186impl Default for Arithmetic {
187 fn default() -> Self {
188 Arithmetic::add()
189 }
190}
191
192impl Default for ArithmeticAssign {
193 fn default() -> Self {
194 ArithmeticAssign::add_assign()
195 }
196}
197
198impl<A, B> BinOp<A, B> for Arithmetic
199where
200 A: NumOps<B> + Pow<B, Output = A>,
201{
202 type Output = A;
203
204 fn eval(&self, lhs: A, rhs: B) -> Self::Output {
205 self.binop().eval(lhs, rhs)
206 }
207}
208
209impl<A, B> BinOp<A, B> for ArithmeticAssign
210where
211 A: NumAssignOps<B>,
212{
213 type Output = A;
214
215 fn eval(&self, lhs: A, rhs: B) -> Self::Output {
216 self.bin_op().eval(lhs, rhs)
217 }
218}
219
220impl<A, B> BinaryAssignOp<A, B> for ArithmeticAssign
221where
222 A: NumAssignOps<B>,
223{
224 fn eval(&self, lhs: A, rhs: B) {
225 self.assign_op().eval(lhs, rhs)
226 }
227}