Skip to main content

claude/
math.rs

1//! Implementations of standard operators:  `Add`, `Sub`, `Mul`, `Div`
2
3use crate::Currency;
4use std::ops::{Add, Div, Mul, Sub};
5
6/// Overloads the '+' operator for Currency objects.
7///
8/// # Panics
9/// Panics if the two addends are different types of currency, as denoted by the Currency's symbol.
10impl Add for Currency {
11    type Output = Currency;
12
13    #[inline]
14    fn add(self, rhs: Currency) -> Currency {
15        if self.symbol == rhs.symbol || self.symbol.is_none() {
16            Currency {
17                symbol: rhs.symbol,
18                value: self.value + rhs.value,
19            }
20        } else {
21            panic!(
22                "Cannot add two different types of currency!\n{:?} vs {:?}",
23                self.symbol, rhs.symbol
24            );
25        }
26    }
27}
28
29/// Overloads the '-' operator for Currency objects.
30///
31/// # Panics
32/// Panics if the minuend and subtrahend are two different types of currency, as denoted by the
33/// Currency's symbol.
34impl Sub for Currency {
35    type Output = Currency;
36
37    #[inline]
38    fn sub(self, rhs: Currency) -> Currency {
39        if self.symbol == rhs.symbol || self.symbol.is_none() {
40            Currency {
41                symbol: rhs.symbol,
42                value: self.value - rhs.value,
43            }
44        } else {
45            panic!("Cannot subtract two different types of currency!");
46        }
47    }
48}
49
50/// Overloads the '*' operator for Currency objects.
51///
52/// Allows a Currency to be multiplied by an i64.
53impl Mul<i64> for Currency {
54    type Output = Currency;
55
56    #[inline]
57    fn mul(self, rhs: i64) -> Currency {
58        Currency {
59            symbol: self.symbol,
60            value: self.value * rhs,
61        }
62    }
63}
64
65/// Overloads the '*' operator for i64.
66///
67/// Allows an i64 to be multiplied by a Currency.
68/// Completes the commutative property for i64 multiplied by Currency.
69impl Mul<Currency> for i64 {
70    type Output = Currency;
71
72    #[inline]
73    fn mul(self, rhs: Currency) -> Currency {
74        Currency {
75            symbol: rhs.symbol,
76            value: rhs.value * self,
77        }
78    }
79}
80
81/// Multiplies with float, probably not a good idea, help appreciated.
82impl Mul<f64> for Currency {
83    type Output = Currency;
84
85    #[inline]
86    fn mul(self, rhs: f64) -> Currency {
87        Currency {
88            symbol: self.symbol,
89            value: (self.value as f64 * rhs).round() as i64,
90        }
91    }
92}
93
94impl Mul<Currency> for f64 {
95    type Output = Currency;
96
97    #[inline]
98    fn mul(self, rhs: Currency) -> Currency {
99        rhs * self
100    }
101}
102
103/// Overloads the '/' operator for Currency objects.
104///
105/// Allows a Currency to be divided by an i64.
106impl Div<i64> for Currency {
107    type Output = Currency;
108
109    #[inline]
110    fn div(self, rhs: i64) -> Currency {
111        Currency {
112            symbol: self.symbol,
113            value: self.value / rhs,
114        }
115    }
116}
117
118#[cfg(test)]
119mod test_arithmetic {
120    use crate::Currency;
121
122    fn dollars(value: i64) -> Currency {
123        Currency {
124            symbol: Some('$'),
125            value,
126        }
127    }
128
129    fn bare(value: i64) -> Currency {
130        Currency::from_value(value)
131    }
132
133    #[test]
134    fn sub_same_symbol() {
135        assert_eq!(dollars(100) - dollars(50), dollars(50));
136    }
137
138    #[test]
139    fn add_same_symbol() {
140        assert_eq!(dollars(100) + dollars(50), dollars(150));
141    }
142
143    #[test]
144    fn bare_lhs_adopts_rhs_symbol_on_add() {
145        assert_eq!(bare(100) + dollars(50), dollars(150));
146    }
147
148    #[test]
149    fn bare_lhs_adopts_rhs_symbol_on_sub() {
150        assert_eq!(bare(100) - dollars(50), dollars(50));
151    }
152
153    #[test]
154    #[should_panic]
155    fn symbolled_lhs_plus_bare_rhs_panics() {
156        let _ = dollars(100) + bare(50);
157    }
158
159    #[test]
160    #[should_panic]
161    fn symbolled_lhs_minus_bare_rhs_panics() {
162        let _ = dollars(100) - bare(50);
163    }
164
165    #[test]
166    #[should_panic]
167    fn mixed_symbols_add_panics() {
168        let euro = Currency {
169            symbol: Some('€'),
170            value: 100,
171        };
172        let _ = dollars(100) + euro;
173    }
174
175    #[test]
176    #[should_panic]
177    fn mixed_symbols_sub_panics() {
178        let euro = Currency {
179            symbol: Some('€'),
180            value: 100,
181        };
182        let _ = dollars(100) - euro;
183    }
184}