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-categorical")]
6pub mod categorical;
7#[cfg(feature = "dtype-categorical")]
8pub use categorical::*;
9#[cfg(feature = "dtype-datetime")]
10mod datetime;
11#[cfg(feature = "dtype-datetime")]
12pub use datetime::*;
13#[cfg(feature = "dtype-decimal")]
14mod decimal;
15#[cfg(feature = "dtype-decimal")]
16pub use decimal::*;
17#[cfg(feature = "dtype-duration")]
18mod duration;
19#[cfg(feature = "dtype-duration")]
20pub use duration::*;
21#[cfg(feature = "dtype-extension")]
22mod extension;
23#[cfg(feature = "dtype-extension")]
24pub use extension::*;
25#[cfg(feature = "dtype-time")]
26mod time;
27use std::marker::PhantomData;
28
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: DataType,
40    _phantom: PhantomData<Logical>,
41}
42
43impl<K: PolarsDataType, T: PolarsDataType> Clone for Logical<K, T> {
44    fn clone(&self) -> Self {
45        Self {
46            phys: self.phys.clone(),
47            dtype: self.dtype.clone(),
48            _phantom: PhantomData,
49        }
50    }
51}
52
53impl<K: PolarsDataType, T: PolarsDataType> Logical<K, T> {
54    /// # Safety
55    /// You must uphold the logical types' invariants.
56    pub unsafe fn new_logical(phys: ChunkedArray<T>, dtype: DataType) -> Logical<K, T> {
57        Logical {
58            phys,
59            dtype,
60            _phantom: PhantomData,
61        }
62    }
63}
64
65pub trait LogicalType {
66    /// Get data type of [`ChunkedArray`].
67    fn dtype(&self) -> &DataType;
68
69    /// Gets [`AnyValue`] from [`LogicalType`]
70    fn get_any_value(&self, _i: usize) -> PolarsResult<AnyValue<'_>> {
71        unimplemented!()
72    }
73
74    /// # Safety
75    /// Does not do any bound checks.
76    unsafe fn get_any_value_unchecked(&self, _i: usize) -> AnyValue<'_> {
77        unimplemented!()
78    }
79
80    fn cast_with_options(&self, dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
81
82    fn cast(&self, dtype: &DataType) -> PolarsResult<Series> {
83        self.cast_with_options(dtype, CastOptions::NonStrict)
84    }
85}
86
87impl<K: PolarsDataType, T: PolarsDataType> Logical<K, T>
88where
89    Self: LogicalType,
90{
91    #[inline(always)]
92    pub fn name(&self) -> &PlSmallStr {
93        self.phys.name()
94    }
95
96    #[inline(always)]
97    pub fn rename(&mut self, name: PlSmallStr) {
98        self.phys.rename(name)
99    }
100
101    #[inline(always)]
102    pub fn len(&self) -> usize {
103        self.phys.len()
104    }
105
106    #[inline(always)]
107    pub fn is_empty(&self) -> bool {
108        self.len() == 0
109    }
110
111    #[inline(always)]
112    pub fn null_count(&self) -> usize {
113        self.phys.null_count()
114    }
115
116    #[inline(always)]
117    pub fn has_nulls(&self) -> bool {
118        self.phys.has_nulls()
119    }
120
121    #[inline(always)]
122    pub fn is_null(&self) -> BooleanChunked {
123        self.phys.is_null()
124    }
125
126    #[inline(always)]
127    pub fn is_not_null(&self) -> BooleanChunked {
128        self.phys.is_not_null()
129    }
130
131    #[inline(always)]
132    pub fn split_at(&self, offset: i64) -> (Self, Self) {
133        let (left, right) = self.phys.split_at(offset);
134        unsafe {
135            (
136                Self::new_logical(left, self.dtype.clone()),
137                Self::new_logical(right, self.dtype.clone()),
138            )
139        }
140    }
141
142    #[inline(always)]
143    pub fn slice(&self, offset: i64, length: usize) -> Self {
144        unsafe { Self::new_logical(self.phys.slice(offset, length), self.dtype.clone()) }
145    }
146
147    #[inline(always)]
148    pub fn field(&self) -> Field {
149        let name = self.phys.ref_field().name();
150        Field::new(name.clone(), LogicalType::dtype(self).clone())
151    }
152
153    #[inline(always)]
154    pub fn physical(&self) -> &ChunkedArray<T> {
155        &self.phys
156    }
157
158    #[inline(always)]
159    pub fn physical_mut(&mut self) -> &mut ChunkedArray<T> {
160        &mut self.phys
161    }
162
163    #[inline(always)]
164    pub fn into_physical(self) -> ChunkedArray<T> {
165        self.phys
166    }
167}