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}