Skip to main content

reifydb_value/value/number/
promote.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4
5#![cfg_attr(rustfmt, rustfmt_skip)]
6
7use std::cmp::Ordering;
8
9use crate::value::is::IsNumber;
10
11pub trait Promote<R> where Self: IsNumber, R: IsNumber {
12    type Output: IsNumber;
13    fn checked_promote(&self, r: &R) -> Option<(Self::Output, Self::Output)>;
14    fn saturating_promote(&self, r: &R) -> (Self::Output, Self::Output);
15    fn wrapping_promote(&self, r: &R) -> (Self::Output, Self::Output);
16
17    fn compare(&self, r: &R) -> Option<Ordering> {
18        self.checked_promote(r).and_then(|(l, r)| l.partial_cmp(&r))
19    }
20}
21
22macro_rules! impl_promote_float_float {
23    ($l:ty, $r:ty => $common:ty) => {
24        impl Promote<$r> for $l {
25            type Output = $common;
26
27            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)> {
28                Some((*self as $common, *r as $common))
29            }
30
31            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
32                let l = if self.is_finite() {
33                    *self as $common
34                } else if self.is_sign_negative() {
35                    <$common>::MIN
36                } else {
37                    <$common>::MAX
38                };
39                let r = if r.is_finite() {
40                    *r as $common
41                } else if r.is_sign_negative() {
42                    <$common>::MIN
43                } else {
44                    <$common>::MAX
45                };
46                (l, r)
47            }
48
49            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
50                (*self as $common, *r as $common)
51            }
52        }
53    };
54}
55
56macro_rules! impl_promote_float_integer {
57    ($l:ty, $r:ty => $common:ty) => {
58        impl Promote<$r> for $l {
59            type Output = $common;
60
61            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)> {
62                if self.is_finite() {
63                    Some((*self as $common, *r as $common))
64                } else {
65                    None
66                }
67            }
68
69            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
70                let l = if self.is_finite() {
71                    *self as $common
72                } else if self.is_sign_negative() {
73                    <$common>::MIN
74                } else {
75                    <$common>::MAX
76                };
77
78                let r = *r as $common;
79                (l, r)
80            }
81
82            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
83                (*self as $common, *r as $common)
84            }
85        }
86    };
87}
88
89
90macro_rules! impl_promote_integer_float {
91    ($l:ty, $r:ty => $common:ty) => {
92        impl Promote<$r> for $l {
93            type Output = $common;
94
95            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)> {
96                if r.is_finite() {
97                    Some((*self as $common, *r as $common))
98                } else {
99                    None
100                }
101            }
102
103            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
104                let l = *self as $common;
105                let r = if r.is_finite() {
106                    *r as $common
107                } else if r.is_sign_negative() {
108                    <$common>::MIN
109                } else {
110                    <$common>::MAX
111                };
112                (l, r)
113            }
114
115            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
116                (*self as $common, *r as $common)
117            }
118        }
119    };
120}
121
122
123
124impl_promote_float_float!(f32, f32 => f64);
125impl_promote_float_float!(f32, f64 => f64); impl_promote_float_float!(f64, f32 => f64);
126impl_promote_float_float!(f64, f64 => f64);
127
128
129
130impl_promote_float_integer!(f32, i8 => f64); impl_promote_integer_float!(i8, f32 => f64);
131impl_promote_float_integer!(f32, i16 => f64); impl_promote_integer_float!(i16, f32 => f64);
132impl_promote_float_integer!(f32, i32 => f64); impl_promote_integer_float!(i32, f32 => f64);
133impl_promote_float_integer!(f32, i64 => f64); impl_promote_integer_float!(i64, f32 => f64);
134impl_promote_float_integer!(f32, i128 => f64); impl_promote_integer_float!(i128, f32 => f64);
135
136impl_promote_float_integer!(f64, i8 => f64); impl_promote_integer_float!(i8, f64 => f64);
137impl_promote_float_integer!(f64, i16 => f64); impl_promote_integer_float!(i16, f64 => f64);
138impl_promote_float_integer!(f64, i32 => f64); impl_promote_integer_float!(i32, f64 => f64);
139impl_promote_float_integer!(f64, i64 => f64); impl_promote_integer_float!(i64, f64 => f64);
140impl_promote_float_integer!(f64, i128 => f64); impl_promote_integer_float!(i128, f64 => f64);
141
142
143
144impl_promote_float_integer!(f32, u8 => f64); impl_promote_integer_float!(u8, f32 => f64);
145impl_promote_float_integer!(f32, u16 => f64); impl_promote_integer_float!(u16, f32 => f64);
146impl_promote_float_integer!(f32, u32 => f64); impl_promote_integer_float!(u32, f32 => f64);
147impl_promote_float_integer!(f32, u64 => f64); impl_promote_integer_float!(u64, f32 => f64);
148impl_promote_float_integer!(f32, u128 => f64); impl_promote_integer_float!(u128, f32 => f64);
149
150impl_promote_float_integer!(f64, u8 => f64); impl_promote_integer_float!(u8, f64 => f64);
151impl_promote_float_integer!(f64, u16 => f64); impl_promote_integer_float!(u16, f64 => f64);
152impl_promote_float_integer!(f64, u32 => f64); impl_promote_integer_float!(u32, f64 => f64);
153impl_promote_float_integer!(f64, u64 => f64); impl_promote_integer_float!(u64, f64 => f64);
154impl_promote_float_integer!(f64, u128 => f64); impl_promote_integer_float!(u128, f64 => f64);
155
156
157macro_rules! impl_promote_signed_signed {
158    ($l:ty, $r:ty => $common:ty) => {
159        impl Promote<$r> for $l {
160            type Output = $common;
161
162            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)>{
163                let l: Option<$common> = <$common>::try_from(*self).ok();
164                let r: Option<$common> = <$common>::try_from(*r).ok();
165                match(l,r){
166                    (Some(l),Some(r)) => Some((l,r)),
167                    _ => None
168                }
169            }
170
171            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
172                let l = match <$common>::try_from(*self) {
173                    Ok(v) => v,
174                    Err(_) => if *self < 0 { <$common>::MIN } else { <$common>::MAX }};
175                let r = match <$common>::try_from(*r) {
176                    Ok(v) => v,
177                    Err(_) => if *r < 0 { <$common>::MIN } else { <$common>::MAX }};
178                (l, r)
179            }
180
181            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
182                (*self as $common, *r as $common)
183            }
184        }
185    };
186}
187impl_promote_signed_signed!(i8, i8 => i128);
188impl_promote_signed_signed!(i8, i16 => i128); impl_promote_signed_signed!(i16, i8 => i128);
189impl_promote_signed_signed!(i8, i32 => i128); impl_promote_signed_signed!(i32, i8 => i128);
190impl_promote_signed_signed!(i8, i64 => i128); impl_promote_signed_signed!(i64, i8 => i128);
191impl_promote_signed_signed!(i8, i128 => i128); impl_promote_signed_signed!(i128, i8 => i128);
192
193impl_promote_signed_signed!(i16, i16 => i128);
194impl_promote_signed_signed!(i16, i32 => i128); impl_promote_signed_signed!(i32, i16 => i128);
195impl_promote_signed_signed!(i16, i64 => i128); impl_promote_signed_signed!(i64, i16 => i128);
196impl_promote_signed_signed!(i16, i128 => i128); impl_promote_signed_signed!(i128, i16 => i128);
197
198impl_promote_signed_signed!(i32, i32 => i128);
199impl_promote_signed_signed!(i32, i64 => i128); impl_promote_signed_signed!(i64, i32 => i128);
200impl_promote_signed_signed!(i32, i128 => i128); impl_promote_signed_signed!(i128, i32 => i128);
201
202impl_promote_signed_signed!(i64, i64 => i128);
203impl_promote_signed_signed!(i64, i128 => i128); impl_promote_signed_signed!(i128, i64 => i128);
204
205impl_promote_signed_signed!(i128, i128 => i128);
206
207macro_rules! impl_promote_unsigned_unsigned {
208    ($l:ty, $r:ty => $common:ty) => {
209        impl Promote<$r> for $l {
210            type Output = $common;
211
212            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)>{
213                let l: Option<$common> = <$common>::try_from(*self).ok();
214                let r: Option<$common> = <$common>::try_from(*r).ok();
215                match(l,r){
216                    (Some(l),Some(r)) => Some((l,r)),
217                    _ => None
218                }
219            }
220
221            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
222                let l = match <$common>::try_from(*self) {
223                    Ok(v) => v,
224                    Err(_) =>  <$common>::MAX};
225                let r = match <$common>::try_from(*r) {
226                    Ok(v) => v,
227                    Err(_) => <$common>::MAX};
228                (l, r)
229            }
230
231            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
232                (*self as $common, *r as $common)
233            }
234        }
235    };
236}
237
238impl_promote_unsigned_unsigned!(u8, u8 => u128);
239impl_promote_unsigned_unsigned!(u8, u16 => u128); impl_promote_unsigned_unsigned!(u16, u8 => u128);
240impl_promote_unsigned_unsigned!(u8, u32 => u128); impl_promote_unsigned_unsigned!(u32, u8 => u128);
241impl_promote_unsigned_unsigned!(u8, u64 => u128); impl_promote_unsigned_unsigned!(u64, u8 => u128);
242impl_promote_unsigned_unsigned!(u8, u128 => u128); impl_promote_unsigned_unsigned!(u128, u8 => u128);
243
244impl_promote_unsigned_unsigned!(u16, u16 => u128);
245impl_promote_unsigned_unsigned!(u16, u32 => u128); impl_promote_unsigned_unsigned!(u32, u16 => u128);
246impl_promote_unsigned_unsigned!(u16, u64 => u128); impl_promote_unsigned_unsigned!(u64, u16 => u128);
247impl_promote_unsigned_unsigned!(u16, u128 => u128); impl_promote_unsigned_unsigned!(u128, u16 => u128);
248
249impl_promote_unsigned_unsigned!(u32, u32 => u128);
250impl_promote_unsigned_unsigned!(u32, u64 => u128); impl_promote_unsigned_unsigned!(u64, u32 => u128);
251impl_promote_unsigned_unsigned!(u32, u128 => u128); impl_promote_unsigned_unsigned!(u128, u32 => u128);
252
253impl_promote_unsigned_unsigned!(u64, u64 => u128);
254impl_promote_unsigned_unsigned!(u64, u128 => u128); impl_promote_unsigned_unsigned!(u128, u64 => u128);
255
256impl_promote_unsigned_unsigned!(u128, u128 => u128);
257
258
259macro_rules! impl_promote_signed_unsigned {
260    ($l:ty, $r:ty => $common:ty) => {
261        impl Promote<$r> for $l {
262            type Output = $common;
263
264            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)>{
265                let l: Option<$common> = <$common>::try_from(*self).ok();
266                let r: Option<$common> = <$common>::try_from(*r).ok();
267                match(l,r){
268                    (Some(l),Some(r)) => Some((l,r)),
269                    _ => None
270                }
271            }
272
273            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
274                let l = match <$common>::try_from(*self) {
275                    Ok(v) => v,
276                    Err(_) => if *self < 0 { <$common>::MIN } else { <$common>::MAX }};
277                let r = match <$common>::try_from(*r) {
278                    Ok(v) => v,
279                    Err(_) => <$common>::MAX};
280                (l, r)
281            }
282
283            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
284                (*self as $common, *r as $common)
285            }
286
287            fn compare(&self, r: &$r) -> Option<Ordering> {
288                if *self < 0 {
289                    return Some(Ordering::Less);
290                }
291                Some((*self as u128).cmp(&(*r as u128)))
292            }
293        }
294    };
295}
296
297macro_rules! impl_promote_unsigned_signed {
298    ($l:ty, $r:ty => $common:ty) => {
299        impl Promote<$r> for $l {
300            type Output = $common;
301
302            fn checked_promote(&self, r: &$r) -> Option<(Self::Output, Self::Output)>{
303                let l: Option<$common> = <$common>::try_from(*self).ok();
304                let r: Option<$common> = <$common>::try_from(*r).ok();
305                match(l,r){
306                    (Some(l),Some(r)) => Some((l,r)),
307                    _ => None
308                }
309            }
310
311            fn saturating_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
312                let l = match <$common>::try_from(*self) {
313                    Ok(v) => v,
314                    Err(_) => <$common>::MAX};
315                let r = match <$common>::try_from(*r) {
316                    Ok(v) => v,
317                    Err(_) => if *r < 0 { <$common>::MIN } else { <$common>::MAX }};
318                (l, r)
319            }
320
321            fn wrapping_promote(&self, r: &$r) -> (Self::Output, Self::Output) {
322                (*self as $common, *r as $common)
323            }
324
325            fn compare(&self, r: &$r) -> Option<Ordering> {
326                if *r < 0 {
327                    return Some(Ordering::Greater);
328                }
329                Some((*self as u128).cmp(&(*r as u128)))
330            }
331        }
332    };
333}
334
335impl_promote_signed_unsigned!(i8, u8 => i128);    impl_promote_unsigned_signed!(u8, i8 => i128);
336impl_promote_signed_unsigned!(i8, u16 => i128);   impl_promote_unsigned_signed!(u16, i8 => i128);
337impl_promote_signed_unsigned!(i8, u32 => i128);   impl_promote_unsigned_signed!(u32, i8 => i128);
338impl_promote_signed_unsigned!(i8, u64 => i128);   impl_promote_unsigned_signed!(u64, i8 => i128);
339impl_promote_signed_unsigned!(i8, u128 => i128);  impl_promote_unsigned_signed!(u128, i8 => i128);
340impl_promote_signed_unsigned!(i16, u8 => i128);   impl_promote_unsigned_signed!(u8, i16 => i128);
341impl_promote_signed_unsigned!(i16, u16 => i128);  impl_promote_unsigned_signed!(u16, i16 => i128);
342impl_promote_signed_unsigned!(i16, u32 => i128);  impl_promote_unsigned_signed!(u32, i16 => i128);
343impl_promote_signed_unsigned!(i16, u64 => i128);  impl_promote_unsigned_signed!(u64, i16 => i128);
344impl_promote_signed_unsigned!(i16, u128 => i128); impl_promote_unsigned_signed!(u128, i16 => i128);
345impl_promote_signed_unsigned!(i32, u8 => i128);   impl_promote_unsigned_signed!(u8, i32 => i128);
346impl_promote_signed_unsigned!(i32, u16 => i128);  impl_promote_unsigned_signed!(u16, i32 => i128);
347impl_promote_signed_unsigned!(i32, u32 => i128);  impl_promote_unsigned_signed!(u32, i32 => i128);
348impl_promote_signed_unsigned!(i32, u64 => i128);  impl_promote_unsigned_signed!(u64, i32 => i128);
349impl_promote_signed_unsigned!(i32, u128 => i128); impl_promote_unsigned_signed!(u128, i32 => i128);
350impl_promote_signed_unsigned!(i64, u8 => i128);   impl_promote_unsigned_signed!(u8, i64 => i128);
351impl_promote_signed_unsigned!(i64, u16 => i128);  impl_promote_unsigned_signed!(u16, i64 => i128);
352impl_promote_signed_unsigned!(i64, u32 => i128);  impl_promote_unsigned_signed!(u32, i64 => i128);
353impl_promote_signed_unsigned!(i64, u64 => i128);  impl_promote_unsigned_signed!(u64, i64 => i128);
354impl_promote_signed_unsigned!(i64, u128 => i128); impl_promote_unsigned_signed!(u128, i64 => i128);
355impl_promote_signed_unsigned!(i128, u8 => i128);   impl_promote_unsigned_signed!(u8, i128 => i128);
356impl_promote_signed_unsigned!(i128, u16 => i128);  impl_promote_unsigned_signed!(u16, i128 => i128);
357impl_promote_signed_unsigned!(i128, u32 => i128);  impl_promote_unsigned_signed!(u32, i128 => i128);
358impl_promote_signed_unsigned!(i128, u64 => i128);  impl_promote_unsigned_signed!(u64, i128 => i128);
359impl_promote_signed_unsigned!(i128, u128 => i128); impl_promote_unsigned_signed!(u128, i128 => i128);
360
361use crate::value::decimal::Decimal;
362
363impl Promote<Decimal> for Decimal {
364    type Output = Decimal;
365
366    fn checked_promote(&self, r: &Decimal) -> Option<(Self::Output, Self::Output)> {
367        Some((self.clone(), r.clone()))
368    }
369
370    fn saturating_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
371        (self.clone(), r.clone())
372    }
373
374    fn wrapping_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
375        (self.clone(), r.clone())
376    }
377}
378
379impl Promote<Decimal> for f32 {
380    type Output = Decimal;
381    
382    fn checked_promote(&self, r: &Decimal) -> Option<(Self::Output, Self::Output)> {
383        if self.is_finite() {
384            Some((Decimal::from(*self), r.clone()))
385        } else {
386            None
387        }
388    }
389    
390    fn saturating_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
391        let l_as_decimal = if self.is_finite() {
392            Decimal::from(*self)
393        } else {
394            Decimal::zero()
395        };
396        (l_as_decimal, r.clone())
397    }
398    
399    fn wrapping_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
400        let l_as_decimal = if self.is_finite() {
401            Decimal::from(*self)
402        } else {
403            Decimal::zero()
404        };
405        (l_as_decimal, r.clone())
406    }
407}
408
409impl Promote<f32> for Decimal {
410    type Output = Decimal;
411    
412    fn checked_promote(&self, r: &f32) -> Option<(Self::Output, Self::Output)> {
413        if r.is_finite() {
414            Some((self.clone(), Decimal::from(*r)))
415        } else {
416            None
417        }
418    }
419    
420    fn saturating_promote(&self, r: &f32) -> (Self::Output, Self::Output) {
421        let r_as_decimal = if r.is_finite() {
422            Decimal::from(*r)
423        } else {
424            Decimal::zero()
425        };
426        (self.clone(), r_as_decimal)
427    }
428    
429    fn wrapping_promote(&self, r: &f32) -> (Self::Output, Self::Output) {
430        let r_as_decimal = if r.is_finite() {
431            Decimal::from(*r)
432        } else {
433            Decimal::zero()
434        };
435        (self.clone(), r_as_decimal)
436    }
437}
438
439
440impl Promote<Decimal> for f64 {
441    type Output = Decimal;
442    
443    fn checked_promote(&self, r: &Decimal) -> Option<(Self::Output, Self::Output)> {
444        if self.is_finite() {
445            let l_as_decimal = Decimal::from(*self);
446            Some((l_as_decimal, r.clone()))
447        } else {
448            None
449        }
450    }
451    
452    fn saturating_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
453        let l_as_decimal = if self.is_finite() {
454            Decimal::from(*self)
455        } else {
456            Decimal::zero()
457        };
458        (l_as_decimal, r.clone())
459    }
460    
461    fn wrapping_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
462        let l_as_decimal = if self.is_finite() {
463            Decimal::from(*self)
464        } else {
465            Decimal::zero()
466        };
467        (l_as_decimal, r.clone())
468    }
469}
470
471impl Promote<f64> for Decimal {
472    type Output = Decimal;
473    
474    fn checked_promote(&self, r: &f64) -> Option<(Self::Output, Self::Output)> {
475        if r.is_finite() {
476            let r_as_decimal = Decimal::from(*r);
477            Some((self.clone(), r_as_decimal))
478        } else {
479            None
480        }
481    }
482    
483    fn saturating_promote(&self, r: &f64) -> (Self::Output, Self::Output) {
484        let r_as_decimal = if r.is_finite() {
485            Decimal::from(*r)
486        } else {
487            Decimal::zero()
488        };
489        (self.clone(), r_as_decimal)
490    }
491    
492    fn wrapping_promote(&self, r: &f64) -> (Self::Output, Self::Output) {
493        let r_as_decimal = if r.is_finite() {
494            Decimal::from(*r)
495        } else {
496            Decimal::zero()
497        };
498        (self.clone(), r_as_decimal)
499    }
500}
501
502
503macro_rules! impl_promote_int_to_decimal {
504    ($($t:ty),*) => {
505        $(
506            impl Promote<Decimal> for $t {
507                type Output = Decimal;
508                
509                fn checked_promote(&self, r: &Decimal) -> Option<(Self::Output, Self::Output)> {
510                    Some((Decimal::from(*self), r.clone()))
511                }
512                
513                fn saturating_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
514                    (Decimal::from(*self), r.clone())
515                }
516                
517                fn wrapping_promote(&self, r: &Decimal) -> (Self::Output, Self::Output) {
518                    (Decimal::from(*self), r.clone())
519                }
520            }
521            
522            impl Promote<$t> for Decimal {
523                type Output = Decimal;
524                
525                fn checked_promote(&self, r: &$t) -> Option<(Self::Output, Self::Output)> {
526                    Some((self.clone(), Decimal::from(*r)))
527                }
528                
529                fn saturating_promote(&self, r: &$t) -> (Self::Output, Self::Output) {
530                    (self.clone(), Decimal::from(*r))
531                }
532                
533                fn wrapping_promote(&self, r: &$t) -> (Self::Output, Self::Output) {
534                    (self.clone(), Decimal::from(*r))
535                }
536            }
537        )*
538    }
539}
540
541impl_promote_int_to_decimal!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);