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    #[inline]
61    pub unsafe fn new_logical(phys: ChunkedArray<T>, dtype: DataType) -> Logical<K, T> {
62        Logical {
63            phys,
64            dtype,
65            _phantom: PhantomData,
66        }
67    }
68}
69
70pub trait LogicalType {
71    /// Get data type of [`ChunkedArray`].
72    fn dtype(&self) -> &DataType;
73
74    /// Gets [`AnyValue`] from [`LogicalType`]
75    fn get_any_value(&self, _i: usize) -> PolarsResult<AnyValue<'_>> {
76        unimplemented!()
77    }
78
79    /// # Safety
80    /// Does not do any bound checks.
81    unsafe fn get_any_value_unchecked(&self, _i: usize) -> AnyValue<'_> {
82        unimplemented!()
83    }
84
85    fn cast_with_options(&self, dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
86
87    fn cast(&self, dtype: &DataType) -> PolarsResult<Series> {
88        self.cast_with_options(dtype, CastOptions::NonStrict)
89    }
90}
91
92impl<K: PolarsDataType, T: PolarsDataType> Logical<K, T>
93where
94    Self: LogicalType,
95{
96    #[inline(always)]
97    pub fn name(&self) -> &PlSmallStr {
98        self.phys.name()
99    }
100
101    #[inline(always)]
102    pub fn rename(&mut self, name: PlSmallStr) {
103        self.phys.rename(name)
104    }
105
106    #[inline(always)]
107    pub fn len(&self) -> usize {
108        self.phys.len()
109    }
110
111    #[inline(always)]
112    pub fn is_empty(&self) -> bool {
113        self.len() == 0
114    }
115
116    #[inline(always)]
117    pub fn null_count(&self) -> usize {
118        self.phys.null_count()
119    }
120
121    #[inline(always)]
122    pub fn has_nulls(&self) -> bool {
123        self.phys.has_nulls()
124    }
125
126    #[inline(always)]
127    pub fn is_null(&self) -> BooleanChunked {
128        self.phys.is_null()
129    }
130
131    #[inline(always)]
132    pub fn is_not_null(&self) -> BooleanChunked {
133        self.phys.is_not_null()
134    }
135
136    #[inline(always)]
137    pub fn split_at(&self, offset: i64) -> (Self, Self) {
138        let (left, right) = self.phys.split_at(offset);
139        unsafe {
140            (
141                Self::new_logical(left, self.dtype.clone()),
142                Self::new_logical(right, self.dtype.clone()),
143            )
144        }
145    }
146
147    #[inline(always)]
148    pub fn slice(&self, offset: i64, length: usize) -> Self {
149        unsafe { Self::new_logical(self.phys.slice(offset, length), self.dtype.clone()) }
150    }
151
152    #[inline(always)]
153    pub fn field(&self) -> Field {
154        let name = self.phys.ref_field().name();
155        Field::new(name.clone(), LogicalType::dtype(self).clone())
156    }
157
158    #[inline(always)]
159    pub fn physical(&self) -> &ChunkedArray<T> {
160        &self.phys
161    }
162
163    #[inline(always)]
164    pub fn physical_mut(&mut self) -> &mut ChunkedArray<T> {
165        &mut self.phys
166    }
167
168    #[inline(always)]
169    pub fn into_physical(self) -> ChunkedArray<T> {
170        self.phys
171    }
172}