rsdiff_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, lhs: &mut A, rhs: B) {
79                $($p)::*::$op(lhs, rhs);
80            }
81        }
82    };
83}
84
85operations!(Arithmetic<Binary> {
86    Add(Addition): add,
87    Div(Division): div,
88    Mul(Multiplication): mul,
89    Pow(Power): pow,
90    Rem(Remainder): rem,
91    Sub(Subtraction): sub
92});
93
94operations!(ArithmeticAssign<Binary> {
95    AddAssign(AddAssign): add_assign,
96    DivAssign(DivAssign): div_assign,
97    MulAssign(MulAssign): mul_assign,
98    RemAssign(RemAssign): rem_assign,
99    SubAssign(SubAssign): sub_assign
100});
101
102impl_binary_op!(
103    Addition(core::ops::Add.add),
104    Division(core::ops::Div.div),
105    Multiplication(core::ops::Mul.mul),
106    Remainder(core::ops::Rem.rem),
107    Subtraction(core::ops::Sub.sub),
108    Power(num::traits::Pow.pow)
109);
110
111impl_binary_assign!(
112    AddAssign(core::ops::AddAssign.add_assign),
113    DivAssign(core::ops::DivAssign.div_assign),
114    MulAssign(core::ops::MulAssign.mul_assign),
115    RemAssign(core::ops::RemAssign.rem_assign),
116    SubAssign(core::ops::SubAssign.sub_assign)
117);
118
119impl Arithmetic {
120    pub fn new(op: Arithmetic) -> Self {
121        op
122    }
123
124    pub fn is_commutative(&self) -> bool {
125        match self {
126            Arithmetic::Add(_) | Arithmetic::Mul(_) => true,
127            _ => false,
128        }
129    }
130
131    pub fn binop<A, B, C>(&self) -> Box<dyn BinOp<A, B, Output = C>>
132    where
133        A: NumOps<B, C> + Pow<B, Output = C>,
134    {
135        match *self {
136            Arithmetic::Add(op) => Box::new(op),
137            Arithmetic::Div(op) => Box::new(op),
138            Arithmetic::Mul(op) => Box::new(op),
139            Arithmetic::Pow(op) => Box::new(op),
140            Arithmetic::Rem(op) => Box::new(op),
141            Arithmetic::Sub(op) => Box::new(op),
142        }
143    }
144}
145
146impl ArithmeticAssign {
147    pub fn new(op: ArithmeticAssign) -> Self {
148        op
149    }
150
151    pub fn assign_op<A, B>(&self) -> Box<dyn BinaryAssignOp<A, B>>
152    where
153        A: NumAssignOps<B>,
154    {
155        match *self {
156            ArithmeticAssign::AddAssign(op) => Box::new(op),
157            ArithmeticAssign::DivAssign(op) => Box::new(op),
158            ArithmeticAssign::MulAssign(op) => Box::new(op),
159            ArithmeticAssign::RemAssign(op) => Box::new(op),
160            ArithmeticAssign::SubAssign(op) => Box::new(op),
161        }
162    }
163
164    pub fn bin_op<A, B>(&self) -> Box<dyn BinOp<A, B, Output = A>>
165    where
166        A: NumAssignOps<B>,
167    {
168        match *self {
169            ArithmeticAssign::AddAssign(op) => Box::new(op),
170            ArithmeticAssign::DivAssign(op) => Box::new(op),
171            ArithmeticAssign::MulAssign(op) => Box::new(op),
172            ArithmeticAssign::RemAssign(op) => Box::new(op),
173            ArithmeticAssign::SubAssign(op) => Box::new(op),
174        }
175    }
176}
177
178impl Default for Arithmetic {
179    fn default() -> Self {
180        Arithmetic::add()
181    }
182}
183
184impl Default for ArithmeticAssign {
185    fn default() -> Self {
186        ArithmeticAssign::add_assign()
187    }
188}
189
190impl<A, B> BinOp<A, B> for Arithmetic
191where
192    A: NumOps<B> + Pow<B, Output = A>,
193{
194    type Output = A;
195
196    fn eval(&self, lhs: A, rhs: B) -> Self::Output {
197        self.binop().eval(lhs, rhs)
198    }
199}
200
201impl<A, B> BinOp<A, B> for ArithmeticAssign
202where
203    A: NumAssignOps<B>,
204{
205    type Output = A;
206
207    fn eval(&self, lhs: A, rhs: B) -> Self::Output {
208        self.bin_op().eval(lhs, rhs)
209    }
210}
211
212impl<A, B> BinaryAssignOp<A, B> for ArithmeticAssign
213where
214    A: NumAssignOps<B>,
215{
216    fn eval(&self, lhs: &mut A, rhs: B) {
217        self.assign_op().eval(lhs, rhs)
218    }
219}