bigdecimal/
impl_ops.rs

1//! Implement math operations: Add,Sub, etc
2
3use crate::*;
4
5
6macro_rules! impl_add_for_primitive {
7    ($t:ty) => {
8        impl_add_for_primitive!(IMPL:ADD $t);
9        impl_add_for_primitive!(IMPL:ADD-ASSIGN $t);
10        impl_add_for_primitive!(IMPL:ADD &$t);
11        impl_add_for_primitive!(IMPL:ADD-ASSIGN &$t);
12    };
13    (IMPL:ADD $t:ty) => {
14        impl Add<$t> for BigDecimal {
15            type Output = BigDecimal;
16
17            fn add(mut self, rhs: $t) -> BigDecimal {
18                self += rhs;
19                self
20            }
21        }
22
23        impl Add<$t> for &BigDecimal {
24            type Output = BigDecimal;
25
26            fn add(self, rhs: $t) -> BigDecimal {
27                self.to_ref() + rhs
28            }
29        }
30
31        impl Add<$t> for BigDecimalRef<'_> {
32            type Output = BigDecimal;
33
34            fn add(self, rhs: $t) -> BigDecimal {
35                BigDecimal::from(rhs) + self
36            }
37        }
38
39        impl Add<BigDecimal> for $t {
40            type Output = BigDecimal;
41
42            fn add(self, rhs: BigDecimal) -> BigDecimal {
43                rhs + self
44            }
45        }
46
47        impl Add<&BigDecimal> for $t {
48            type Output = BigDecimal;
49
50            fn add(self, rhs: &BigDecimal) -> BigDecimal {
51                rhs + self
52            }
53        }
54    };
55    (IMPL:ADD-ASSIGN &$t:ty) => {
56        // special case for the ref types
57        impl AddAssign<&$t> for BigDecimal {
58            fn add_assign(&mut self, rhs: &$t) {
59                *self += *rhs;
60            }
61        }
62    };
63    (IMPL:ADD-ASSIGN $t:ty) => {
64        impl AddAssign<$t> for BigDecimal {
65            fn add_assign(&mut self, rhs: $t) {
66                if rhs == 0 {
67                    // no-op
68                } else if self.scale == 0 {
69                    self.int_val += rhs;
70                } else {
71                    *self += BigDecimal::from(rhs);
72                }
73            }
74        }
75    };
76}
77
78impl_add_for_primitive!(u8);
79impl_add_for_primitive!(u16);
80impl_add_for_primitive!(u32);
81impl_add_for_primitive!(u64);
82impl_add_for_primitive!(u128);
83impl_add_for_primitive!(i8);
84impl_add_for_primitive!(i16);
85impl_add_for_primitive!(i32);
86impl_add_for_primitive!(i64);
87impl_add_for_primitive!(i128);
88
89
90macro_rules! impl_sub_for_primitive {
91    ($t:ty) => {
92        impl_sub_for_primitive!(IMPL:SUB $t);
93        impl_sub_for_primitive!(IMPL:SUB-ASSIGN $t);
94        impl_sub_for_primitive!(IMPL:SUB &$t);
95        impl_sub_for_primitive!(IMPL:SUB-ASSIGN &$t);
96    };
97    (IMPL:SUB $t:ty) => {
98        impl Sub<$t> for BigDecimal {
99            type Output = BigDecimal;
100
101            fn sub(mut self, rhs: $t) -> BigDecimal {
102                self -= rhs;
103                self
104            }
105        }
106
107        impl Sub<$t> for &BigDecimal {
108            type Output = BigDecimal;
109
110            fn sub(self, rhs: $t) -> BigDecimal {
111                let res = BigDecimal::from(rhs).neg();
112                res + self
113            }
114        }
115
116        impl Sub<BigDecimal> for $t {
117            type Output = BigDecimal;
118
119            fn sub(self, rhs: BigDecimal) -> BigDecimal {
120                rhs.neg() + self
121            }
122        }
123
124        impl Sub<&BigDecimal> for $t {
125            type Output = BigDecimal;
126
127            fn sub(self, rhs: &BigDecimal) -> BigDecimal {
128                rhs.neg() + self
129            }
130        }
131    };
132    (IMPL:SUB-ASSIGN &$t:ty) => {
133        impl SubAssign<&$t> for BigDecimal {
134            fn sub_assign(&mut self, rhs: &$t) {
135                *self -= *rhs;
136            }
137        }
138    };
139    (IMPL:SUB-ASSIGN $t:ty) => {
140        impl SubAssign<$t> for BigDecimal {
141            fn sub_assign(&mut self, rhs: $t) {
142                if self.scale == 0 {
143                    self.int_val -= rhs;
144                } else {
145                    *self -= BigDecimal::from(rhs);
146                }
147            }
148        }
149    };
150}
151
152
153impl_sub_for_primitive!(u8);
154impl_sub_for_primitive!(u16);
155impl_sub_for_primitive!(u32);
156impl_sub_for_primitive!(u64);
157impl_sub_for_primitive!(u128);
158impl_sub_for_primitive!(i8);
159impl_sub_for_primitive!(i16);
160impl_sub_for_primitive!(i32);
161impl_sub_for_primitive!(i64);
162impl_sub_for_primitive!(i128);
163
164
165macro_rules! impl_mul_for_primitive {
166    ($t:ty) => {
167        impl_mul_for_primitive!(IMPL:MUL $t);
168        impl_mul_for_primitive!(IMPL:MUL-ASSIGN $t);
169        impl_mul_for_primitive!(IMPL:MUL &$t);
170        impl_mul_for_primitive!(IMPL:MUL-ASSIGN &$t);
171    };
172    (IMPL:MUL $t:ty) => {
173        impl Mul<$t> for BigDecimal {
174            type Output = BigDecimal;
175
176            fn mul(mut self, rhs: $t) -> BigDecimal {
177                self *= rhs;
178                self
179            }
180        }
181
182        impl Mul<$t> for &BigDecimal {
183            type Output = BigDecimal;
184
185            fn mul(self, rhs: $t) -> BigDecimal {
186                let res = BigDecimal::from(rhs);
187                res * self
188            }
189        }
190
191        impl Mul<BigDecimal> for $t {
192            type Output = BigDecimal;
193
194            fn mul(self, rhs: BigDecimal) -> BigDecimal {
195                rhs * self
196            }
197        }
198
199        impl Mul<&BigDecimal> for $t {
200            type Output = BigDecimal;
201
202            fn mul(self, rhs: &BigDecimal) -> BigDecimal {
203                rhs * self
204            }
205        }
206    };
207    (IMPL:MUL-ASSIGN $t:ty) => {
208        impl MulAssign<$t> for BigDecimal {
209            fn mul_assign(&mut self, rhs: $t) {
210                if rhs.is_zero() {
211                    *self = BigDecimal::zero()
212                } else if rhs.is_one() {
213                    // no-op
214                } else {
215                    *self *= BigDecimal::from(rhs);
216                }
217            }
218        }
219    };
220}
221
222
223impl_mul_for_primitive!(u8);
224impl_mul_for_primitive!(u16);
225impl_mul_for_primitive!(u32);
226impl_mul_for_primitive!(u64);
227impl_mul_for_primitive!(u128);
228impl_mul_for_primitive!(i8);
229impl_mul_for_primitive!(i16);
230impl_mul_for_primitive!(i32);
231impl_mul_for_primitive!(i64);
232impl_mul_for_primitive!(i128);
233
234macro_rules! impl_div_for_primitive {
235    (f32) => {
236        impl_div_for_primitive!(IMPL:DIV:FLOAT f32);
237        impl_div_for_primitive!(IMPL:DIV:REF &f32);
238    };
239    (f64) => {
240        impl_div_for_primitive!(IMPL:DIV:FLOAT f64);
241        impl_div_for_primitive!(IMPL:DIV:REF &f64);
242    };
243    ($t:ty) => {
244        impl_div_for_primitive!(IMPL:DIV $t);
245        impl_div_for_primitive!(IMPL:DIV:REF &$t);
246        impl_div_for_primitive!(IMPL:DIV-ASSIGN $t);
247    };
248    (IMPL:DIV $t:ty) => {
249        impl Div<$t> for BigDecimal {
250            type Output = BigDecimal;
251
252            fn div(self, denom: $t) -> BigDecimal {
253                if denom.is_one() {
254                    self
255                } else if denom.checked_neg() == Some(1) {
256                    self.neg()
257                } else if denom.clone() == 2 {
258                    self.half()
259                } else if denom.checked_neg() == Some(2) {
260                    self.half().neg()
261                } else {
262                    self / BigDecimal::from(denom)
263                }
264            }
265        }
266
267        impl Div<$t> for &BigDecimal {
268            type Output = BigDecimal;
269
270            fn div(self, denom: $t) -> BigDecimal {
271                self.clone() / denom
272            }
273        }
274
275        impl Div<BigDecimal> for $t {
276            type Output = BigDecimal;
277
278            fn div(self, denom: BigDecimal) -> BigDecimal {
279                if self.is_one() {
280                    denom.inverse()
281                } else {
282                    BigDecimal::from(self) / denom
283                }
284            }
285        }
286
287        impl Div<&BigDecimal> for $t {
288            type Output = BigDecimal;
289
290            fn div(self, denom: &BigDecimal) -> BigDecimal {
291                self / denom.clone()
292            }
293        }
294    };
295    (IMPL:DIV-ASSIGN $t:ty) => {
296        impl DivAssign<$t> for BigDecimal {
297            fn div_assign(&mut self, rhs: $t) {
298                if rhs.is_zero() {
299                    *self = BigDecimal::zero()
300                } else if rhs.is_one() {
301                    // no-op
302                } else {
303                    *self = self.clone() / BigDecimal::from(rhs);
304                }
305            }
306        }
307    };
308    (IMPL:DIV:REF $t:ty) => {
309        impl Div<$t> for BigDecimal {
310            type Output = BigDecimal;
311
312            fn div(self, denom: $t) -> BigDecimal {
313                self / *denom
314            }
315        }
316
317        impl Div<BigDecimal> for $t {
318            type Output = BigDecimal;
319
320            fn div(self, denom: BigDecimal) -> Self::Output {
321                *self / denom
322            }
323        }
324
325        impl Div<&BigDecimal> for $t {
326            type Output = BigDecimal;
327
328            fn div(self, denom: &BigDecimal) -> Self::Output {
329                *self / denom
330            }
331        }
332
333        impl DivAssign<$t> for BigDecimal {
334            fn div_assign(&mut self, denom: $t) {
335                self.div_assign(*denom)
336            }
337        }
338    };
339    (IMPL:DIV:FLOAT $t:ty) => {
340        impl Div<$t> for BigDecimal {
341            type Output = BigDecimal;
342
343            #[allow(clippy::float_cmp)]
344            fn div(self, denom: $t) -> BigDecimal {
345                if !denom.is_normal() {
346                    BigDecimal::zero()
347                } else if denom == (1.0 as $t) {
348                    self
349                } else if denom == (-1.0 as $t) {
350                    self.neg()
351                } else if denom == (2.0 as $t) {
352                    self.half()
353                } else if denom == (-2.0 as $t) {
354                    self.half().neg()
355                } else {
356                    self / BigDecimal::try_from(denom).unwrap()
357                }
358            }
359        }
360
361        impl Div<$t> for &BigDecimal {
362            type Output = BigDecimal;
363
364            fn div(self, denom: $t) -> BigDecimal {
365                self.clone() / denom
366            }
367        }
368
369        impl Div<BigDecimal> for $t {
370            type Output = BigDecimal;
371
372            fn div(self, denom: BigDecimal) -> Self::Output {
373                if !self.is_normal() {
374                    BigDecimal::zero()
375                } else if self.is_one() {
376                    denom.inverse()
377                } else {
378                    BigDecimal::try_from(self).unwrap() / denom
379                }
380            }
381        }
382
383        impl Div<&BigDecimal> for $t {
384            type Output = BigDecimal;
385
386            fn div(self, denom: &BigDecimal) -> Self::Output {
387                if !self.is_normal() {
388                    BigDecimal::zero()
389                } else if self.is_one() {
390                    denom.inverse()
391                } else {
392                    BigDecimal::try_from(self).unwrap() / denom
393                }
394            }
395        }
396
397        impl DivAssign<$t> for BigDecimal {
398            fn div_assign(&mut self, denom: $t) {
399                if !denom.is_normal() {
400                    *self = BigDecimal::zero()
401                } else {
402                    *self = self.clone() / BigDecimal::try_from(denom).unwrap()
403                };
404            }
405        }
406    };
407}
408
409
410impl_div_for_primitive!(u8);
411impl_div_for_primitive!(u16);
412impl_div_for_primitive!(u32);
413impl_div_for_primitive!(u64);
414impl_div_for_primitive!(u128);
415impl_div_for_primitive!(i8);
416impl_div_for_primitive!(i16);
417impl_div_for_primitive!(i32);
418impl_div_for_primitive!(i64);
419impl_div_for_primitive!(i128);
420
421impl_div_for_primitive!(f32);
422impl_div_for_primitive!(f64);
423
424
425impl Neg for BigDecimal {
426    type Output = BigDecimal;
427
428    #[inline]
429    fn neg(mut self) -> BigDecimal {
430        self.int_val = -self.int_val;
431        self
432    }
433}
434
435impl Neg for &BigDecimal {
436    type Output = BigDecimal;
437
438    #[inline]
439    fn neg(self) -> BigDecimal {
440        -self.clone()
441    }
442}
443
444impl Neg for BigDecimalRef<'_> {
445    type Output = Self;
446
447    fn neg(self) -> Self::Output {
448        Self {
449            sign: self.sign.neg(),
450            digits: self.digits,
451            scale: self.scale,
452        }
453    }
454}