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