1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! addition routines
//!

use crate::*;


pub(crate) fn add_bigdecimals(
    mut a: BigDecimal,
    mut b: BigDecimal,
) -> BigDecimal {
    if b.is_zero() {
        if a.scale < b.scale {
            a.int_val *= ten_to_the((b.scale - a.scale) as u64);
            a.scale = b.scale;
        }
        return a;
    }

    if a.is_zero() {
        if b.scale < a.scale {
            b.int_val *= ten_to_the((a.scale - b.scale) as u64);
            b.scale = a.scale;
        }
        return b;
    }

    let (a, b) = match a.scale.cmp(&b.scale) {
        Ordering::Equal => (a, b),
        Ordering::Less => (a.take_and_scale(b.scale), b),
        Ordering::Greater => (b.take_and_scale(a.scale), a),
    };

    add_aligned_bigdecimals(a, b)
}

fn add_aligned_bigdecimals(
    mut a: BigDecimal,
    mut b: BigDecimal,
) -> BigDecimal {
    debug_assert_eq!(a.scale, b.scale);
    if a.int_val.bits() >= b.int_val.bits() {
        a.int_val += b.int_val;
        a
    } else {
        b.int_val += a.int_val;
        b
    }
}


pub(crate) fn add_bigdecimal_refs<'a, 'b, Lhs, Rhs>(
    lhs: Lhs,
    rhs: Rhs,
) -> BigDecimal
where
    Rhs: Into<BigDecimalRef<'a>>,
    Lhs: Into<BigDecimalRef<'b>>,
{
    let lhs = lhs.into();
    let rhs = rhs.into();
    if rhs.is_zero() {
        return lhs.to_owned();
    }
    if lhs.is_zero() {
        return rhs.to_owned();
    }
    if lhs.scale >= rhs.scale {
        lhs.to_owned() + rhs
    } else {
        rhs.to_owned() + lhs
    }
}


pub(crate) fn addassign_bigdecimals(
    lhs: &mut BigDecimal,
    rhs: BigDecimal,
) {
    if rhs.is_zero() {
        return;
    }
    if lhs.is_zero() {
        *lhs = rhs;
        return;
    }
    lhs.add_assign(rhs.to_ref());
}


pub(crate) fn addassign_bigdecimal_ref<'a, T: Into<BigDecimalRef<'a>>>(
    lhs: &mut BigDecimal,
    rhs: T,
) {
    // TODO: Replace to_owned() with efficient addition algorithm
    let rhs = rhs.into().to_owned();
    match lhs.scale.cmp(&rhs.scale) {
        Ordering::Less => {
            let scaled = lhs.with_scale(rhs.scale);
            lhs.int_val = scaled.int_val + &rhs.int_val;
            lhs.scale = rhs.scale;
        }
        Ordering::Greater => {
            let scaled = rhs.with_scale(lhs.scale);
            lhs.int_val += scaled.int_val;
        }
        Ordering::Equal => {
            lhs.int_val += &rhs.int_val;
        }
    }
}