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