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            #[cfg(rustc_1_70)]  // Option::is_some_and
253            #[allow(clippy::incompatible_msrv)]
254            fn div(self, denom: $t) -> BigDecimal {
255                if denom.is_one() {
256                    self
257                } else if denom.checked_neg().is_some_and(|n| n == 1) {
258                    self.neg()
259                } else if denom.clone() == 2 {
260                    self.half()
261                } else if denom.checked_neg().is_some_and(|n| n == 2) {
262                    self.half().neg()
263                } else {
264                    self / BigDecimal::from(denom)
265                }
266            }
267
268            #[cfg(not(rustc_1_70))]
269            fn div(self, denom: $t) -> BigDecimal {
270                if denom.is_one() {
271                    self
272                } else if denom.checked_neg().map(|n| n == 1).unwrap_or(false) {
273                    self.neg()
274                } else if denom.clone() == 2 {
275                    self.half()
276                } else if denom.checked_neg().map(|n| n == 2).unwrap_or(false) {
277                    self.half().neg()
278                } else {
279                    self / BigDecimal::from(denom)
280                }
281            }
282        }
283
284        impl Div<$t> for &BigDecimal {
285            type Output = BigDecimal;
286
287            fn div(self, denom: $t) -> BigDecimal {
288                self.clone() / denom
289            }
290        }
291
292        impl Div<BigDecimal> for $t {
293            type Output = BigDecimal;
294
295            fn div(self, denom: BigDecimal) -> BigDecimal {
296                if self.is_one() {
297                    denom.inverse()
298                } else {
299                    BigDecimal::from(self) / denom
300                }
301            }
302        }
303
304        impl Div<&BigDecimal> for $t {
305            type Output = BigDecimal;
306
307            fn div(self, denom: &BigDecimal) -> BigDecimal {
308                self / denom.clone()
309            }
310        }
311    };
312    (IMPL:DIV-ASSIGN $t:ty) => {
313        impl DivAssign<$t> for BigDecimal {
314            fn div_assign(&mut self, rhs: $t) {
315                if rhs.is_zero() {
316                    *self = BigDecimal::zero()
317                } else if rhs.is_one() {
318                    // no-op
319                } else {
320                    *self = self.clone() / BigDecimal::from(rhs);
321                }
322            }
323        }
324    };
325    (IMPL:DIV:REF $t:ty) => {
326        impl Div<$t> for BigDecimal {
327            type Output = BigDecimal;
328
329            fn div(self, denom: $t) -> BigDecimal {
330                self / *denom
331            }
332        }
333
334        impl Div<BigDecimal> for $t {
335            type Output = BigDecimal;
336
337            fn div(self, denom: BigDecimal) -> Self::Output {
338                *self / denom
339            }
340        }
341
342        impl Div<&BigDecimal> for $t {
343            type Output = BigDecimal;
344
345            fn div(self, denom: &BigDecimal) -> Self::Output {
346                *self / denom
347            }
348        }
349
350        impl DivAssign<$t> for BigDecimal {
351            fn div_assign(&mut self, denom: $t) {
352                self.div_assign(*denom)
353            }
354        }
355    };
356    (IMPL:DIV:FLOAT $t:ty) => {
357        impl Div<$t> for BigDecimal {
358            type Output = BigDecimal;
359
360            #[allow(clippy::float_cmp)]
361            fn div(self, denom: $t) -> BigDecimal {
362                if !denom.is_normal() {
363                    BigDecimal::zero()
364                } else if denom == (1.0 as $t) {
365                    self
366                } else if denom == (-1.0 as $t) {
367                    self.neg()
368                } else if denom == (2.0 as $t) {
369                    self.half()
370                } else if denom == (-2.0 as $t) {
371                    self.half().neg()
372                } else {
373                    self / BigDecimal::try_from(denom).unwrap()
374                }
375            }
376        }
377
378        impl Div<$t> for &BigDecimal {
379            type Output = BigDecimal;
380
381            fn div(self, denom: $t) -> BigDecimal {
382                self.clone() / denom
383            }
384        }
385
386        impl Div<BigDecimal> for $t {
387            type Output = BigDecimal;
388
389            fn div(self, denom: BigDecimal) -> Self::Output {
390                if !self.is_normal() {
391                    BigDecimal::zero()
392                } else if self.is_one() {
393                    denom.inverse()
394                } else {
395                    BigDecimal::try_from(self).unwrap() / denom
396                }
397            }
398        }
399
400        impl Div<&BigDecimal> for $t {
401            type Output = BigDecimal;
402
403            fn div(self, denom: &BigDecimal) -> Self::Output {
404                if !self.is_normal() {
405                    BigDecimal::zero()
406                } else if self.is_one() {
407                    denom.inverse()
408                } else {
409                    BigDecimal::try_from(self).unwrap() / denom
410                }
411            }
412        }
413
414        impl DivAssign<$t> for BigDecimal {
415            fn div_assign(&mut self, denom: $t) {
416                if !denom.is_normal() {
417                    *self = BigDecimal::zero()
418                } else {
419                    *self = self.clone() / BigDecimal::try_from(denom).unwrap()
420                };
421            }
422        }
423    };
424}
425
426
427impl_div_for_primitive!(u8);
428impl_div_for_primitive!(u16);
429impl_div_for_primitive!(u32);
430impl_div_for_primitive!(u64);
431impl_div_for_primitive!(u128);
432impl_div_for_primitive!(i8);
433impl_div_for_primitive!(i16);
434impl_div_for_primitive!(i32);
435impl_div_for_primitive!(i64);
436impl_div_for_primitive!(i128);
437
438impl_div_for_primitive!(f32);
439impl_div_for_primitive!(f64);
440
441
442impl Neg for BigDecimal {
443    type Output = BigDecimal;
444
445    #[inline]
446    fn neg(mut self) -> BigDecimal {
447        self.int_val = -self.int_val;
448        self
449    }
450}
451
452impl Neg for &BigDecimal {
453    type Output = BigDecimal;
454
455    #[inline]
456    fn neg(self) -> BigDecimal {
457        -self.clone()
458    }
459}
460
461impl Neg for BigDecimalRef<'_> {
462    type Output = Self;
463
464    fn neg(self) -> Self::Output {
465        Self {
466            sign: self.sign.neg(),
467            digits: self.digits,
468            scale: self.scale,
469        }
470    }
471}