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}