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
use crate::{Currency, CurrencyLocale};
use std::ops::{Add, Sub, SubAssign};

impl<L, T> Sub<T> for Currency<L>
where
    T: Into<Currency<L>>,
    L: CurrencyLocale + Default,
{
    type Output = Self;

    fn sub(self, rhs: T) -> Self::Output {
        let rhs = rhs.into();

        match (self.negative, rhs.negative) {
            (true | false, true) => self.add(Self::new(false, rhs.full, rhs.part, rhs.locale)),
            (true, false) => {
                let new_part = self.part + rhs.part;
                let new_full = self.full + rhs.full + usize::from(new_part >= 100);
                Self::new(false, new_full, new_part % 100, self.locale)
            }
            (false, false) => {
                let decrease_full = self.part.checked_sub(rhs.part).is_none();
                let decrement = rhs.full + usize::from(decrease_full);
                let mut negative = false;
                let (new_full, new_part) = if decrement > self.full {
                    negative = true;
                    (rhs.full - self.full, rhs.part - self.part)
                } else {
                    (self.full - decrement, self.part - rhs.part)
                };
                Self::new(negative, new_full, new_part, self.locale)
            }
        }
    }
}

impl<L, T> SubAssign<T> for Currency<L>
where
    T: Into<Currency<L>>,
    L: CurrencyLocale + Default + Clone,
{
    fn sub_assign(&mut self, rhs: T) {
        let rhs = rhs.into();

        match (self.negative, rhs.negative) {
            (true | false, true) => {
                let new = rhs
                    .clone()
                    .add(Self::new(false, rhs.full, rhs.part, L::default()));
                self.negative = new.negative;
                self.full = new.full;
                self.part = new.part;
            }
            (true, false) => {
                let new_part = self.part + rhs.part;
                let new_full = self.full + rhs.full + usize::from(new_part >= 100);
                self.part = new_part % 100;
                self.full = new_full;
            }
            (false, false) => {
                let decrease_full = self.part.checked_sub(rhs.part).is_none();
                let decrement = rhs.full + usize::from(decrease_full);
                let mut negative = false;
                let (new_full, new_part) = if decrement > self.full {
                    negative = true;
                    (
                        rhs.full - self.full - usize::from(decrease_full),
                        rhs.part - self.part,
                    )
                } else {
                    (self.full - decrement, self.part - rhs.part)
                };

                let new = Self::new(negative, new_full, new_part, self.locale.clone());
                self.negative = new.negative;
                self.full = new.full;
                self.part = new.part;
            }
        }
    }
}