null_kane/calculation/
sub.rs

1use crate::{Currency, CurrencyLocale};
2use std::ops::{Sub, SubAssign};
3
4impl<L, T> Sub<T> for Currency<L>
5where
6    T: Into<Currency<L>>,
7    L: CurrencyLocale,
8{
9    type Output = Self;
10
11    fn sub(self, rhs: T) -> Self::Output {
12        let rhs = rhs.into();
13
14        match (self.negative, rhs.negative) {
15            (false, true) | (true, false) => {
16                Self::new(self.negative, self.amount + rhs.amount, self.locale)
17            }
18            (false, false) | (true, true) => {
19                let negative = self.amount.checked_sub(rhs.amount).is_none();
20                let amount = if negative {
21                    rhs.amount - self.amount
22                } else {
23                    self.amount - rhs.amount
24                };
25                Self::new(self.negative ^ negative, amount, self.locale)
26            }
27        }
28    }
29}
30
31impl<L, T> SubAssign<T> for Currency<L>
32where
33    T: Into<Currency<L>>,
34    L: CurrencyLocale,
35{
36    fn sub_assign(&mut self, rhs: T) {
37        let rhs = rhs.into();
38
39        match (self.negative, rhs.negative) {
40            (false, true) | (true, false) => self.amount += rhs.amount,
41            (false, false) | (true, true) => {
42                let negative = self.amount.checked_sub(rhs.amount).is_none();
43                self.amount = if negative {
44                    rhs.amount - self.amount
45                } else {
46                    self.amount - rhs.amount
47                };
48                self.negative ^= negative;
49            }
50        }
51    }
52}
53
54#[cfg(test)]
55mod test {
56    use super::*;
57
58    #[derive(Clone, Copy, Default, Debug, PartialEq)]
59    enum CurrencyL {
60        #[default]
61        De,
62    }
63
64    impl CurrencyLocale for CurrencyL {
65        fn separator(&self) -> char {
66            ','
67        }
68
69        fn thousand_separator(&self) -> char {
70            '.'
71        }
72
73        fn currency_symbol(&self) -> &'static str {
74            "€"
75        }
76    }
77
78    #[test]
79    fn sub_currency() {
80        let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
81        let curr2 = Currency::new(false, 24_000_99, CurrencyL::De);
82
83        let expected = curr1 - curr2;
84        assert_eq!(expected, Currency::new(true, 77, CurrencyL::De));
85    }
86
87    #[test]
88    fn sub_usize() {
89        let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
90
91        let expected = curr1 - 22usize;
92        assert_eq!(expected, Currency::new(false, 24_000_00, CurrencyL::De));
93    }
94
95    #[test]
96    fn sub_f32() {
97        let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
98
99        let expected = curr1 - 24_000.98_f32;
100        assert_eq!(expected, Currency::new(true, 76, CurrencyL::De));
101    }
102
103    #[test]
104    fn sub_negative_f32() {
105        let curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
106
107        let expected = curr1 - -24_000.98_f32;
108        assert_eq!(expected, Currency::new(false, 48_001_20, CurrencyL::De));
109    }
110
111    #[test]
112    fn negative_sub_f32() {
113        let curr1 = Currency::new(true, 24_000_22, CurrencyL::De);
114
115        let expected = curr1 - 24_000.98_f32;
116        assert_eq!(expected, Currency::new(true, 48_001_20, CurrencyL::De));
117    }
118
119    #[test]
120    fn negative_sub_negative_f32() {
121        let curr1 = Currency::new(true, 24_000_22, CurrencyL::De);
122
123        let expected = curr1 - -24_000.98_f32;
124        assert_eq!(expected, Currency::new(false, 76, CurrencyL::De));
125    }
126
127    #[test]
128    fn subassign_usize() {
129        let mut curr = Currency::new(false, 24_000_22, CurrencyL::De);
130
131        curr -= 1usize;
132
133        assert_eq!(curr, Currency::new(false, 24_000_21, CurrencyL::De));
134    }
135
136    #[test]
137    fn subassign_currency() {
138        let mut curr1 = Currency::new(false, 24_000_22, CurrencyL::De);
139        let curr2 = Currency::new(false, 24_000_99, CurrencyL::De);
140
141        curr1 -= curr2;
142        assert_eq!(curr1, Currency::new(true, 77, CurrencyL::De));
143    }
144
145    #[test]
146    fn subassign_negative_currency() {
147        let mut curr1 = Currency::new(false, 24_00022, CurrencyL::De);
148        let curr2 = Currency::new(true, 24_000_99, CurrencyL::De);
149
150        curr1 -= curr2;
151        assert_eq!(curr1, Currency::new(false, 48_001_21, CurrencyL::De));
152    }
153
154    #[test]
155    fn negative_subassign_negative_currency() {
156        let mut curr1 = Currency::new(true, 24_000_22, CurrencyL::De);
157        let curr2 = Currency::new(true, 24_000_99, CurrencyL::De);
158
159        curr1 -= curr2;
160        assert_eq!(curr1, Currency::new(false, 77, CurrencyL::De));
161    }
162}