stdlib_rs/
money.rs

1use std::fmt;
2use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
3
4#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
5pub struct Money(i64);
6
7#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
8pub enum Currency {
9    USD(Money),
10    JPY(Money),
11    RMB(Money),
12}
13
14impl fmt::Display for Currency {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        match self {
17            Currency::USD(amount) => write!(f, "{} cents", amount.0),
18            Currency::JPY(amount) => write!(f, "{} yen", amount.0),
19            Currency::RMB(amount) => write!(f, "{} rmb", amount.0),
20        }
21    }
22}
23
24impl Add for Currency {
25    type Output = Self;
26
27    fn add(self, other: Currency) -> Currency {
28        match (self, other) {
29            (Currency::USD(a), Currency::USD(b)) => Currency::USD(a + b),
30            (Currency::JPY(a), Currency::JPY(b)) => Currency::JPY(a + b),
31            (Currency::RMB(a), Currency::RMB(b)) => Currency::RMB(a + b),
32            (_, _) => panic!(),
33        }
34    }
35}
36
37impl Sub for Currency {
38    type Output = Self;
39
40    fn sub(self, other: Currency) -> Currency {
41        match (self, other) {
42            (Currency::USD(a), Currency::USD(b)) => Currency::USD(a - b),
43            (Currency::JPY(a), Currency::JPY(b)) => Currency::JPY(a - b),
44            (Currency::RMB(a), Currency::RMB(b)) => Currency::RMB(a - b),
45            (_, _) => panic!(),
46        }
47    }
48}
49
50impl Mul for Currency {
51    type Output = Self;
52
53    fn mul(self, other: Currency) -> Currency {
54        match (self, other) {
55            (Currency::USD(a), Currency::USD(b)) => Currency::USD(a * b),
56            (Currency::JPY(a), Currency::JPY(b)) => Currency::JPY(a * b),
57            (Currency::RMB(a), Currency::RMB(b)) => Currency::RMB(a * b),
58            (_, _) => panic!(),
59        }
60    }
61}
62
63impl Div for Currency {
64    type Output = Self;
65
66    fn div(self, other: Currency) -> Currency {
67        match (self, other) {
68            (Currency::USD(a), Currency::USD(b)) => Currency::USD(a / b),
69            (Currency::JPY(a), Currency::JPY(b)) => Currency::JPY(a / b),
70            (Currency::RMB(a), Currency::RMB(b)) => Currency::RMB(a / b),
71            (_, _) => panic!(),
72        }
73    }
74}
75
76impl Money {
77    pub fn new(amount: i64) -> Self {
78        Money(amount)
79    }
80}
81
82impl Add for Money {
83    type Output = Self;
84
85    fn add(self, other: Self) -> Self {
86        Self::new(self.0 + other.0)
87    }
88}
89
90impl Sub for Money {
91    type Output = Self;
92
93    fn sub(self, other: Self) -> Self {
94        Self::new(self.0 - other.0)
95    }
96}
97
98impl Mul for Money {
99    type Output = Self;
100
101    fn mul(self, other: Self) -> Self {
102        Self::new(self.0 * other.0)
103    }
104}
105
106impl Div for Money {
107    type Output = Self;
108
109    fn div(self, other: Self) -> Self {
110        Self::new(self.0 / other.0)
111    }
112}
113
114impl AddAssign for Money {
115    fn add_assign(&mut self, other: Self) {
116        self.0 += other.0
117    }
118}
119
120impl SubAssign for Money {
121    fn sub_assign(&mut self, other: Self) {
122        self.0 -= other.0
123    }
124}
125
126impl MulAssign for Money {
127    fn mul_assign(&mut self, other: Self) {
128        self.0 *= other.0
129    }
130}
131
132impl DivAssign for Money {
133    fn div_assign(&mut self, other: Self) {
134        self.0 /= other.0
135    }
136}
137
138impl From<i8> for Money {
139    fn from(amount: i8) -> Self {
140        Self(amount.into())
141    }
142}
143
144impl From<i16> for Money {
145    fn from(amount: i16) -> Self {
146        Self(amount.into())
147    }
148}
149
150impl From<i32> for Money {
151    fn from(amount: i32) -> Self {
152        Self(amount.into())
153    }
154}
155
156impl From<i64> for Money {
157    fn from(amount: i64) -> Self {
158        Self(amount)
159    }
160}
161
162impl From<u8> for Money {
163    fn from(amount: u8) -> Self {
164        Self(amount.into())
165    }
166}
167
168impl From<u16> for Money {
169    fn from(amount: u16) -> Self {
170        Self(amount.into())
171    }
172}
173
174impl From<u32> for Money {
175    fn from(amount: u32) -> Self {
176        Self(amount.into())
177    }
178}
179
180impl From<u64> for Money {
181    fn from(amount: u64) -> Self {
182        Self(amount as i64)
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    #[test]
191    fn from_u64() {
192        let num: u64 = 30;
193        let res = Money::from(num);
194        assert_eq!(res, Money::new(30));
195    }
196
197    #[test]
198    #[should_panic]
199    fn from_u64_max() {
200        let num: u64 = u64::MAX;
201        let res = Money::from(num);
202        assert_eq!(res, Money::new(30));
203    }
204
205    #[test]
206    fn add_money() {
207        let left = Money::new(10);
208        let right = Money::new(10);
209        let new = left + right;
210        assert_eq!(new, Money::new(20));
211    }
212
213    #[test]
214    fn add_currencies() {
215        let left = Currency::JPY(Money::new(10));
216        let right = Currency::JPY(Money::new(10));
217        let new = left + right;
218        assert_eq!(new, Currency::JPY(Money::new(20)));
219    }
220}