Skip to main content

polars_core/series/
series_trait.rs

1use std::any::Any;
2use std::borrow::Cow;
3
4use arrow::bitmap::{Bitmap, BitmapBuilder};
5use arrow::compute::utils::combine_validities_and;
6use polars_compute::rolling::QuantileMethod;
7
8use crate::chunked_array::cast::CastOptions;
9#[cfg(feature = "object")]
10use crate::chunked_array::object::PolarsObjectSafe;
11use crate::prelude::*;
12use crate::utils::{first_non_null, last_non_null};
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
15pub enum IsSorted {
16    Ascending,
17    Descending,
18    Not,
19}
20
21impl IsSorted {
22    pub fn reverse(self) -> Self {
23        use IsSorted::*;
24        match self {
25            Ascending => Descending,
26            Descending => Ascending,
27            Not => Not,
28        }
29    }
30}
31
32pub enum BitRepr {
33    U8(UInt8Chunked),
34    U16(UInt16Chunked),
35    U32(UInt32Chunked),
36    U64(UInt64Chunked),
37    #[cfg(feature = "dtype-u128")]
38    U128(UInt128Chunked),
39}
40
41pub(crate) mod private {
42    use polars_utils::aliases::PlSeedableRandomStateQuality;
43
44    use super::*;
45    use crate::chunked_array::flags::StatisticsFlags;
46    use crate::chunked_array::ops::compare_inner::{TotalEqInner, TotalOrdInner};
47
48    pub trait PrivateSeriesNumeric {
49        /// Return a bit representation
50        ///
51        /// If there is no available bit representation this returns `None`.
52        fn bit_repr(&self) -> Option<BitRepr>;
53    }
54
55    pub trait PrivateSeries {
56        #[cfg(feature = "object")]
57        fn get_list_builder(
58            &self,
59            _name: PlSmallStr,
60            _values_capacity: usize,
61            _list_capacity: usize,
62        ) -> Box<dyn ListBuilderTrait> {
63            invalid_operation_panic!(get_list_builder, self)
64        }
65
66        /// Get field (used in schema)
67        fn _field(&self) -> Cow<'_, Field>;
68
69        fn _dtype(&self) -> &DataType;
70
71        fn compute_len(&mut self);
72
73        fn _get_flags(&self) -> StatisticsFlags;
74
75        fn _set_flags(&mut self, flags: StatisticsFlags);
76
77        #[expect(clippy::wrong_self_convention)]
78        fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a>;
79        #[expect(clippy::wrong_self_convention)]
80        fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a>;
81
82        fn vec_hash(
83            &self,
84            _build_hasher: PlSeedableRandomStateQuality,
85            _buf: &mut Vec<u64>,
86        ) -> PolarsResult<()>;
87        fn vec_hash_combine(
88            &self,
89            _build_hasher: PlSeedableRandomStateQuality,
90            _hashes: &mut [u64],
91        ) -> PolarsResult<()>;
92
93        /// # Safety
94        ///
95        /// Does no bounds checks, groups must be correct.
96        #[cfg(feature = "algorithm_group_by")]
97        unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
98            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
99        }
100        /// # Safety
101        ///
102        /// Does no bounds checks, groups must be correct.
103        #[cfg(feature = "algorithm_group_by")]
104        unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
105            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
106        }
107        /// # Safety
108        ///
109        /// Does no bounds checks, groups must be correct.
110        #[cfg(feature = "algorithm_group_by")]
111        unsafe fn agg_arg_min(&self, groups: &GroupsType) -> Series {
112            Series::full_null(self._field().name().clone(), groups.len(), &IDX_DTYPE)
113        }
114
115        /// # Safety
116        ///
117        /// Does no bounds checks, groups must be correct.
118        #[cfg(feature = "algorithm_group_by")]
119        unsafe fn agg_arg_max(&self, groups: &GroupsType) -> Series {
120            Series::full_null(self._field().name().clone(), groups.len(), &IDX_DTYPE)
121        }
122
123        /// If the [`DataType`] is one of `{Int8, UInt8, Int16, UInt16}` the `Series` is
124        /// first cast to `Int64` to prevent overflow issues.
125        #[cfg(feature = "algorithm_group_by")]
126        unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
127            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
128        }
129        /// # Safety
130        ///
131        /// Does no bounds checks, groups must be correct.
132        #[cfg(feature = "algorithm_group_by")]
133        unsafe fn agg_std(&self, groups: &GroupsType, _ddof: u8) -> Series {
134            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
135        }
136        /// # Safety
137        ///
138        /// Does no bounds checks, groups must be correct.
139        #[cfg(feature = "algorithm_group_by")]
140        unsafe fn agg_var(&self, groups: &GroupsType, _ddof: u8) -> Series {
141            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
142        }
143        /// # Safety
144        ///
145        /// Does no bounds checks, groups must be correct.
146        #[cfg(feature = "algorithm_group_by")]
147        unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
148            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
149        }
150
151        /// # Safety
152        ///
153        /// Does no bounds checks, groups must be correct.
154        #[cfg(feature = "bitwise")]
155        unsafe fn agg_and(&self, groups: &GroupsType) -> Series {
156            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
157        }
158
159        /// # Safety
160        ///
161        /// Does no bounds checks, groups must be correct.
162        #[cfg(feature = "bitwise")]
163        unsafe fn agg_or(&self, groups: &GroupsType) -> Series {
164            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
165        }
166
167        /// # Safety
168        ///
169        /// Does no bounds checks, groups must be correct.
170        #[cfg(feature = "bitwise")]
171        unsafe fn agg_xor(&self, groups: &GroupsType) -> Series {
172            Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
173        }
174
175        fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
176            polars_bail!(opq = subtract, self._dtype());
177        }
178        fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
179            polars_bail!(opq = add, self._dtype());
180        }
181        fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
182            polars_bail!(opq = multiply, self._dtype());
183        }
184        fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
185            polars_bail!(opq = divide, self._dtype());
186        }
187        fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
188            polars_bail!(opq = remainder, self._dtype());
189        }
190        #[cfg(feature = "algorithm_group_by")]
191        fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsType> {
192            polars_bail!(opq = group_tuples, self._dtype());
193        }
194        #[cfg(feature = "zip_with")]
195        fn zip_with_same_type(
196            &self,
197            _mask: &BooleanChunked,
198            _other: &Series,
199        ) -> PolarsResult<Series> {
200            polars_bail!(opq = zip_with_same_type, self._dtype());
201        }
202
203        #[allow(unused_variables)]
204        fn arg_sort_multiple(
205            &self,
206            by: &[Column],
207            _options: &SortMultipleOptions,
208        ) -> PolarsResult<IdxCa> {
209            polars_bail!(opq = arg_sort_multiple, self._dtype());
210        }
211    }
212}
213
214pub trait SeriesTrait:
215    Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
216{
217    /// Rename the Series.
218    fn rename(&mut self, name: PlSmallStr);
219
220    /// Get the lengths of the underlying chunks
221    fn chunk_lengths(&self) -> ChunkLenIter<'_>;
222
223    /// Name of series.
224    fn name(&self) -> &PlSmallStr;
225
226    /// Get field (used in schema)
227    fn field(&self) -> Cow<'_, Field> {
228        self._field()
229    }
230
231    /// Get datatype of series.
232    fn dtype(&self) -> &DataType {
233        self._dtype()
234    }
235
236    /// Underlying chunks.
237    fn chunks(&self) -> &Vec<ArrayRef>;
238
239    /// Underlying chunks.
240    ///
241    /// # Safety
242    /// The caller must ensure the length and the data types of `ArrayRef` does not change.
243    unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef>;
244
245    /// Number of chunks in this Series
246    fn n_chunks(&self) -> usize {
247        self.chunks().len()
248    }
249
250    /// Shrink the capacity of this array to fit its length.
251    fn shrink_to_fit(&mut self) {
252        // no-op
253    }
254
255    /// Take `num_elements` from the top as a zero copy view.
256    fn limit(&self, num_elements: usize) -> Series {
257        self.slice(0, num_elements)
258    }
259
260    /// Get a zero copy view of the data.
261    ///
262    /// When offset is negative the offset is counted from the
263    /// end of the array
264    fn slice(&self, _offset: i64, _length: usize) -> Series;
265
266    /// Get a zero copy view of the data.
267    ///
268    /// When offset is negative the offset is counted from the
269    /// end of the array
270    fn split_at(&self, _offset: i64) -> (Series, Series);
271
272    fn append(&mut self, other: &Series) -> PolarsResult<()>;
273    fn append_owned(&mut self, other: Series) -> PolarsResult<()>;
274
275    #[doc(hidden)]
276    fn extend(&mut self, _other: &Series) -> PolarsResult<()>;
277
278    /// Filter by boolean mask. This operation clones data.
279    fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series>;
280
281    /// Take from `self` at the indexes given by `idx`.
282    ///
283    /// Null values in `idx` because null values in the output array.
284    ///
285    /// This operation is clone.
286    fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
287
288    /// Take from `self` at the indexes given by `idx`.
289    ///
290    /// Null values in `idx` because null values in the output array.
291    ///
292    /// # Safety
293    /// This doesn't check any bounds.
294    unsafe fn take_unchecked(&self, _idx: &IdxCa) -> Series;
295
296    /// Take from `self` at the indexes given by `idx`.
297    ///
298    /// This operation is clone.
299    fn take_slice(&self, _indices: &[IdxSize]) -> PolarsResult<Series>;
300
301    /// Take from `self` at the indexes given by `idx`.
302    ///
303    /// # Safety
304    /// This doesn't check any bounds.
305    unsafe fn take_slice_unchecked(&self, _idx: &[IdxSize]) -> Series;
306
307    /// Get length of series.
308    fn len(&self) -> usize;
309
310    /// Check if Series is empty.
311    fn is_empty(&self) -> bool {
312        self.len() == 0
313    }
314
315    /// Check if Series only consists of nulls.
316    fn is_full_null(&self) -> bool {
317        self.len() == self.null_count()
318    }
319
320    /// Aggregate all chunks to a contiguous array of memory.
321    fn rechunk(&self) -> Series;
322
323    /// Returns the validity of this series as a single bitmap.
324    fn rechunk_validity(&self) -> Option<Bitmap> {
325        if self.chunks().len() == 1 {
326            return self.chunks()[0].validity().cloned();
327        }
328
329        if !self.has_nulls() || self.is_empty() {
330            return None;
331        }
332
333        let mut bm = BitmapBuilder::with_capacity(self.len());
334        for arr in self.chunks() {
335            if let Some(v) = arr.validity() {
336                bm.extend_from_bitmap(v);
337            } else {
338                bm.extend_constant(arr.len(), true);
339            }
340        }
341        bm.into_opt_validity()
342    }
343
344    /// Sets the validity mask of this Series to the given bitmap.
345    fn with_validity(&self, validity: Option<Bitmap>) -> Series;
346
347    /// Applies the given mask to this Series, returning a new Series. If a
348    /// validity bit is true nothing changes, if it is false the corresponding
349    /// element becomes null.
350    fn mask(&self, validity: &Bitmap) -> Series {
351        if validity.len() == 1 {
352            if validity.get_bit(0) {
353                Series(self.clone_inner())
354            } else {
355                Series::full_null(self._field().name().clone(), self.len(), self._dtype())
356            }
357        } else {
358            self.with_validity(combine_validities_and(
359                self.rechunk_validity().as_ref(),
360                Some(validity),
361            ))
362        }
363    }
364
365    /// Drop all null values and return a new Series.
366    fn drop_nulls(&self) -> Series {
367        if self.null_count() == 0 {
368            Series(self.clone_inner())
369        } else {
370            self.filter(&self.is_not_null()).unwrap()
371        }
372    }
373
374    /// Returns the sum of the array as an f64.
375    fn _sum_as_f64(&self) -> f64 {
376        invalid_operation_panic!(_sum_as_f64, self)
377    }
378
379    /// Returns the mean value in the array
380    /// Returns an option because the array is nullable.
381    fn mean(&self) -> Option<f64> {
382        None
383    }
384
385    /// Returns the std value in the array
386    /// Returns an option because the array is nullable.
387    fn std(&self, _ddof: u8) -> Option<f64> {
388        None
389    }
390
391    /// Returns the var value in the array
392    /// Returns an option because the array is nullable.
393    fn var(&self, _ddof: u8) -> Option<f64> {
394        None
395    }
396
397    /// Returns the median value in the array
398    /// Returns an option because the array is nullable.
399    fn median(&self) -> Option<f64> {
400        None
401    }
402
403    /// Create a new Series filled with values from the given index.
404    ///
405    /// # Example
406    ///
407    /// ```rust
408    /// use polars_core::prelude::*;
409    /// let s = Series::new("a".into(), [0i32, 1, 8]);
410    /// let s2 = s.new_from_index(2, 4);
411    /// assert_eq!(Vec::from(s2.i32().unwrap()), &[Some(8), Some(8), Some(8), Some(8)])
412    /// ```
413    fn new_from_index(&self, _index: usize, _length: usize) -> Series;
414
415    /// Trim all lists of unused start and end elements recursively.
416    ///
417    /// - `None` if nothing needed to be done.
418    /// - `Some(series)` if something changed.
419    fn trim_lists_to_normalized_offsets(&self) -> Option<Series> {
420        None
421    }
422
423    /// Propagate down nulls in nested types.
424    ///
425    /// - `None` if nothing needed to be done.
426    /// - `Some(series)` if something changed.
427    fn propagate_nulls(&self) -> Option<Series> {
428        None
429    }
430
431    fn deposit(&self, validity: &Bitmap) -> Series;
432
433    /// Find the indices of elements where the null masks are different recursively.
434    fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>);
435
436    fn cast(&self, _dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
437
438    /// Get a single value by index. Don't use this operation for loops as a runtime cast is
439    /// needed for every iteration.
440    fn get(&self, index: usize) -> PolarsResult<AnyValue<'_>> {
441        polars_ensure!(index < self.len(), oob = index, self.len());
442        // SAFETY: Just did bounds check
443        let value = unsafe { self.get_unchecked(index) };
444        Ok(value)
445    }
446
447    /// Get a single value by index. Don't use this operation for loops as a runtime cast is
448    /// needed for every iteration.
449    ///
450    /// This may refer to physical types
451    ///
452    /// # Safety
453    /// Does not do any bounds checking
454    unsafe fn get_unchecked(&self, _index: usize) -> AnyValue<'_>;
455
456    fn sort_with(&self, _options: SortOptions) -> PolarsResult<Series> {
457        polars_bail!(opq = sort_with, self._dtype());
458    }
459
460    /// Retrieve the indexes needed for a sort.
461    #[allow(unused)]
462    fn arg_sort(&self, options: SortOptions) -> IdxCa {
463        invalid_operation_panic!(arg_sort, self)
464    }
465
466    /// Count the null values.
467    fn null_count(&self) -> usize;
468
469    /// Return if any the chunks in this [`ChunkedArray`] have nulls.
470    fn has_nulls(&self) -> bool;
471
472    /// Get unique values in the Series.
473    fn unique(&self) -> PolarsResult<Series> {
474        polars_bail!(opq = unique, self._dtype());
475    }
476
477    /// Get unique values in the Series.
478    ///
479    /// A `null` value also counts as a unique value.
480    fn n_unique(&self) -> PolarsResult<usize> {
481        polars_bail!(opq = n_unique, self._dtype());
482    }
483
484    /// Get first indexes of unique values.
485    fn arg_unique(&self) -> PolarsResult<IdxCa> {
486        polars_bail!(opq = arg_unique, self._dtype());
487    }
488
489    /// Get dense ids for each unique value.
490    ///
491    /// Returns: (n_unique, unique_ids)
492    fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)> {
493        polars_bail!(opq = unique_id, self._dtype());
494    }
495
496    /// Get a mask of the null values.
497    fn is_null(&self) -> BooleanChunked;
498
499    /// Get a mask of the non-null values.
500    fn is_not_null(&self) -> BooleanChunked;
501
502    /// return a Series in reversed order
503    fn reverse(&self) -> Series;
504
505    /// Rechunk and return a pointer to the start of the Series.
506    /// Only implemented for numeric types
507    fn as_single_ptr(&mut self) -> PolarsResult<usize> {
508        polars_bail!(opq = as_single_ptr, self._dtype());
509    }
510
511    /// Shift the values by a given period and fill the parts that will be empty due to this operation
512    /// with `Nones`.
513    ///
514    /// *NOTE: If you want to fill the Nones with a value use the
515    /// [`shift` operation on `ChunkedArray<T>`](../chunked_array/ops/trait.ChunkShift.html).*
516    ///
517    /// # Example
518    ///
519    /// ```rust
520    /// # use polars_core::prelude::*;
521    /// fn example() -> PolarsResult<()> {
522    ///     let s = Series::new("series".into(), &[1, 2, 3]);
523    ///
524    ///     let shifted = s.shift(1);
525    ///     assert_eq!(Vec::from(shifted.i32()?), &[None, Some(1), Some(2)]);
526    ///
527    ///     let shifted = s.shift(-1);
528    ///     assert_eq!(Vec::from(shifted.i32()?), &[Some(2), Some(3), None]);
529    ///
530    ///     let shifted = s.shift(2);
531    ///     assert_eq!(Vec::from(shifted.i32()?), &[None, None, Some(1)]);
532    ///
533    ///     Ok(())
534    /// }
535    /// example();
536    /// ```
537    fn shift(&self, _periods: i64) -> Series;
538
539    /// Get the sum of the Series as a new Scalar.
540    ///
541    /// If the [`DataType`] is one of `{Int8, UInt8, Int16, UInt16}` the `Series` is
542    /// first cast to `Int64` to prevent overflow issues.
543    fn sum_reduce(&self) -> PolarsResult<Scalar> {
544        polars_bail!(opq = sum, self._dtype());
545    }
546    /// Get the max of the Series as a new Series of length 1.
547    fn max_reduce(&self) -> PolarsResult<Scalar> {
548        polars_bail!(opq = max, self._dtype());
549    }
550    /// Get the min of the Series as a new Series of length 1.
551    fn min_reduce(&self) -> PolarsResult<Scalar> {
552        polars_bail!(opq = min, self._dtype());
553    }
554    /// Get the median of the Series as a new Series of length 1.
555    fn median_reduce(&self) -> PolarsResult<Scalar> {
556        polars_bail!(opq = median, self._dtype());
557    }
558    /// Get the mean of the Series as a new Scalar
559    fn mean_reduce(&self) -> PolarsResult<Scalar> {
560        polars_bail!(opq = mean, self._dtype());
561    }
562    /// Get the variance of the Series as a new Series of length 1.
563    fn var_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
564        polars_bail!(opq = var, self._dtype());
565    }
566    /// Get the standard deviation of the Series as a new Series of length 1.
567    fn std_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
568        polars_bail!(opq = std, self._dtype());
569    }
570    /// Get the quantile of the Series as a new Series of length 1.
571    fn quantile_reduce(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Scalar> {
572        polars_bail!(opq = quantile, self._dtype());
573    }
574    /// Get multiple quantiles of the ChunkedArray as a new `List` Scalar
575    fn quantiles_reduce(
576        &self,
577        _quantiles: &[f64],
578        _method: QuantileMethod,
579    ) -> PolarsResult<Scalar> {
580        polars_bail!(opq = quantiles, self._dtype());
581    }
582    /// Get the bitwise AND of the Series as a new Series of length 1,
583    fn and_reduce(&self) -> PolarsResult<Scalar> {
584        polars_bail!(opq = and_reduce, self._dtype());
585    }
586    /// Get the bitwise OR of the Series as a new Series of length 1,
587    fn or_reduce(&self) -> PolarsResult<Scalar> {
588        polars_bail!(opq = or_reduce, self._dtype());
589    }
590    /// Get the bitwise XOR of the Series as a new Series of length 1,
591    fn xor_reduce(&self) -> PolarsResult<Scalar> {
592        polars_bail!(opq = xor_reduce, self._dtype());
593    }
594
595    /// Get the first element of the [`Series`] as a [`Scalar`]
596    ///
597    /// If the [`Series`] is empty, a [`Scalar`] with a [`AnyValue::Null`] is returned.
598    fn first(&self) -> Scalar {
599        let dt = self.dtype();
600        let av = self.get(0).map_or(AnyValue::Null, AnyValue::into_static);
601
602        Scalar::new(dt.clone(), av)
603    }
604
605    /// Get the first non-null element of the [`Series`] as a [`Scalar`]
606    ///
607    /// If the [`Series`] is empty, a [`Scalar`] with a [`AnyValue::Null`] is returned.
608    fn first_non_null(&self) -> Scalar {
609        let av = if self.len() == 0 {
610            AnyValue::Null
611        } else {
612            let idx = if self.has_nulls() {
613                first_non_null(self.chunks().iter().map(|c| c.as_ref())).unwrap_or(0)
614            } else {
615                0
616            };
617            self.get(idx).map_or(AnyValue::Null, AnyValue::into_static)
618        };
619        Scalar::new(self.dtype().clone(), av)
620    }
621
622    /// Get the last element of the [`Series`] as a [`Scalar`]
623    ///
624    /// If the [`Series`] is empty, a [`Scalar`] with a [`AnyValue::Null`] is returned.
625    fn last(&self) -> Scalar {
626        let dt = self.dtype();
627        let av = if self.len() == 0 {
628            AnyValue::Null
629        } else {
630            // SAFETY: len-1 < len if len != 0
631            unsafe { self.get_unchecked(self.len() - 1) }.into_static()
632        };
633
634        Scalar::new(dt.clone(), av)
635    }
636
637    /// Get the last non-null element of the [`Series`] as a [`Scalar`]
638    ///
639    /// If the [`Series`] is empty, a [`Scalar`] with a [`AnyValue::Null`] is returned.
640    fn last_non_null(&self) -> Scalar {
641        let n = self.len();
642        let av = if n == 0 {
643            AnyValue::Null
644        } else {
645            let idx = if self.has_nulls() {
646                last_non_null(self.chunks().iter().map(|c| c.as_ref()), n).unwrap_or(n - 1)
647            } else {
648                n - 1
649            };
650            // SAFETY: len-1 < len if len != 0
651            unsafe { self.get_unchecked(idx) }.into_static()
652        };
653        Scalar::new(self.dtype().clone(), av)
654    }
655
656    #[cfg(feature = "approx_unique")]
657    fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
658        polars_bail!(opq = approx_n_unique, self._dtype());
659    }
660
661    /// Clone inner ChunkedArray and wrap in a new Arc
662    fn clone_inner(&self) -> Arc<dyn SeriesTrait>;
663
664    #[cfg(feature = "object")]
665    /// Get the value at this index as a downcastable Any trait ref.
666    fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
667        invalid_operation_panic!(get_object, self)
668    }
669
670    #[cfg(feature = "object")]
671    /// Get the value at this index as a downcastable Any trait ref.
672    ///
673    /// # Safety
674    /// This function doesn't do any bound checks.
675    unsafe fn get_object_chunked_unchecked(
676        &self,
677        _chunk: usize,
678        _index: usize,
679    ) -> Option<&dyn PolarsObjectSafe> {
680        invalid_operation_panic!(get_object_chunked_unchecked, self)
681    }
682
683    /// Get a hold of the [`ChunkedArray`], [`Logical`] or `NullChunked` as an `Any` trait
684    /// reference.
685    fn as_any(&self) -> &dyn Any;
686
687    /// Get a hold of the [`ChunkedArray`], [`Logical`] or `NullChunked` as an `Any` trait mutable
688    /// reference.
689    fn as_any_mut(&mut self) -> &mut dyn Any;
690
691    /// Get a hold of the [`ChunkedArray`] or `NullChunked` as an `Any` trait reference. This
692    /// pierces through `Logical` types to get the underlying physical array.
693    fn as_phys_any(&self) -> &dyn Any;
694
695    fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
696
697    #[cfg(feature = "checked_arithmetic")]
698    fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
699        polars_bail!(opq = checked_div, self._dtype());
700    }
701
702    #[cfg(feature = "rolling_window")]
703    /// Apply a custom function over a rolling/ moving window of the array.
704    /// This has quite some dynamic dispatch, so prefer rolling_min, max, mean, sum over this.
705    fn rolling_map(
706        &self,
707        _f: &dyn Fn(&Series) -> PolarsResult<Series>,
708        _options: RollingOptionsFixedWindow,
709    ) -> PolarsResult<Series> {
710        polars_bail!(opq = rolling_map, self._dtype());
711    }
712}
713
714impl dyn SeriesTrait + '_ {
715    pub fn unpack<T: PolarsPhysicalType>(&self) -> PolarsResult<&ChunkedArray<T>> {
716        polars_ensure!(&T::get_static_dtype() == self.dtype(), unpack);
717        Ok(self.as_ref())
718    }
719}