reifydb_value/value/number/safe/
mul.rs1pub trait SafeMul: Sized {
5 fn checked_mul(&self, r: &Self) -> Option<Self>;
6 fn saturating_mul(&self, r: &Self) -> Self;
7 fn wrapping_mul(&self, r: &Self) -> Self;
8}
9
10macro_rules! impl_safe_mul {
11 ($($t:ty),*) => {
12 $(
13 impl SafeMul for $t {
14 fn checked_mul(&self, r: &Self) -> Option<Self> {
15 <$t>::checked_mul(*self, *r)
16 }
17 fn saturating_mul(&self, r: &Self) -> Self {
18 <$t>::saturating_mul(*self, *r)
19 }
20 fn wrapping_mul(&self, r: &Self) -> Self {
21 <$t>::wrapping_mul(*self, *r)
22 }
23 }
24 )*
25 };
26}
27
28impl_safe_mul!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
29
30use crate::value::{decimal::Decimal, int::Int, uint::Uint};
31
32impl SafeMul for Int {
33 fn checked_mul(&self, r: &Self) -> Option<Self> {
34 Some(Int::from(&self.0 * &r.0))
35 }
36
37 fn saturating_mul(&self, r: &Self) -> Self {
38 Int::from(&self.0 * &r.0)
39 }
40
41 fn wrapping_mul(&self, r: &Self) -> Self {
42 Int::from(&self.0 * &r.0)
43 }
44}
45
46impl SafeMul for Uint {
47 fn checked_mul(&self, r: &Self) -> Option<Self> {
48 Some(Uint::from(&self.0 * &r.0))
49 }
50
51 fn saturating_mul(&self, r: &Self) -> Self {
52 Uint::from(&self.0 * &r.0)
53 }
54
55 fn wrapping_mul(&self, r: &Self) -> Self {
56 Uint::from(&self.0 * &r.0)
57 }
58}
59
60impl SafeMul for Decimal {
61 fn checked_mul(&self, r: &Self) -> Option<Self> {
62 let result = self.inner() * r.inner();
63 Some(Decimal::from(result))
64 }
65
66 fn saturating_mul(&self, r: &Self) -> Self {
67 let result = self.inner() * r.inner();
68 Decimal::from(result)
69 }
70
71 fn wrapping_mul(&self, r: &Self) -> Self {
72 let result = self.inner() * r.inner();
73 Decimal::from(result)
74 }
75}
76
77impl SafeMul for f32 {
78 fn checked_mul(&self, r: &Self) -> Option<Self> {
79 let result = *self * *r;
80 if result.is_finite() {
81 Some(result)
82 } else {
83 None
84 }
85 }
86
87 fn saturating_mul(&self, r: &Self) -> Self {
88 let result = *self * *r;
89 if result.is_infinite() {
90 if result.is_sign_positive() {
91 f32::MAX
92 } else {
93 f32::MIN
94 }
95 } else {
96 result
97 }
98 }
99
100 fn wrapping_mul(&self, r: &Self) -> Self {
101 let result = *self * *r;
102 if result.is_infinite() || result.is_nan() {
103 let sign = if (self.is_sign_positive() && r.is_sign_positive())
104 || (self.is_sign_negative() && r.is_sign_negative())
105 {
106 1.0
107 } else {
108 -1.0
109 };
110
111 let wrapped_val = f32::MAX / 2.0;
112 wrapped_val * sign
113 } else {
114 result
115 }
116 }
117}
118
119impl SafeMul for f64 {
120 fn checked_mul(&self, r: &Self) -> Option<Self> {
121 let result = *self * *r;
122 if result.is_finite() {
123 Some(result)
124 } else {
125 None
126 }
127 }
128
129 fn saturating_mul(&self, r: &Self) -> Self {
130 let result = *self * *r;
131 if result.is_infinite() {
132 if result.is_sign_positive() {
133 f64::MAX
134 } else {
135 f64::MIN
136 }
137 } else {
138 result
139 }
140 }
141
142 fn wrapping_mul(&self, r: &Self) -> Self {
143 let result = *self * *r;
144 if result.is_infinite() || result.is_nan() {
145 let sign = if (self.is_sign_positive() && r.is_sign_positive())
146 || (self.is_sign_negative() && r.is_sign_negative())
147 {
148 1.0
149 } else {
150 -1.0
151 };
152
153 let wrapped_val = f64::MAX / 2.0;
154 wrapped_val * sign
155 } else {
156 result
157 }
158 }
159}
160
161#[cfg(test)]
162pub mod tests {
163
164 macro_rules! signed_unsigned {
165 ($($t:ty => $mod:ident),*) => {
166 $(
167 mod $mod {
168 use super::super::SafeMul;
169
170 #[test]
171 fn checked_mul_happy() {
172 let x: $t = 10;
173 let y: $t = 2;
174 assert_eq!(SafeMul::checked_mul(&x, &y), Some(20));
175 }
176
177 #[test]
178 fn checked_mul_unhappy() {
179 let x: $t = <$t>::MAX;
180 let y: $t = 2;
181 assert_eq!(SafeMul::checked_mul(&x, &y), None);
182 }
183
184 #[test]
185 fn saturating_mul_happy() {
186 let x: $t = 10;
187 let y: $t = 2;
188 assert_eq!(SafeMul::saturating_mul(&x, &y), 20);
189 }
190
191 #[test]
192 fn saturating_mul_unhappy() {
193 let x: $t = <$t>::MAX;
194 let y: $t = 2;
195 assert_eq!(SafeMul::saturating_mul(&x, &y), <$t>::MAX);
196 }
197
198 #[test]
199 fn wrapping_mul_happy() {
200 let x: $t = 10;
201 let y: $t = 2;
202 assert_eq!(SafeMul::wrapping_mul(&x, &y), 20);
203 }
204
205 #[test]
206 fn wrapping_mul_unhappy() {
207 let x: $t = <$t>::MAX;
208 let y: $t = 2;
209 assert_eq!(SafeMul::wrapping_mul(&x, &y), <$t>::wrapping_mul(<$t>::MAX, 2));
210 }
211 }
212 )*
213 };
214 }
215
216 signed_unsigned!(
217 i8 => i8,
218 i16 => i16,
219 i32 => i32,
220 i64 => i64,
221 i128 => i128,
222 u8 => u8,
223 u16 => u16,
224 u32 => u32,
225 u64 => u64,
226 u128 => u128
227 );
228
229 mod f32 {
230 use crate::value::number::safe::mul::SafeMul;
231
232 #[test]
233 fn checked_mul_happy() {
234 let x: f32 = 10.0;
235 let y: f32 = 2.0;
236 assert_eq!(SafeMul::checked_mul(&x, &y), Some(20.0));
237 }
238
239 #[test]
240 fn checked_mul_unhappy() {
241 let x: f32 = f32::MAX;
242 let y: f32 = 2.0;
243 assert_eq!(SafeMul::checked_mul(&x, &y), None);
244 }
245
246 #[test]
247 fn saturating_mul_happy() {
248 let x: f32 = 10.0;
249 let y: f32 = 2.0;
250 assert_eq!(SafeMul::saturating_mul(&x, &y), 20.0);
251 }
252
253 #[test]
254 fn saturating_mul_unhappy() {
255 let x: f32 = f32::MAX;
256 let y: f32 = 2.0;
257 assert_eq!(SafeMul::saturating_mul(&x, &y), f32::MAX);
258 }
259
260 #[test]
261 fn wrapping_mul_happy() {
262 let x: f32 = 10.0;
263 let y: f32 = 2.0;
264 assert_eq!(SafeMul::wrapping_mul(&x, &y), 20.0);
265 }
266
267 #[test]
268 fn wrapping_mul_unhappy() {
269 let x: f32 = f32::MAX;
270 let y: f32 = 2.0;
271 let result = SafeMul::wrapping_mul(&x, &y);
272 assert!(result.is_finite());
274 assert!(result > 0.0);
276 assert_eq!(result, f32::MAX / 2.0);
279 }
280
281 #[test]
282 fn wrapping_mul_negative() {
283 let x: f32 = f32::MAX;
284 let y: f32 = -2.0;
285 let result = SafeMul::wrapping_mul(&x, &y);
286 assert!(result.is_finite());
288 assert!(result < 0.0);
290 assert_eq!(result, -(f32::MAX / 2.0));
293 }
294 }
295
296 mod f64 {
297 use crate::value::number::safe::mul::SafeMul;
298
299 #[test]
300 fn checked_mul_happy() {
301 let x: f64 = 10.0;
302 let y: f64 = 2.0;
303 assert_eq!(SafeMul::checked_mul(&x, &y), Some(20.0));
304 }
305
306 #[test]
307 fn checked_mul_unhappy() {
308 let x: f64 = f64::MAX;
309 let y: f64 = 2.0;
310 assert_eq!(SafeMul::checked_mul(&x, &y), None);
311 }
312
313 #[test]
314 fn saturating_mul_happy() {
315 let x: f64 = 10.0;
316 let y: f64 = 2.0;
317 assert_eq!(SafeMul::saturating_mul(&x, &y), 20.0);
318 }
319
320 #[test]
321 fn saturating_mul_unhappy() {
322 let x: f64 = f64::MAX;
323 let y: f64 = 2.0;
324 assert_eq!(SafeMul::saturating_mul(&x, &y), f64::MAX);
325 }
326
327 #[test]
328 fn wrapping_mul_happy() {
329 let x: f64 = 10.0;
330 let y: f64 = 2.0;
331 assert_eq!(SafeMul::wrapping_mul(&x, &y), 20.0);
332 }
333
334 #[test]
335 fn wrapping_mul_unhappy() {
336 let x: f64 = f64::MAX;
337 let y: f64 = 2.0;
338 let result = SafeMul::wrapping_mul(&x, &y);
339 assert!(result.is_finite());
341 assert!(result > 0.0);
343 assert_eq!(result, f64::MAX / 2.0);
346 }
347
348 #[test]
349 fn wrapping_mul_negative() {
350 let x: f64 = f64::MAX;
351 let y: f64 = -2.0;
352 let result = SafeMul::wrapping_mul(&x, &y);
353 assert!(result.is_finite());
355 assert!(result < 0.0);
357 assert_eq!(result, -(f64::MAX / 2.0));
360 }
361 }
362}