polars_core/chunked_array/logical/
mod.rs

1#[cfg(feature = "dtype-date")]
2mod date;
3#[cfg(feature = "dtype-date")]
4pub use date::*;
5#[cfg(feature = "dtype-datetime")]
6mod datetime;
7#[cfg(feature = "dtype-datetime")]
8pub use datetime::*;
9#[cfg(feature = "dtype-decimal")]
10mod decimal;
11#[cfg(feature = "dtype-decimal")]
12pub use decimal::*;
13#[cfg(feature = "dtype-duration")]
14mod duration;
15#[cfg(feature = "dtype-duration")]
16pub use duration::*;
17#[cfg(feature = "dtype-categorical")]
18pub mod categorical;
19#[cfg(feature = "dtype-categorical")]
20pub mod enum_;
21#[cfg(feature = "dtype-time")]
22mod time;
23
24use std::marker::PhantomData;
25use std::ops::{Deref, DerefMut};
26
27#[cfg(feature = "dtype-categorical")]
28pub use categorical::*;
29#[cfg(feature = "dtype-time")]
30pub use time::*;
31
32use crate::chunked_array::cast::CastOptions;
33use crate::prelude::*;
34
35/// Maps a logical type to a chunked array implementation of the physical type.
36/// This saves a lot of compiler bloat and allows us to reuse functionality.
37pub struct Logical<Logical: PolarsDataType, Physical: PolarsDataType> {
38    pub phys: ChunkedArray<Physical>,
39    pub dtype: Option<DataType>,
40    _phantom: PhantomData<Logical>,
41}
42
43impl<K: PolarsDataType, T: PolarsDataType> Default for Logical<K, T> {
44    fn default() -> Self {
45        Self {
46            phys: Default::default(),
47            _phantom: Default::default(),
48            dtype: Default::default(),
49        }
50    }
51}
52
53impl<K: PolarsDataType, T: PolarsDataType> Clone for Logical<K, T> {
54    fn clone(&self) -> Self {
55        let mut new = Logical::<K, _>::new_logical(self.phys.clone());
56        new.dtype.clone_from(&self.dtype);
57        new
58    }
59}
60
61impl<K: PolarsDataType, T: PolarsDataType> Deref for Logical<K, T> {
62    type Target = ChunkedArray<T>;
63
64    fn deref(&self) -> &Self::Target {
65        &self.phys
66    }
67}
68
69impl<K: PolarsDataType, T: PolarsDataType> DerefMut for Logical<K, T> {
70    fn deref_mut(&mut self) -> &mut Self::Target {
71        &mut self.phys
72    }
73}
74
75impl<K: PolarsDataType, T: PolarsDataType> Logical<K, T> {
76    pub fn new_logical<J: PolarsDataType>(ca: ChunkedArray<T>) -> Logical<J, T> {
77        Logical {
78            phys: ca,
79            _phantom: PhantomData,
80            dtype: None,
81        }
82    }
83}
84
85pub trait LogicalType {
86    /// Get data type of [`ChunkedArray`].
87    fn dtype(&self) -> &DataType;
88
89    /// Gets [`AnyValue`] from [`LogicalType`]
90    fn get_any_value(&self, _i: usize) -> PolarsResult<AnyValue<'_>> {
91        unimplemented!()
92    }
93
94    /// # Safety
95    /// Does not do any bound checks.
96    unsafe fn get_any_value_unchecked(&self, _i: usize) -> AnyValue<'_> {
97        unimplemented!()
98    }
99
100    fn cast_with_options(&self, dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
101
102    fn cast(&self, dtype: &DataType) -> PolarsResult<Series> {
103        self.cast_with_options(dtype, CastOptions::NonStrict)
104    }
105}
106
107impl<K: PolarsDataType, T: PolarsDataType> Logical<K, T>
108where
109    Self: LogicalType,
110{
111    pub fn physical(&self) -> &ChunkedArray<T> {
112        &self.phys
113    }
114    pub fn field(&self) -> Field {
115        let name = self.phys.ref_field().name();
116        Field::new(name.clone(), LogicalType::dtype(self).clone())
117    }
118}