rtm_core/models/
amount.rs1use rust_decimal::Decimal;
2
3const DECIMAL_PRECISION: u32 = 4;
4
5#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
7#[repr(transparent)]
8#[must_use]
9pub struct Amount {
10 value: Decimal,
11}
12
13impl Amount {
14 pub fn zero() -> Self {
15 Self::new(Decimal::from(0))
16 }
17
18 fn new(mut value: Decimal) -> Self {
19 value.rescale(DECIMAL_PRECISION);
20 Self { value }
21 }
22}
23
24impl std::fmt::Display for Amount {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "{}", self.value)
27 }
28}
29
30impl From<i32> for Amount {
31 fn from(value: i32) -> Self {
32 Self::new(value.into())
33 }
34}
35
36impl From<u32> for Amount {
37 fn from(value: u32) -> Self {
38 Self::new(value.into())
39 }
40}
41
42impl Default for Amount {
43 fn default() -> Self {
44 Self::zero()
45 }
46}
47
48#[derive(Debug, PartialEq, Eq, Hash)]
49pub struct InvalidNumericalStringError;
50
51impl TryFrom<&str> for Amount {
52 type Error = InvalidNumericalStringError;
53
54 fn try_from(value: &str) -> Result<Self, Self::Error> {
55 match Decimal::try_from(value) {
56 Ok(result) => Ok(Self::new(result)),
57 Err(_) => Err(InvalidNumericalStringError),
58 }
59 }
60}
61
62macro_rules! impl_binary_op {
63 ( $op: ty, $method: ident ) => {
64 impl $op for Amount {
65 type Output = Self;
66
67 fn $method(self, rhs: Self) -> Self {
68 Self::new(self.value.$method(rhs.value))
69 }
70 }
71 };
72}
73
74macro_rules! impl_unary_op {
75 ( $op: ty, $method: ident ) => {
76 impl $op for Amount {
77 fn $method(&mut self, rhs: Self) {
78 self.value.$method(rhs.value);
79 }
80 }
81 };
82}
83
84impl_binary_op!(std::ops::Add, add);
85impl_binary_op!(std::ops::Sub, sub);
86impl_binary_op!(std::ops::Mul, mul);
87impl_binary_op!(std::ops::Div, div);
88impl_unary_op!(std::ops::AddAssign, add_assign);
89impl_unary_op!(std::ops::SubAssign, sub_assign);
90impl_unary_op!(std::ops::MulAssign, mul_assign);
91impl_unary_op!(std::ops::DivAssign, div_assign);
92
93impl std::ops::Neg for Amount {
94 type Output = Self;
95
96 fn neg(self) -> Self {
97 Self::new(self.value.neg())
98 }
99}