1use core::ops::{
7 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
8};
9
10use crate::Decimal;
11
12#[cold]
13#[inline(never)]
14fn panic_overflow(op: &str) -> ! {
15 panic!("decimal {op} overflow")
16}
17
18#[cold]
19#[inline(never)]
20fn panic_div_zero() -> ! {
21 panic!("decimal division overflow or division by zero")
22}
23
24macro_rules! impl_decimal_ops {
25 ($backing:ty) => {
26 impl<const D: u8> Add for Decimal<$backing, D> {
27 type Output = Self;
28
29 #[inline(always)]
30 fn add(self, rhs: Self) -> Self {
31 match self.checked_add(rhs) {
32 Some(v) => v,
33 None => panic_overflow("addition"),
34 }
35 }
36 }
37
38 impl<const D: u8> Sub for Decimal<$backing, D> {
39 type Output = Self;
40
41 #[inline(always)]
42 fn sub(self, rhs: Self) -> Self {
43 match self.checked_sub(rhs) {
44 Some(v) => v,
45 None => panic_overflow("subtraction"),
46 }
47 }
48 }
49
50 impl<const D: u8> Neg for Decimal<$backing, D> {
51 type Output = Self;
52
53 #[inline(always)]
54 fn neg(self) -> Self {
55 match self.checked_neg() {
56 Some(v) => v,
57 None => panic_overflow("negation"),
58 }
59 }
60 }
61
62 impl<const D: u8> AddAssign for Decimal<$backing, D> {
63 #[inline(always)]
64 fn add_assign(&mut self, rhs: Self) {
65 *self = *self + rhs;
66 }
67 }
68
69 impl<const D: u8> SubAssign for Decimal<$backing, D> {
70 #[inline(always)]
71 fn sub_assign(&mut self, rhs: Self) {
72 *self = *self - rhs;
73 }
74 }
75 };
76}
77
78impl_decimal_ops!(i32);
79impl_decimal_ops!(i64);
80impl_decimal_ops!(i128);
81
82macro_rules! impl_decimal_mul_div_ops {
83 ($backing:ty) => {
84 impl<const D: u8> Mul for Decimal<$backing, D> {
85 type Output = Self;
86
87 #[inline(always)]
88 fn mul(self, rhs: Self) -> Self {
89 match self.checked_mul(rhs) {
90 Some(v) => v,
91 None => panic_overflow("multiplication"),
92 }
93 }
94 }
95
96 impl<const D: u8> Div for Decimal<$backing, D> {
97 type Output = Self;
98
99 #[inline(always)]
100 fn div(self, rhs: Self) -> Self {
101 match self.checked_div(rhs) {
102 Some(v) => v,
103 None => panic_div_zero(),
104 }
105 }
106 }
107
108 impl<const D: u8> MulAssign for Decimal<$backing, D> {
109 #[inline(always)]
110 fn mul_assign(&mut self, rhs: Self) {
111 *self = *self * rhs;
112 }
113 }
114
115 impl<const D: u8> DivAssign for Decimal<$backing, D> {
116 #[inline(always)]
117 fn div_assign(&mut self, rhs: Self) {
118 *self = *self / rhs;
119 }
120 }
121
122 impl<const D: u8> Rem for Decimal<$backing, D> {
123 type Output = Self;
124
125 #[inline(always)]
131 fn rem(self, rhs: Self) -> Self {
132 if rhs.value == 0 {
133 panic_div_zero()
134 }
135 Self {
136 value: self.value % rhs.value,
137 }
138 }
139 }
140
141 impl<const D: u8> RemAssign for Decimal<$backing, D> {
142 #[inline(always)]
143 fn rem_assign(&mut self, rhs: Self) {
144 *self = *self % rhs;
145 }
146 }
147 };
148}
149
150impl_decimal_mul_div_ops!(i32);
151impl_decimal_mul_div_ops!(i64);
152impl_decimal_mul_div_ops!(i128);
153
154macro_rules! impl_decimal_iter_traits {
159 ($backing:ty) => {
160 impl<const D: u8> core::iter::Sum for Decimal<$backing, D> {
161 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
162 iter.fold(Self::ZERO, |acc, x| acc + x)
163 }
164 }
165
166 impl<'a, const D: u8> core::iter::Sum<&'a Self> for Decimal<$backing, D> {
167 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
168 iter.fold(Self::ZERO, |acc, &x| acc + x)
169 }
170 }
171
172 impl<const D: u8> core::iter::Product for Decimal<$backing, D> {
173 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
174 iter.fold(Self::ONE, |acc, x| acc * x)
175 }
176 }
177
178 impl<'a, const D: u8> core::iter::Product<&'a Self> for Decimal<$backing, D> {
179 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
180 iter.fold(Self::ONE, |acc, &x| acc * x)
181 }
182 }
183 };
184}
185
186impl_decimal_iter_traits!(i32);
187impl_decimal_iter_traits!(i64);
188impl_decimal_iter_traits!(i128);
189
190macro_rules! impl_decimal_from_traits {
195 ($backing:ty) => {
196 #[cfg(feature = "std")]
201 impl<const D: u8> TryFrom<f64> for Decimal<$backing, D> {
202 type Error = crate::error::ConvertError;
203
204 fn try_from(value: f64) -> Result<Self, Self::Error> {
205 Self::from_f64(value)
206 }
207 }
208
209 #[cfg(feature = "std")]
210 impl<const D: u8> TryFrom<f32> for Decimal<$backing, D> {
211 type Error = crate::error::ConvertError;
212
213 fn try_from(value: f32) -> Result<Self, Self::Error> {
214 Self::from_f32(value)
215 }
216 }
217 };
218}
219
220impl_decimal_from_traits!(i32);
221impl_decimal_from_traits!(i64);
222impl_decimal_from_traits!(i128);