acme_core/ops/kinds/binary/
arithmetic.rs

1/*
2    Appellation: arithmetic <mod>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use 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
102// impl_binary_op!(
103//     (BitAnd, BitAnd.
104//     (BitOr, BitOr, |),
105//     (BitXor, BitXor, &|),
106//     (Shl, Shl, <<),
107//     (Shr, Shr, >>)
108// );
109
110operations!(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}