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