tea_dtype/
cast.rs

1use crate::*;
2/// A trait for types that can be cast to another type.
3///
4/// This trait provides a method to convert a value of one type into a value of another type.
5/// The conversion is typically lossless, but this is not guaranteed for all implementations.
6pub trait Cast<T> {
7    /// Casts the value to the target type `T`.
8    ///
9    /// # Returns
10    ///
11    /// Returns the value cast to type `T`.
12    ///
13    /// # Examples
14    ///
15    /// ```
16    /// use tea_dtype::Cast;
17    ///
18    /// let x: i32 = 42;
19    /// let y: f64 = x.cast();
20    /// assert_eq!(y, 42.0);
21    /// ```
22    fn cast(self) -> T;
23}
24
25impl<T: IsNone> Cast<Option<T>> for T {
26    #[inline]
27    fn cast(self) -> Option<T> {
28        if self.is_none() {
29            None
30        } else {
31            Some(self)
32        }
33    }
34}
35
36impl<T> Cast<T> for T {
37    #[inline(always)]
38    fn cast(self) -> T {
39        self
40    }
41}
42
43macro_rules! impl_numeric_cast {
44    (@ $T: ty => impl $U: ty ) => {
45        impl Cast<$U> for $T {
46            #[inline] fn cast(self) -> $U { self as $U }
47        }
48
49        impl Cast<Option<$U>> for $T {
50            #[inline] fn cast(self) -> Option<$U> {
51                if self.is_none() {
52                    None
53                } else {
54                    Some(self as $U)
55                }
56            }
57        }
58
59        impl Cast<Option<$U>> for Option<$T> {
60            #[inline] fn cast(self) -> Option<$U> {
61                self.map(|v| v.cast())
62            }
63        }
64
65        impl Cast<$U> for Option<$T> {
66            #[inline] fn cast(self) -> $U { self.map(|v| v as $U).unwrap_or_else(<$U as IsNone>::none)}
67        }
68    };
69
70    (@ $T: ty => { $( $U: ty ),* } ) => {$(
71        impl_numeric_cast!(@ $T => impl $U);
72    )*};
73
74    (@common_impl $T: ty => { $( $U: ty ),* } ) => {
75
76        // cast for bool type
77        impl Cast<bool> for $T {
78            #[inline] fn cast(self) -> bool {
79                let value = Cast::<i32>::cast(self);
80                if  value == 0_i32 {
81                    false
82                } else if value == 1 {
83                    true
84                } else {
85                    panic!("can not cast {value:?} to bool")
86                }
87            }
88        }
89
90        impl Cast<Option<bool>> for $T {
91            #[inline] fn cast(self) -> Option<bool> {
92                if self.is_none() {
93                    None
94                } else {
95                    Some(self.cast())
96                }
97            }
98        }
99
100        impl Cast<bool> for Option<$T> {
101            #[inline] fn cast(self) -> bool {
102                self.expect("can not cast None to bool").cast()
103            }
104        }
105
106        impl Cast<Option<bool>> for Option<$T> {
107            #[inline] fn cast(self) -> Option<bool> {
108                self.map(|v| v.cast())
109            }
110        }
111
112        impl Cast<$T> for bool {
113            #[inline] fn cast(self) -> $T { (self as u8).cast() }
114        }
115
116        impl Cast<Option<$T>> for bool {
117            #[inline] fn cast(self) -> Option<$T> { Some((self as u8).cast()) }
118        }
119
120        impl Cast<$T> for Option<bool> {
121            #[inline] fn cast(self) -> $T {
122                if let Some(v) = self {
123                    v.cast()
124                } else {
125                    <$T as IsNone>::none()
126                }
127             }
128        }
129
130        impl Cast<Option<$T>> for Option<bool> {
131            #[inline] fn cast(self) -> Option<$T> { self.map(Cast::cast) }
132        }
133
134        // cast for string type
135        impl Cast<String> for $T {
136            #[inline] fn cast(self) -> String { self.to_string() }
137        }
138
139        impl Cast<String> for Option<$T> {
140            #[inline] fn cast(self) -> String {
141                self.map(|v| v.to_string()).unwrap_or("None".to_string())
142            }
143        }
144
145        #[cfg(feature="time")]
146        impl<U: TimeUnitTrait> Cast<DateTime<U>> for $T {
147            #[inline] fn cast(self) -> DateTime<U> { Cast::<i64>::cast(self).into() }
148        }
149
150        #[cfg(feature="time")]
151        impl Cast<TimeDelta> for $T {
152            #[inline] fn cast(self) -> TimeDelta { Cast::<i64>::cast(self).into() }
153        }
154
155        #[cfg(feature="time")]
156        impl Cast<Time> for $T {
157            #[inline] fn cast(self) -> Time { Cast::<i64>::cast(self).into() }
158        }
159
160
161        #[cfg(feature="time")]
162        impl<U: TimeUnitTrait> Cast<DateTime<U>> for Option<$T> {
163            #[inline] fn cast(self) -> DateTime<U> { self.map(|v| v.cast()).unwrap_or(DateTime::nat()) }
164        }
165
166        #[cfg(feature="time")]
167        impl Cast<TimeDelta> for Option<$T> {
168            #[inline] fn cast(self) -> TimeDelta { self.map(|v| v.cast()).unwrap_or(TimeDelta::nat()) }
169        }
170
171        #[cfg(feature="time")]
172        impl Cast<Time> for Option<$T> {
173            #[inline] fn cast(self) -> Time { self.map(|v| v.cast()).unwrap_or(Time::nat()) }
174        }
175    };
176
177    ($T: ty => { $( $U: ty ),* } ) => {
178        impl Cast<$T> for Option<$T> {
179            #[inline(always)]
180            fn cast(self) -> $T {
181                self.unwrap_or_else(<$T as IsNone>::none)
182            }
183        }
184        impl_numeric_cast!(@common_impl $T => { $( $U ),* });
185        impl_numeric_cast!(@ $T => { $( $U),* });
186    };
187
188    (nocommon $T: ty => { $( $U: ty ),* } ) => {
189        impl_numeric_cast!(@ $T => { $( $U),* });
190    };
191}
192
193impl Cast<String> for bool {
194    #[inline]
195    fn cast(self) -> String {
196        self.to_string()
197    }
198}
199
200impl Cast<bool> for Option<bool> {
201    #[inline]
202    fn cast(self) -> bool {
203        if let Some(v) = self {
204            v
205        } else {
206            panic!("Should not cast None to bool")
207        }
208    }
209}
210
211#[cfg(feature = "time")]
212impl<U: TimeUnitTrait> Cast<DateTime<U>> for bool {
213    #[inline]
214    fn cast(self) -> DateTime<U> {
215        panic!("Should not cast bool to datetime")
216    }
217}
218
219#[cfg(feature = "time")]
220impl Cast<TimeDelta> for bool {
221    #[inline]
222    fn cast(self) -> TimeDelta {
223        panic!("Should not cast bool to timedelta")
224    }
225}
226
227#[cfg(feature = "time")]
228impl Cast<Time> for bool {
229    #[inline]
230    fn cast(self) -> Time {
231        panic!("Should not cast bool to time")
232    }
233}
234
235impl Cast<String> for Option<bool> {
236    #[inline]
237    fn cast(self) -> String {
238        format!("{:?}", self)
239    }
240}
241
242#[cfg(feature = "time")]
243impl<U: TimeUnitTrait> Cast<DateTime<U>> for Option<bool> {
244    #[inline]
245    fn cast(self) -> DateTime<U> {
246        panic!("Should not cast option bool to datetime")
247    }
248}
249
250#[cfg(feature = "time")]
251impl Cast<TimeDelta> for Option<bool> {
252    #[inline]
253    fn cast(self) -> TimeDelta {
254        panic!("Should not cast option bool to timedelta")
255    }
256}
257
258#[cfg(feature = "time")]
259impl Cast<Time> for Option<bool> {
260    #[inline]
261    fn cast(self) -> Time {
262        panic!("Should not cast option bool to time")
263    }
264}
265
266#[cfg(feature = "time")]
267macro_rules! impl_time_cast {
268    ($($T: ty),*) => {
269        $(
270            impl<U: TimeUnitTrait> Cast<$T> for DateTime<U> {
271                #[inline] fn cast(self) -> $T { Cast::<i64>::cast(self).cast() }
272            }
273
274            impl<U: TimeUnitTrait> Cast<Option<$T>> for DateTime<U> {
275                #[inline] fn cast(self) -> Option<$T> {
276                    if self.is_none() {
277                        None
278                    } else {
279                        Some(self.cast())
280                    }
281                 }
282            }
283
284
285            impl Cast<$T> for TimeDelta {
286                #[inline] fn cast(self) -> $T { Cast::<i64>::cast(self).cast() }
287            }
288
289            impl Cast<Option<$T>> for TimeDelta {
290                #[inline] fn cast(self) -> Option<$T> {
291                    if self.is_none() {
292                        None
293                    } else {
294                        Some(self.cast())
295                    }
296                 }
297            }
298
299            impl Cast<$T> for Time {
300                #[inline] fn cast(self) -> $T { Cast::<i64>::cast(self).cast() }
301            }
302
303            impl Cast<Option<$T>> for Time {
304                #[inline] fn cast(self) -> Option<$T> {
305                    if self.is_none() {
306                        None
307                    } else {
308                        Some(self.cast())
309                    }
310                 }
311            }
312        )*
313    };
314}
315
316#[cfg(feature = "time")]
317impl<U: TimeUnitTrait> Cast<i64> for DateTime<U> {
318    #[inline(always)]
319    fn cast(self) -> i64 {
320        self.into_i64()
321    }
322}
323
324#[cfg(feature = "time")]
325impl<U: TimeUnitTrait> Cast<Option<i64>> for DateTime<U> {
326    #[inline(always)]
327    fn cast(self) -> Option<i64> {
328        self.into_opt_i64()
329    }
330}
331
332#[cfg(feature = "time")]
333impl Cast<i64> for TimeDelta {
334    #[inline]
335    fn cast(self) -> i64 {
336        let months = self.months;
337        if months != 0 {
338            panic!("not support cast TimeDelta to i64 when months is not zero")
339        } else {
340            self.inner.num_microseconds().unwrap_or(i64::MIN)
341        }
342    }
343}
344
345#[cfg(feature = "time")]
346impl Cast<Option<i64>> for TimeDelta {
347    #[inline]
348    fn cast(self) -> Option<i64> {
349        let months = self.months;
350        if months != 0 {
351            panic!("not support cast TimeDelta to i64 when months is not zero")
352        } else {
353            self.inner.num_microseconds().map(Some).unwrap_or(None)
354        }
355    }
356}
357
358#[cfg(feature = "time")]
359impl Cast<i64> for Time {
360    #[inline]
361    fn cast(self) -> i64 {
362        self.0
363    }
364}
365
366#[cfg(feature = "time")]
367impl Cast<Option<i64>> for Time {
368    #[inline]
369    fn cast(self) -> Option<i64> {
370        if self.is_none() {
371            None
372        } else {
373            Some(self.0)
374        }
375    }
376}
377
378impl_numeric_cast!(u8 => { u64, f32, f64, i32, i64, usize, isize });
379impl_numeric_cast!(u64 => { u8, f32, f64, i32, i64, usize, isize });
380impl_numeric_cast!(i64 => { u8, f32, f64, i32, u64, usize, isize });
381impl_numeric_cast!(i32 => { u8, f32, f64, i64, u64, usize, isize });
382impl_numeric_cast!(f32 => { u8, f64, i32, i64, u64, usize, isize  });
383impl_numeric_cast!(f64 => { u8, f32, i32, i64, u64, usize, isize  });
384impl_numeric_cast!(usize => { u8, f32, f64, i32, i64, u64, isize });
385impl_numeric_cast!(isize => { u8, f32, f64, i32, i64, u64, usize });
386// impl_numeric_cast!(char => { char });
387// impl_numeric_cast!(nocommon bool => {u8, i32, i64, u64, usize, isize});
388
389#[cfg(feature = "time")]
390impl_time_cast!(u8, u64, f32, f64, i32, usize, isize, bool);
391
392macro_rules! impl_cast_from_string {
393    ($($T: ty),*) => {
394        $(
395            impl Cast<$T> for String {
396                #[inline] fn cast(self) -> $T { self.parse().expect("Parse string error") }
397            }
398
399            impl Cast<$T> for &str {
400                #[inline] fn cast(self) -> $T { self.parse().expect("Parse string error") }
401            }
402
403            impl Cast<Option<$T>> for String {
404                #[inline]
405                fn cast(self) -> Option<$T> {
406                    if self == "None" {
407                        None
408                    } else {
409                        Some(self.cast())
410                    }
411                }
412            }
413
414            impl Cast<Option<$T>> for &str {
415                #[inline]
416                fn cast(self) -> Option<$T> {
417                    if self == "None" {
418                        None
419                    } else {
420                        Some(self.cast())
421                    }
422                }
423            }
424        )*
425    };
426}
427
428impl_cast_from_string!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64, char, bool);
429
430impl Cast<String> for &str {
431    #[inline]
432    fn cast(self) -> String {
433        self.to_string()
434    }
435}
436
437#[cfg(feature = "time")]
438impl<U: TimeUnitTrait> Cast<String> for DateTime<U>
439where
440    CrDateTime<Utc>: From<DateTime<U>>,
441{
442    fn cast(self) -> String {
443        format!("{:?}", self)
444    }
445}
446
447#[cfg(feature = "time")]
448impl<U: TimeUnitTrait> Cast<DateTime<U>> for String
449where
450    DateTime<U>: From<CrDateTime<Utc>>,
451{
452    #[inline]
453    fn cast(self) -> DateTime<U> {
454        self.parse().expect("Parse string to datetime error")
455    }
456}
457
458#[cfg(feature = "time")]
459impl<U: TimeUnitTrait> Cast<DateTime<U>> for &str
460where
461    DateTime<U>: From<CrDateTime<Utc>>,
462{
463    #[inline]
464    fn cast(self) -> DateTime<U> {
465        self.parse().expect("Parse str to datetime error")
466    }
467}
468
469#[cfg(feature = "time")]
470impl Cast<String> for TimeDelta {
471    #[inline]
472    fn cast(self) -> String {
473        format!("{:?}", self)
474    }
475}
476
477#[cfg(feature = "time")]
478impl<U: TimeUnitTrait> Cast<TimeDelta> for DateTime<U> {
479    #[inline(always)]
480    fn cast(self) -> TimeDelta {
481        unreachable!()
482    }
483}
484
485#[cfg(feature = "time")]
486impl<U: TimeUnitTrait> Cast<DateTime<U>> for TimeDelta {
487    #[inline(always)]
488    fn cast(self) -> DateTime<U> {
489        unreachable!()
490    }
491}
492
493#[cfg(feature = "time")]
494impl Cast<TimeDelta> for &str {
495    #[inline(always)]
496    fn cast(self) -> TimeDelta {
497        TimeDelta::parse(self).expect("Parse str to timedelta error")
498    }
499}
500
501#[cfg(feature = "time")]
502impl Cast<TimeDelta> for String {
503    #[inline(always)]
504    fn cast(self) -> TimeDelta {
505        TimeDelta::parse(&self).expect("Parse string to timedelta error")
506    }
507}
508
509#[cfg(feature = "time")]
510// TODO: maybe we can remove default Cast<Self>?
511// we can impl Cast<U: TimeUnitTrait> for DateTime<U> once we
512// remove default implemention for Cast<Self>
513macro_rules! time_unit_cast {
514    ($($unit: ident => ($($to_unit: ident),*)),*) => {
515        $($(impl Cast<DateTime<unit::$to_unit>> for DateTime<unit::$unit> {
516            #[inline(always)]
517            fn cast(self) -> DateTime<unit::$to_unit> {
518                self.into_unit::<unit::$to_unit>()
519            }
520        })*)*
521    // ($($unit: ident),*) => {
522    //     $(impl<U: TimeUnitTrait> Cast<DateTime<U>> for DateTime<unit::$unit> {
523    //         #[inline(always)]
524    //         fn cast(self) -> DateTime<U> {
525    //             self.into_unit::<U>()
526    //         }
527    //     })*
528    };
529}
530
531#[cfg(feature = "time")]
532// time_unit_cast!(Millisecond, Microsecond, Second, Nanosecond);
533time_unit_cast!(
534    Millisecond => (Microsecond, Second, Nanosecond),
535    Microsecond => (Millisecond, Second, Nanosecond),
536    Second => (Millisecond, Microsecond, Nanosecond),
537    Nanosecond => (Millisecond, Microsecond, Second)
538);
539
540#[cfg(test)]
541mod tests {
542    use super::*;
543    #[test]
544    fn test_option_cast() {
545        let a = Some(1_usize);
546        let a: i32 = a.cast();
547        assert_eq!(a, 1);
548
549        let b: Option<usize> = None;
550        let b: f64 = b.cast();
551        assert!(b.is_nan());
552
553        let c: Option<usize> = Some(3);
554        let c: usize = c.cast();
555        assert_eq!(c, 3);
556
557        let d = Some(1usize);
558        let d: bool = d.cast();
559        assert!(d);
560
561        let e = Some(2i32);
562        let e: Option<f64> = e.cast();
563        assert_eq!(e, Some(2.0));
564    }
565}