polars_core/series/implementations/
time.rs

1//! This module exists to reduce compilation times.
2//!
3//! All the data types are backed by a physical type in memory e.g. Date -> i32, Datetime-> i64.
4//!
5//! Series lead to code implementations of all traits. Whereas there are a lot of duplicates due to
6//! data types being backed by the same physical type. In this module we reduce compile times by
7//! opting for a little more run time cost. We cast to the physical type -> apply the operation and
8//! (depending on the result) cast back to the original type
9//!
10use super::*;
11#[cfg(feature = "algorithm_group_by")]
12use crate::frame::group_by::*;
13use crate::prelude::*;
14
15unsafe impl IntoSeries for TimeChunked {
16    fn into_series(self) -> Series {
17        Series(Arc::new(SeriesWrap(self)))
18    }
19}
20
21impl private::PrivateSeries for SeriesWrap<TimeChunked> {
22    fn compute_len(&mut self) {
23        self.0.compute_len()
24    }
25
26    fn _field(&self) -> Cow<Field> {
27        Cow::Owned(self.0.field())
28    }
29
30    fn _dtype(&self) -> &DataType {
31        self.0.dtype()
32    }
33
34    fn _get_flags(&self) -> StatisticsFlags {
35        self.0.get_flags()
36    }
37
38    fn _set_flags(&mut self, flags: StatisticsFlags) {
39        self.0.set_flags(flags)
40    }
41
42    #[cfg(feature = "zip_with")]
43    fn zip_with_same_type(&self, mask: &BooleanChunked, other: &Series) -> PolarsResult<Series> {
44        let other = other.to_physical_repr().into_owned();
45        self.0
46            .zip_with(mask, other.as_ref().as_ref())
47            .map(|ca| ca.into_time().into_series())
48    }
49
50    fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a> {
51        self.0.physical().into_total_eq_inner()
52    }
53    fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {
54        self.0.physical().into_total_ord_inner()
55    }
56
57    fn vec_hash(&self, random_state: PlRandomState, buf: &mut Vec<u64>) -> PolarsResult<()> {
58        self.0.vec_hash(random_state, buf)?;
59        Ok(())
60    }
61
62    fn vec_hash_combine(
63        &self,
64        build_hasher: PlRandomState,
65        hashes: &mut [u64],
66    ) -> PolarsResult<()> {
67        self.0.vec_hash_combine(build_hasher, hashes)?;
68        Ok(())
69    }
70
71    #[cfg(feature = "algorithm_group_by")]
72    unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
73        self.0.agg_min(groups).into_time().into_series()
74    }
75
76    #[cfg(feature = "algorithm_group_by")]
77    unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
78        self.0.agg_max(groups).into_time().into_series()
79    }
80
81    #[cfg(feature = "algorithm_group_by")]
82    unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
83        // we cannot cast and dispatch as the inner type of the list would be incorrect
84        self.0
85            .agg_list(groups)
86            .cast(&DataType::List(Box::new(self.dtype().clone())))
87            .unwrap()
88    }
89
90    fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {
91        let rhs = rhs.time().map_err(|_| polars_err!(InvalidOperation: "cannot subtract a {} dtype with a series of type: {}", self.dtype(), rhs.dtype()))?;
92
93        let phys = self
94            .0
95            .physical()
96            .subtract(&rhs.physical().clone().into_series())?;
97
98        Ok(phys.into_duration(TimeUnit::Nanoseconds))
99    }
100
101    fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {
102        polars_bail!(opq = add, DataType::Time, rhs.dtype());
103    }
104
105    fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {
106        polars_bail!(opq = mul, self.0.dtype(), rhs.dtype());
107    }
108
109    fn divide(&self, rhs: &Series) -> PolarsResult<Series> {
110        polars_bail!(opq = div, self.0.dtype(), rhs.dtype());
111    }
112
113    fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {
114        polars_bail!(opq = rem, self.0.dtype(), rhs.dtype());
115    }
116
117    #[cfg(feature = "algorithm_group_by")]
118    fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
119        self.0.group_tuples(multithreaded, sorted)
120    }
121
122    fn arg_sort_multiple(
123        &self,
124        by: &[Column],
125        options: &SortMultipleOptions,
126    ) -> PolarsResult<IdxCa> {
127        self.0.deref().arg_sort_multiple(by, options)
128    }
129}
130
131impl SeriesTrait for SeriesWrap<TimeChunked> {
132    fn rename(&mut self, name: PlSmallStr) {
133        self.0.rename(name);
134    }
135
136    fn chunk_lengths(&self) -> ChunkLenIter {
137        self.0.chunk_lengths()
138    }
139    fn name(&self) -> &PlSmallStr {
140        self.0.name()
141    }
142
143    fn chunks(&self) -> &Vec<ArrayRef> {
144        self.0.chunks()
145    }
146    unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
147        self.0.chunks_mut()
148    }
149
150    fn shrink_to_fit(&mut self) {
151        self.0.shrink_to_fit()
152    }
153
154    fn slice(&self, offset: i64, length: usize) -> Series {
155        self.0.slice(offset, length).into_time().into_series()
156    }
157    fn split_at(&self, offset: i64) -> (Series, Series) {
158        let (a, b) = self.0.split_at(offset);
159        (a.into_series(), b.into_series())
160    }
161
162    fn _sum_as_f64(&self) -> f64 {
163        self.0._sum_as_f64()
164    }
165
166    fn mean(&self) -> Option<f64> {
167        self.0.mean()
168    }
169
170    fn median(&self) -> Option<f64> {
171        self.0.median()
172    }
173
174    fn append(&mut self, other: &Series) -> PolarsResult<()> {
175        polars_ensure!(self.0.dtype() == other.dtype(), append);
176        let mut other = other.to_physical_repr().into_owned();
177        self.0
178            .append_owned(std::mem::take(other._get_inner_mut().as_mut()))
179    }
180    fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
181        polars_ensure!(self.0.dtype() == other.dtype(), append);
182        self.0.append_owned(std::mem::take(
183            &mut other
184                ._get_inner_mut()
185                .as_any_mut()
186                .downcast_mut::<TimeChunked>()
187                .unwrap()
188                .0,
189        ))
190    }
191
192    fn extend(&mut self, other: &Series) -> PolarsResult<()> {
193        polars_ensure!(self.0.dtype() == other.dtype(), extend);
194        // 3 refs
195        // ref Cow
196        // ref SeriesTrait
197        // ref ChunkedArray
198        let other = other.to_physical_repr();
199        self.0.extend(other.as_ref().as_ref().as_ref())?;
200        Ok(())
201    }
202
203    fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
204        self.0.filter(filter).map(|ca| ca.into_time().into_series())
205    }
206
207    fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
208        Ok(self.0.take(indices)?.into_time().into_series())
209    }
210
211    unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
212        self.0.take_unchecked(indices).into_time().into_series()
213    }
214
215    fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
216        Ok(self.0.take(indices)?.into_time().into_series())
217    }
218
219    unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
220        self.0.take_unchecked(indices).into_time().into_series()
221    }
222
223    fn len(&self) -> usize {
224        self.0.len()
225    }
226
227    fn rechunk(&self) -> Series {
228        self.0.rechunk().into_time().into_series()
229    }
230
231    fn new_from_index(&self, index: usize, length: usize) -> Series {
232        self.0
233            .new_from_index(index, length)
234            .into_time()
235            .into_series()
236    }
237
238    fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {
239        match dtype {
240            DataType::String => Ok(self
241                .0
242                .clone()
243                .into_series()
244                .time()
245                .unwrap()
246                .to_string("%T")
247                .into_series()),
248            _ => self.0.cast_with_options(dtype, cast_options),
249        }
250    }
251
252    #[inline]
253    unsafe fn get_unchecked(&self, index: usize) -> AnyValue {
254        self.0.get_any_value_unchecked(index)
255    }
256
257    fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
258        Ok(self.0.sort_with(options).into_time().into_series())
259    }
260
261    fn arg_sort(&self, options: SortOptions) -> IdxCa {
262        self.0.arg_sort(options)
263    }
264
265    fn null_count(&self) -> usize {
266        self.0.null_count()
267    }
268
269    fn has_nulls(&self) -> bool {
270        self.0.has_nulls()
271    }
272
273    #[cfg(feature = "algorithm_group_by")]
274    fn unique(&self) -> PolarsResult<Series> {
275        self.0.unique().map(|ca| ca.into_time().into_series())
276    }
277
278    #[cfg(feature = "algorithm_group_by")]
279    fn n_unique(&self) -> PolarsResult<usize> {
280        self.0.n_unique()
281    }
282
283    #[cfg(feature = "algorithm_group_by")]
284    fn arg_unique(&self) -> PolarsResult<IdxCa> {
285        self.0.arg_unique()
286    }
287
288    fn is_null(&self) -> BooleanChunked {
289        self.0.is_null()
290    }
291
292    fn is_not_null(&self) -> BooleanChunked {
293        self.0.is_not_null()
294    }
295
296    fn reverse(&self) -> Series {
297        self.0.reverse().into_time().into_series()
298    }
299
300    fn as_single_ptr(&mut self) -> PolarsResult<usize> {
301        self.0.as_single_ptr()
302    }
303
304    fn shift(&self, periods: i64) -> Series {
305        self.0.shift(periods).into_time().into_series()
306    }
307
308    fn max_reduce(&self) -> PolarsResult<Scalar> {
309        let sc = self.0.max_reduce();
310        let av = sc.value().cast(self.dtype()).into_static();
311        Ok(Scalar::new(self.dtype().clone(), av))
312    }
313
314    fn min_reduce(&self) -> PolarsResult<Scalar> {
315        let sc = self.0.min_reduce();
316        let av = sc.value().cast(self.dtype()).into_static();
317        Ok(Scalar::new(self.dtype().clone(), av))
318    }
319
320    fn median_reduce(&self) -> PolarsResult<Scalar> {
321        let av = AnyValue::from(self.median().map(|v| v as i64))
322            .cast(self.dtype())
323            .into_static();
324        Ok(Scalar::new(self.dtype().clone(), av))
325    }
326
327    fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
328        Arc::new(SeriesWrap(Clone::clone(&self.0)))
329    }
330
331    fn as_any(&self) -> &dyn Any {
332        &self.0
333    }
334
335    fn as_any_mut(&mut self) -> &mut dyn Any {
336        &mut self.0
337    }
338
339    fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
340        self as _
341    }
342}
343
344impl private::PrivateSeriesNumeric for SeriesWrap<TimeChunked> {
345    fn bit_repr(&self) -> Option<BitRepr> {
346        Some(self.0.to_bit_repr())
347    }
348}