rstsr_dtype_traits/
promotion.rs

1//! Data type promotion traits.
2//!
3//! This follows NumPy's convention:
4//! <https://numpy.org/doc/stable/reference/arrays.promotion.html>
5
6#![allow(non_camel_case_types)]
7
8/* #region trait definition and basic implementation */
9
10type c32 = num::complex::Complex<f32>;
11type c64 = num::complex::Complex<f64>;
12use duplicate::duplicate_item;
13use num::Complex;
14use num::{One, Zero};
15
16pub trait DTypeIntoFloatAPI {
17    type FloatType;
18    fn into_float(self) -> Self::FloatType;
19}
20
21pub trait DTypeCastAPI<T> {
22    fn into_cast(self) -> T;
23}
24
25pub trait DTypePromoteAPI<T> {
26    type Res;
27    const SAME_TYPE: bool = false;
28    const CAN_CAST_SELF: bool = false;
29    const CAN_CAST_OTHER: bool = false;
30    fn promote_self(self) -> Self::Res;
31    fn promote_other(val: T) -> Self::Res;
32    #[inline]
33    fn promote_pair(self, val: T) -> (Self::Res, Self::Res)
34    where
35        Self: Sized,
36    {
37        (self.promote_self(), Self::promote_other(val))
38    }
39}
40
41impl<T> DTypePromoteAPI<T> for T {
42    type Res = T;
43    const SAME_TYPE: bool = true;
44    const CAN_CAST_SELF: bool = true;
45    const CAN_CAST_OTHER: bool = true;
46    #[inline]
47    fn promote_self(self) -> Self::Res {
48        self
49    }
50    #[inline]
51    fn promote_other(val: T) -> Self::Res {
52        val
53    }
54}
55
56impl<T> DTypeCastAPI<T> for T {
57    #[inline]
58    fn into_cast(self) -> T {
59        self
60    }
61}
62
63/* #endregion */
64
65/* #region DTypeIntoFloatAPI */
66
67#[duplicate_item(T; [u8]; [u16]; [u32]; [u64];)]
68impl DTypeIntoFloatAPI for T {
69    type FloatType = f64;
70    #[inline]
71    fn into_float(self) -> Self::FloatType {
72        self as _
73    }
74}
75
76#[duplicate_item(T; [i8]; [i16]; [i32]; [i64];)]
77impl DTypeIntoFloatAPI for T {
78    type FloatType = f64;
79    #[inline]
80    fn into_float(self) -> Self::FloatType {
81        self as _
82    }
83}
84
85#[duplicate_item(T; [f32]; [f64]; [c32]; [c64];)]
86impl DTypeIntoFloatAPI for T {
87    type FloatType = T;
88    #[inline]
89    fn into_float(self) -> Self::FloatType {
90        self
91    }
92}
93
94#[cfg(feature = "half")]
95#[duplicate_item(T; [half::f16]; [half::bf16];)]
96impl DTypeIntoFloatAPI for T {
97    type FloatType = T;
98    #[inline]
99    fn into_float(self) -> Self::FloatType {
100        self
101    }
102}
103
104impl DTypeIntoFloatAPI for usize {
105    type FloatType = f64;
106    #[inline]
107    fn into_float(self) -> Self::FloatType {
108        self as _
109    }
110}
111
112impl DTypeIntoFloatAPI for isize {
113    type FloatType = f64;
114    #[inline]
115    fn into_float(self) -> Self::FloatType {
116        self as _
117    }
118}
119
120/* #endregion */
121
122/* #region rule bool<T> */
123
124macro_rules! impl_promotion_bool_T {
125    ($T:ty) => {
126        impl DTypePromoteAPI<$T> for bool {
127            type Res = $T;
128            const CAN_CAST_OTHER: bool = true;
129            #[inline]
130            fn promote_self(self) -> Self::Res {
131                if self {
132                    <$T>::one()
133                } else {
134                    <$T>::zero()
135                }
136            }
137            #[inline]
138            fn promote_other(val: $T) -> Self::Res {
139                val
140            }
141        }
142
143        impl DTypePromoteAPI<bool> for $T {
144            type Res = $T;
145            const CAN_CAST_SELF: bool = true;
146            #[inline]
147            fn promote_self(self) -> Self::Res {
148                self
149            }
150            #[inline]
151            fn promote_other(val: bool) -> Self::Res {
152                if val {
153                    <$T>::one()
154                } else {
155                    <$T>::zero()
156                }
157            }
158        }
159
160        impl DTypeCastAPI<bool> for $T {
161            #[inline]
162            fn into_cast(self) -> bool {
163                self != <$T>::zero()
164            }
165        }
166
167        impl DTypeCastAPI<$T> for bool {
168            #[inline]
169            fn into_cast(self) -> $T {
170                if self {
171                    <$T>::one()
172                } else {
173                    <$T>::zero()
174                }
175            }
176        }
177    };
178}
179
180// internal type
181impl_promotion_bool_T!(u8);
182impl_promotion_bool_T!(u16);
183impl_promotion_bool_T!(u32);
184impl_promotion_bool_T!(u64);
185impl_promotion_bool_T!(i8);
186impl_promotion_bool_T!(i16);
187impl_promotion_bool_T!(i32);
188impl_promotion_bool_T!(i64);
189impl_promotion_bool_T!(f32);
190impl_promotion_bool_T!(f64);
191// external type
192impl_promotion_bool_T!(usize);
193impl_promotion_bool_T!(isize);
194#[cfg(feature = "half")]
195impl_promotion_bool_T!(half::f16);
196#[cfg(feature = "half")]
197impl_promotion_bool_T!(half::bf16);
198// complex float
199impl_promotion_bool_T!(c32);
200impl_promotion_bool_T!(c64);
201
202/* #endregion */
203
204/* #region as-able primitive types */
205
206macro_rules! impl_promotion_asable {
207    ($T1:ty, $T2:ty, $can_cast_self: ident, $can_cast_other: ident, $Res:ty) => {
208        impl DTypePromoteAPI<$T2> for $T1 {
209            type Res = $Res;
210            const CAN_CAST_SELF: bool = $can_cast_self;
211            const CAN_CAST_OTHER: bool = $can_cast_other;
212            #[inline]
213            fn promote_self(self) -> Self::Res {
214                self as $Res
215            }
216            #[inline]
217            fn promote_other(val: $T2) -> Self::Res {
218                val as $Res
219            }
220        }
221
222        impl DTypeCastAPI<$T2> for $T1 {
223            #[inline]
224            fn into_cast(self) -> $T2 {
225                self as $T2
226            }
227        }
228    };
229}
230
231// internal typeimpl_promotion_asable!(i8, i16, false, true, i16);
232impl_promotion_asable!(i8, i32, false, true, i32);
233impl_promotion_asable!(i8, i64, false, true, i64);
234impl_promotion_asable!(i8, u8, false, false, i16);
235impl_promotion_asable!(i8, u16, false, false, i32);
236impl_promotion_asable!(i8, u32, false, false, i64);
237impl_promotion_asable!(i8, u64, false, false, f64);
238impl_promotion_asable!(i8, f32, false, true, f32);
239impl_promotion_asable!(i8, f64, false, true, f64);
240impl_promotion_asable!(i16, i8, true, false, i16);
241impl_promotion_asable!(i16, i32, false, true, i32);
242impl_promotion_asable!(i16, i64, false, true, i64);
243impl_promotion_asable!(i16, u8, true, false, i16);
244impl_promotion_asable!(i16, u16, false, false, i32);
245impl_promotion_asable!(i16, u32, false, false, i64);
246impl_promotion_asable!(i16, u64, false, false, f64);
247impl_promotion_asable!(i16, f32, false, true, f32);
248impl_promotion_asable!(i16, f64, false, true, f64);
249impl_promotion_asable!(i32, i8, true, false, i32);
250impl_promotion_asable!(i32, i16, true, false, i32);
251impl_promotion_asable!(i32, i64, false, true, i64);
252impl_promotion_asable!(i32, u8, true, false, i32);
253impl_promotion_asable!(i32, u16, true, false, i32);
254impl_promotion_asable!(i32, u32, false, false, i64);
255impl_promotion_asable!(i32, u64, false, false, f64);
256impl_promotion_asable!(i32, f32, false, false, f64);
257impl_promotion_asable!(i32, f64, false, true, f64);
258impl_promotion_asable!(i64, i8, true, false, i64);
259impl_promotion_asable!(i64, i16, true, false, i64);
260impl_promotion_asable!(i64, i32, true, false, i64);
261impl_promotion_asable!(i64, u8, true, false, i64);
262impl_promotion_asable!(i64, u16, true, false, i64);
263impl_promotion_asable!(i64, u32, true, false, i64);
264impl_promotion_asable!(i64, u64, false, false, f64);
265impl_promotion_asable!(i64, f32, false, false, f64);
266impl_promotion_asable!(i64, f64, false, true, f64);
267impl_promotion_asable!(u8, i8, false, false, i16);
268impl_promotion_asable!(u8, i16, false, true, i16);
269impl_promotion_asable!(u8, i32, false, true, i32);
270impl_promotion_asable!(u8, i64, false, true, i64);
271impl_promotion_asable!(u8, u16, false, true, u16);
272impl_promotion_asable!(u8, u32, false, true, u32);
273impl_promotion_asable!(u8, u64, false, true, u64);
274impl_promotion_asable!(u8, f32, false, true, f32);
275impl_promotion_asable!(u8, f64, false, true, f64);
276impl_promotion_asable!(u16, i8, false, false, i32);
277impl_promotion_asable!(u16, i16, false, false, i32);
278impl_promotion_asable!(u16, i32, false, true, i32);
279impl_promotion_asable!(u16, i64, false, true, i64);
280impl_promotion_asable!(u16, u8, true, false, u16);
281impl_promotion_asable!(u16, u32, false, true, u32);
282impl_promotion_asable!(u16, u64, false, true, u64);
283impl_promotion_asable!(u16, f32, false, true, f32);
284impl_promotion_asable!(u16, f64, false, true, f64);
285impl_promotion_asable!(u32, i8, false, false, i64);
286impl_promotion_asable!(u32, i16, false, false, i64);
287impl_promotion_asable!(u32, i32, false, false, i64);
288impl_promotion_asable!(u32, i64, false, true, i64);
289impl_promotion_asable!(u32, u8, true, false, u32);
290impl_promotion_asable!(u32, u16, true, false, u32);
291impl_promotion_asable!(u32, u64, false, true, u64);
292impl_promotion_asable!(u32, f32, false, false, f64);
293impl_promotion_asable!(u32, f64, false, true, f64);
294impl_promotion_asable!(u64, i8, false, false, f64);
295impl_promotion_asable!(u64, i16, false, false, f64);
296impl_promotion_asable!(u64, i32, false, false, f64);
297impl_promotion_asable!(u64, i64, false, false, f64);
298impl_promotion_asable!(u64, u8, true, false, u64);
299impl_promotion_asable!(u64, u16, true, false, u64);
300impl_promotion_asable!(u64, u32, true, false, u64);
301impl_promotion_asable!(u64, f32, false, false, f64);
302impl_promotion_asable!(u64, f64, false, true, f64);
303impl_promotion_asable!(f32, i8, true, false, f32);
304impl_promotion_asable!(f32, i16, true, false, f32);
305impl_promotion_asable!(f32, i32, false, false, f64);
306impl_promotion_asable!(f32, i64, false, false, f64);
307impl_promotion_asable!(f32, u8, true, false, f32);
308impl_promotion_asable!(f32, u16, true, false, f32);
309impl_promotion_asable!(f32, u32, false, false, f64);
310impl_promotion_asable!(f32, u64, false, false, f64);
311impl_promotion_asable!(f32, f64, false, true, f64);
312impl_promotion_asable!(f64, i8, true, false, f64);
313impl_promotion_asable!(f64, i16, true, false, f64);
314impl_promotion_asable!(f64, i32, true, false, f64);
315impl_promotion_asable!(f64, i64, true, false, f64);
316impl_promotion_asable!(f64, u8, true, false, f64);
317impl_promotion_asable!(f64, u16, true, false, f64);
318impl_promotion_asable!(f64, u32, true, false, f64);
319impl_promotion_asable!(f64, u64, true, false, f64);
320impl_promotion_asable!(f64, f32, true, false, f64);
321
322// external type: isize
323impl_promotion_asable!(isize, i8, true, false, isize);
324impl_promotion_asable!(isize, i16, true, false, isize);
325impl_promotion_asable!(isize, i32, true, false, isize);
326impl_promotion_asable!(isize, i64, true, true, isize);
327impl_promotion_asable!(isize, u8, true, false, isize);
328impl_promotion_asable!(isize, u16, true, false, isize);
329impl_promotion_asable!(isize, u32, true, false, isize);
330impl_promotion_asable!(isize, u64, false, false, f64);
331impl_promotion_asable!(isize, f32, false, false, f64);
332impl_promotion_asable!(isize, f64, false, true, f64);
333impl_promotion_asable!(i8, isize, false, true, isize);
334impl_promotion_asable!(i16, isize, false, true, isize);
335impl_promotion_asable!(i32, isize, false, true, isize);
336impl_promotion_asable!(i64, isize, true, true, isize);
337impl_promotion_asable!(u8, isize, false, true, isize);
338impl_promotion_asable!(u16, isize, false, true, isize);
339impl_promotion_asable!(u32, isize, false, true, isize);
340impl_promotion_asable!(u64, isize, false, false, f64);
341impl_promotion_asable!(f32, isize, false, false, f64);
342impl_promotion_asable!(f64, isize, true, false, f64);
343
344// external type: usize
345impl_promotion_asable!(usize, i8, false, false, f64);
346impl_promotion_asable!(usize, i16, false, false, f64);
347impl_promotion_asable!(usize, i32, false, false, f64);
348impl_promotion_asable!(usize, i64, false, false, f64);
349impl_promotion_asable!(usize, u8, true, false, usize);
350impl_promotion_asable!(usize, u16, true, false, usize);
351impl_promotion_asable!(usize, u32, true, false, usize);
352impl_promotion_asable!(usize, u64, true, true, usize);
353impl_promotion_asable!(usize, f32, false, false, f64);
354impl_promotion_asable!(usize, f64, false, true, f64);
355impl_promotion_asable!(i8, usize, false, false, f64);
356impl_promotion_asable!(i16, usize, false, false, f64);
357impl_promotion_asable!(i32, usize, false, false, f64);
358impl_promotion_asable!(i64, usize, false, false, f64);
359impl_promotion_asable!(u8, usize, false, true, usize);
360impl_promotion_asable!(u16, usize, false, true, usize);
361impl_promotion_asable!(u32, usize, false, true, usize);
362impl_promotion_asable!(u64, usize, true, true, usize);
363impl_promotion_asable!(f32, usize, false, false, f64);
364impl_promotion_asable!(f64, usize, true, false, f64);
365
366/* #endregion */
367
368/* #region complex to primitive */
369
370macro_rules! impl_promotion_complex_primitive_cast_self {
371    ($TComp:ty, $TPrim:ty, $can_cast_self:ident, $can_cast_other:ident, $ResComp:ty) => {
372        impl DTypePromoteAPI<$TPrim> for Complex<$TComp> {
373            type Res = Complex<$ResComp>;
374            const CAN_CAST_SELF: bool = $can_cast_self;
375            const CAN_CAST_OTHER: bool = $can_cast_other;
376            #[inline]
377            fn promote_self(self) -> Self::Res {
378                self
379            }
380            #[inline]
381            fn promote_other(val: $TPrim) -> Self::Res {
382                Self::Res::new(val as _, 0 as _)
383            }
384        }
385    };
386}
387
388macro_rules! impl_promotion_complex_primitive_no_cast_self {
389    ($TComp:ty, $TPrim:ty, $can_cast_self:ident, $can_cast_other:ident, $ResComp:ty) => {
390        impl DTypePromoteAPI<$TPrim> for Complex<$TComp> {
391            type Res = Complex<$ResComp>;
392            const CAN_CAST_SELF: bool = $can_cast_self;
393            const CAN_CAST_OTHER: bool = $can_cast_other;
394            #[inline]
395            fn promote_self(self) -> Self::Res {
396                Self::Res::new(self.re as _, self.im as _)
397            }
398            #[inline]
399            fn promote_other(val: $TPrim) -> Self::Res {
400                Self::Res::new(val as _, 0 as _)
401            }
402        }
403    };
404}
405
406impl_promotion_complex_primitive_cast_self!(f32, i8, true, false, f32);
407impl_promotion_complex_primitive_cast_self!(f32, i16, true, false, f32);
408impl_promotion_complex_primitive_cast_self!(f32, u8, true, false, f32);
409impl_promotion_complex_primitive_cast_self!(f32, u16, true, false, f32);
410impl_promotion_complex_primitive_cast_self!(f32, f32, true, false, f32);
411
412impl_promotion_complex_primitive_cast_self!(f64, i8, true, false, f64);
413impl_promotion_complex_primitive_cast_self!(f64, i16, true, false, f64);
414impl_promotion_complex_primitive_cast_self!(f64, i32, true, false, f64);
415impl_promotion_complex_primitive_cast_self!(f64, i64, true, false, f64);
416impl_promotion_complex_primitive_cast_self!(f64, isize, true, false, f64);
417impl_promotion_complex_primitive_cast_self!(f64, u8, true, false, f64);
418impl_promotion_complex_primitive_cast_self!(f64, u16, true, false, f64);
419impl_promotion_complex_primitive_cast_self!(f64, u32, true, false, f64);
420impl_promotion_complex_primitive_cast_self!(f64, u64, true, false, f64);
421impl_promotion_complex_primitive_cast_self!(f64, usize, true, false, f64);
422impl_promotion_complex_primitive_cast_self!(f64, f32, true, false, f64);
423impl_promotion_complex_primitive_cast_self!(f64, f64, true, false, f64);
424
425impl_promotion_complex_primitive_no_cast_self!(f32, i32, false, false, f64);
426impl_promotion_complex_primitive_no_cast_self!(f32, i64, false, false, f64);
427impl_promotion_complex_primitive_no_cast_self!(f32, isize, false, false, f64);
428impl_promotion_complex_primitive_no_cast_self!(f32, u32, false, false, f64);
429impl_promotion_complex_primitive_no_cast_self!(f32, u64, false, false, f64);
430impl_promotion_complex_primitive_no_cast_self!(f32, usize, false, false, f64);
431impl_promotion_complex_primitive_no_cast_self!(f32, f64, false, false, f64);
432
433/* #endregion */
434
435/* #region primitive to complex */
436
437macro_rules! impl_promotion_primitive_complex_cast_other {
438    ($TComp:ty, $TPrim:ty, $can_cast_self:ident, $can_cast_other:ident, $ResComp:ty) => {
439        impl DTypePromoteAPI<Complex<$TComp>> for $TPrim {
440            type Res = Complex<$ResComp>;
441            const CAN_CAST_SELF: bool = $can_cast_self;
442            const CAN_CAST_OTHER: bool = $can_cast_other;
443            #[inline]
444            fn promote_self(self) -> Self::Res {
445                Self::Res::new(self as _, 0 as _)
446            }
447            #[inline]
448            fn promote_other(val: Complex<$TComp>) -> Self::Res {
449                val
450            }
451        }
452
453        impl DTypeCastAPI<Complex<$TComp>> for $TPrim {
454            #[inline]
455            fn into_cast(self) -> Complex<$TComp> {
456                Complex::<$TComp>::new(self as _, 0 as _)
457            }
458        }
459    };
460}
461
462macro_rules! impl_promotion_primitive_complex_nocast_other {
463    ($TComp:ty, $TPrim:ty, $can_cast_self:ident, $can_cast_other:ident, $ResComp:ty) => {
464        impl DTypePromoteAPI<Complex<$TComp>> for $TPrim {
465            type Res = Complex<$ResComp>;
466            const CAN_CAST_SELF: bool = $can_cast_self;
467            const CAN_CAST_OTHER: bool = $can_cast_other;
468            #[inline]
469            fn promote_self(self) -> Self::Res {
470                Self::Res::new(self as _, 0 as _)
471            }
472            #[inline]
473            fn promote_other(val: Complex<$TComp>) -> Self::Res {
474                Self::Res::new(val.re as _, val.im as _)
475            }
476        }
477
478        impl DTypeCastAPI<Complex<$TComp>> for $TPrim {
479            #[inline]
480            fn into_cast(self) -> Complex<$TComp> {
481                Complex::<$TComp>::new(self as _, 0 as _)
482            }
483        }
484    };
485}
486
487impl_promotion_primitive_complex_cast_other!(f32, i8, false, true, f32);
488impl_promotion_primitive_complex_cast_other!(f32, i16, false, true, f32);
489impl_promotion_primitive_complex_cast_other!(f32, u8, false, true, f32);
490impl_promotion_primitive_complex_cast_other!(f32, u16, false, true, f32);
491impl_promotion_primitive_complex_cast_other!(f32, f32, false, true, f32);
492
493impl_promotion_primitive_complex_nocast_other!(f64, i8, false, true, f64);
494impl_promotion_primitive_complex_nocast_other!(f64, i16, false, true, f64);
495impl_promotion_primitive_complex_nocast_other!(f64, i32, false, true, f64);
496impl_promotion_primitive_complex_nocast_other!(f64, i64, false, true, f64);
497impl_promotion_primitive_complex_nocast_other!(f64, isize, false, true, f64);
498impl_promotion_primitive_complex_nocast_other!(f64, u8, false, true, f64);
499impl_promotion_primitive_complex_nocast_other!(f64, u16, false, true, f64);
500impl_promotion_primitive_complex_nocast_other!(f64, u32, false, true, f64);
501impl_promotion_primitive_complex_nocast_other!(f64, u64, false, true, f64);
502impl_promotion_primitive_complex_nocast_other!(f64, usize, false, true, f64);
503impl_promotion_primitive_complex_nocast_other!(f64, f32, false, true, f64);
504impl_promotion_primitive_complex_nocast_other!(f64, f64, false, true, f64);
505
506impl_promotion_primitive_complex_nocast_other!(f32, i32, false, false, f64);
507impl_promotion_primitive_complex_nocast_other!(f32, i64, false, false, f64);
508impl_promotion_primitive_complex_nocast_other!(f32, isize, false, false, f64);
509impl_promotion_primitive_complex_nocast_other!(f32, u32, false, false, f64);
510impl_promotion_primitive_complex_nocast_other!(f32, u64, false, false, f64);
511impl_promotion_primitive_complex_nocast_other!(f32, usize, false, false, f64);
512impl_promotion_primitive_complex_nocast_other!(f32, f64, false, false, f64);
513
514/* #endregion */
515
516/* #region complex to complex */
517
518impl DTypePromoteAPI<c32> for c64 {
519    type Res = c64;
520    const CAN_CAST_SELF: bool = true;
521    const CAN_CAST_OTHER: bool = false;
522    #[inline]
523    fn promote_self(self) -> Self::Res {
524        self
525    }
526    #[inline]
527    fn promote_other(val: c32) -> Self::Res {
528        c64::new(val.re as f64, val.im as f64)
529    }
530}
531
532impl DTypePromoteAPI<c64> for c32 {
533    type Res = c64;
534    const CAN_CAST_SELF: bool = false;
535    const CAN_CAST_OTHER: bool = true;
536    #[inline]
537    fn promote_self(self) -> Self::Res {
538        c64::new(self.re as f64, self.im as f64)
539    }
540    #[inline]
541    fn promote_other(val: c64) -> Self::Res {
542        val
543    }
544}
545
546impl DTypeCastAPI<c32> for c64 {
547    #[inline]
548    fn into_cast(self) -> c32 {
549        c32::new(self.re as f32, self.im as f32)
550    }
551}
552
553impl DTypeCastAPI<c64> for c32 {
554    #[inline]
555    fn into_cast(self) -> c64 {
556        c64::new(self.re as f64, self.im as f64)
557    }
558}
559
560/* #endregion */