Skip to main content

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