1use std::any::Any;
2use std::borrow::Cow;
3
4use polars_arrow::bitmap::{Bitmap, BitmapBuilder};
5use polars_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::TotalOrdInner;
47
48 pub trait PrivateSeriesNumeric {
49 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 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_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a>;
79
80 fn vec_hash(
81 &self,
82 _build_hasher: PlSeedableRandomStateQuality,
83 _buf: &mut Vec<u64>,
84 ) -> PolarsResult<()>;
85 fn vec_hash_combine(
86 &self,
87 _build_hasher: PlSeedableRandomStateQuality,
88 _hashes: &mut [u64],
89 ) -> PolarsResult<()>;
90
91 #[cfg(feature = "algorithm_group_by")]
95 unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
96 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
97 }
98 #[cfg(feature = "algorithm_group_by")]
102 unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
103 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
104 }
105 #[cfg(feature = "algorithm_group_by")]
109 unsafe fn agg_arg_min(&self, groups: &GroupsType) -> Series {
110 Series::full_null(self._field().name().clone(), groups.len(), &IDX_DTYPE)
111 }
112
113 #[cfg(feature = "algorithm_group_by")]
117 unsafe fn agg_arg_max(&self, groups: &GroupsType) -> Series {
118 Series::full_null(self._field().name().clone(), groups.len(), &IDX_DTYPE)
119 }
120
121 #[cfg(feature = "algorithm_group_by")]
124 unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
125 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
126 }
127 #[cfg(feature = "algorithm_group_by")]
131 unsafe fn agg_std(&self, groups: &GroupsType, _ddof: u8) -> Series {
132 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
133 }
134 #[cfg(feature = "algorithm_group_by")]
138 unsafe fn agg_var(&self, groups: &GroupsType, _ddof: u8) -> Series {
139 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
140 }
141 #[cfg(feature = "algorithm_group_by")]
145 unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
146 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
147 }
148
149 #[cfg(feature = "bitwise")]
153 unsafe fn agg_and(&self, groups: &GroupsType) -> Series {
154 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
155 }
156
157 #[cfg(feature = "bitwise")]
161 unsafe fn agg_or(&self, groups: &GroupsType) -> Series {
162 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
163 }
164
165 #[cfg(feature = "bitwise")]
169 unsafe fn agg_xor(&self, groups: &GroupsType) -> Series {
170 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
171 }
172
173 fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
174 polars_bail!(opq = subtract, self._dtype());
175 }
176 fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
177 polars_bail!(opq = add, self._dtype());
178 }
179 fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
180 polars_bail!(opq = multiply, self._dtype());
181 }
182 fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
183 polars_bail!(opq = divide, self._dtype());
184 }
185 fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
186 polars_bail!(opq = remainder, self._dtype());
187 }
188 #[cfg(feature = "algorithm_group_by")]
189 fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsType> {
190 polars_bail!(opq = group_tuples, self._dtype());
191 }
192 #[cfg(feature = "zip_with")]
193 fn zip_with_same_type(
194 &self,
195 _mask: &BooleanChunked,
196 _other: &Series,
197 ) -> PolarsResult<Series> {
198 polars_bail!(opq = zip_with_same_type, self._dtype());
199 }
200
201 #[allow(unused_variables)]
202 fn arg_sort_multiple(
203 &self,
204 by: &[Column],
205 _options: &SortMultipleOptions,
206 ) -> PolarsResult<IdxCa> {
207 polars_bail!(opq = arg_sort_multiple, self._dtype());
208 }
209 }
210}
211
212pub trait SeriesTrait:
213 Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
214{
215 fn rename(&mut self, name: PlSmallStr);
217
218 fn chunk_lengths(&self) -> ChunkLenIter<'_>;
220
221 fn name(&self) -> &PlSmallStr;
223
224 fn field(&self) -> Cow<'_, Field> {
226 self._field()
227 }
228
229 #[inline(always)]
231 fn dtype(&self) -> &DataType {
232 self._dtype()
233 }
234
235 fn chunks(&self) -> &Vec<ArrayRef>;
237
238 unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef>;
243
244 fn n_chunks(&self) -> usize {
246 self.chunks().len()
247 }
248
249 fn shrink_to_fit(&mut self) {
251 }
253
254 fn limit(&self, num_elements: usize) -> Series {
256 self.slice(0, num_elements)
257 }
258
259 fn slice(&self, _offset: i64, _length: usize) -> Series;
264
265 fn split_at(&self, _offset: i64) -> (Series, Series);
270
271 fn append(&mut self, other: &Series) -> PolarsResult<()>;
272 fn append_owned(&mut self, other: Series) -> PolarsResult<()>;
273
274 #[doc(hidden)]
275 fn extend(&mut self, _other: &Series) -> PolarsResult<()>;
276
277 fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series>;
279
280 fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
286
287 unsafe fn take_unchecked(&self, _idx: &IdxCa) -> Series;
294
295 fn take_slice(&self, _indices: &[IdxSize]) -> PolarsResult<Series>;
299
300 unsafe fn take_slice_unchecked(&self, _idx: &[IdxSize]) -> Series;
305
306 fn len(&self) -> usize;
308
309 fn is_empty(&self) -> bool {
311 self.len() == 0
312 }
313
314 fn is_full_null(&self) -> bool {
316 self.len() == self.null_count()
317 }
318
319 fn rechunk(&self) -> Series;
321
322 fn rechunk_validity(&self) -> Option<Bitmap> {
324 if self.chunks().len() == 1 {
325 return self.chunks()[0].validity().cloned();
326 }
327
328 if !self.has_nulls() || self.is_empty() {
329 return None;
330 }
331
332 let mut bm = BitmapBuilder::with_capacity(self.len());
333 for arr in self.chunks() {
334 if let Some(v) = arr.validity() {
335 bm.extend_from_bitmap(v);
336 } else {
337 bm.extend_constant(arr.len(), true);
338 }
339 }
340 bm.into_opt_validity()
341 }
342
343 fn with_validity(&self, validity: Option<Bitmap>) -> Series;
345
346 fn mask(&self, validity: &Bitmap) -> Series {
350 if validity.len() == 1 {
351 if validity.get_bit(0) {
352 Series(self.clone_inner())
353 } else {
354 Series::full_null(self._field().name().clone(), self.len(), self._dtype())
355 }
356 } else if self.len() == 1 && validity.len() != 1 {
357 self.new_from_index(0, validity.len()).mask(validity)
358 } else {
359 self.with_validity(combine_validities_and(
360 self.rechunk_validity().as_ref(),
361 Some(validity),
362 ))
363 }
364 }
365
366 fn drop_nulls(&self) -> Series {
368 if self.null_count() == 0 {
369 Series(self.clone_inner())
370 } else {
371 self.filter(&self.is_not_null()).unwrap()
372 }
373 }
374
375 fn _sum_as_f64(&self) -> f64 {
377 invalid_operation_panic!(_sum_as_f64, self)
378 }
379
380 fn mean(&self) -> Option<f64> {
383 None
384 }
385
386 fn std(&self, _ddof: u8) -> Option<f64> {
389 None
390 }
391
392 fn var(&self, _ddof: u8) -> Option<f64> {
395 None
396 }
397
398 fn median(&self) -> Option<f64> {
401 None
402 }
403
404 fn new_from_index(&self, _index: usize, _length: usize) -> Series;
415
416 fn trim_lists_to_normalized_offsets(&self) -> Option<Series> {
421 None
422 }
423
424 fn propagate_nulls(&self) -> Option<Series> {
429 None
430 }
431
432 fn deposit(&self, validity: &Bitmap) -> Series;
433
434 fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>);
436
437 fn cast(&self, _dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
438
439 fn get(&self, index: usize) -> PolarsResult<AnyValue<'_>> {
442 polars_ensure!(index < self.len(), oob = index, self.len());
443 let value = unsafe { self.get_unchecked(index) };
445 Ok(value)
446 }
447
448 unsafe fn get_unchecked(&self, _index: usize) -> AnyValue<'_>;
456
457 fn sort_with(&self, _options: SortOptions) -> PolarsResult<Series> {
458 polars_bail!(opq = sort_with, self._dtype());
459 }
460
461 #[allow(unused)]
463 fn arg_sort(&self, options: SortOptions) -> IdxCa {
464 invalid_operation_panic!(arg_sort, self)
465 }
466
467 fn null_count(&self) -> usize;
469
470 fn has_nulls(&self) -> bool;
472
473 fn unique(&self) -> PolarsResult<Series> {
475 polars_bail!(opq = unique, self._dtype());
476 }
477
478 fn n_unique(&self) -> PolarsResult<usize> {
482 polars_bail!(opq = n_unique, self._dtype());
483 }
484
485 fn arg_unique(&self) -> PolarsResult<IdxCa> {
487 polars_bail!(opq = arg_unique, self._dtype());
488 }
489
490 fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)> {
494 polars_bail!(opq = unique_id, self._dtype());
495 }
496
497 fn is_null(&self) -> BooleanChunked;
499
500 fn is_not_null(&self) -> BooleanChunked;
502
503 fn reverse(&self) -> Series;
505
506 fn as_single_ptr(&mut self) -> PolarsResult<usize> {
509 polars_bail!(opq = as_single_ptr, self._dtype());
510 }
511
512 fn shift(&self, _periods: i64) -> Series;
539
540 fn sum_reduce(&self) -> PolarsResult<Scalar> {
545 polars_bail!(opq = sum, self._dtype());
546 }
547 fn max_reduce(&self) -> PolarsResult<Scalar> {
549 polars_bail!(opq = max, self._dtype());
550 }
551 fn min_reduce(&self) -> PolarsResult<Scalar> {
553 polars_bail!(opq = min, self._dtype());
554 }
555 fn median_reduce(&self) -> PolarsResult<Scalar> {
557 polars_bail!(opq = median, self._dtype());
558 }
559 fn mean_reduce(&self) -> PolarsResult<Scalar> {
561 polars_bail!(opq = mean, self._dtype());
562 }
563 fn var_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
565 polars_bail!(opq = var, self._dtype());
566 }
567 fn std_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
569 polars_bail!(opq = std, self._dtype());
570 }
571 fn quantile_reduce(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Scalar> {
573 polars_bail!(opq = quantile, self._dtype());
574 }
575 fn quantiles_reduce(
577 &self,
578 _quantiles: &[f64],
579 _method: QuantileMethod,
580 ) -> PolarsResult<Scalar> {
581 polars_bail!(opq = quantiles, self._dtype());
582 }
583 fn and_reduce(&self) -> PolarsResult<Scalar> {
585 polars_bail!(opq = and_reduce, self._dtype());
586 }
587 fn or_reduce(&self) -> PolarsResult<Scalar> {
589 polars_bail!(opq = or_reduce, self._dtype());
590 }
591 fn xor_reduce(&self) -> PolarsResult<Scalar> {
593 polars_bail!(opq = xor_reduce, self._dtype());
594 }
595
596 fn first(&self) -> Scalar {
600 let dt = self.dtype();
601 let av = self.get(0).map_or(AnyValue::Null, AnyValue::into_static);
602
603 Scalar::new(dt.clone(), av)
604 }
605
606 fn first_non_null(&self) -> Scalar {
610 let av = if self.len() == 0 {
611 AnyValue::Null
612 } else {
613 let idx = if self.has_nulls() {
614 first_non_null(self.chunks().iter().map(|c| c.as_ref())).unwrap_or(0)
615 } else {
616 0
617 };
618 self.get(idx).map_or(AnyValue::Null, AnyValue::into_static)
619 };
620 Scalar::new(self.dtype().clone(), av)
621 }
622
623 fn last(&self) -> Scalar {
627 let dt = self.dtype();
628 let av = if self.len() == 0 {
629 AnyValue::Null
630 } else {
631 unsafe { self.get_unchecked(self.len() - 1) }.into_static()
633 };
634
635 Scalar::new(dt.clone(), av)
636 }
637
638 fn last_non_null(&self) -> Scalar {
642 let n = self.len();
643 let av = if n == 0 {
644 AnyValue::Null
645 } else {
646 let idx = if self.has_nulls() {
647 last_non_null(self.chunks().iter().map(|c| c.as_ref()), n).unwrap_or(n - 1)
648 } else {
649 n - 1
650 };
651 unsafe { self.get_unchecked(idx) }.into_static()
653 };
654 Scalar::new(self.dtype().clone(), av)
655 }
656
657 #[cfg(feature = "approx_unique")]
658 fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
659 polars_bail!(opq = approx_n_unique, self._dtype());
660 }
661
662 fn clone_inner(&self) -> Arc<dyn SeriesTrait>;
664
665 #[cfg(feature = "object")]
666 fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
668 invalid_operation_panic!(get_object, self)
669 }
670
671 #[cfg(feature = "object")]
672 unsafe fn get_object_chunked_unchecked(
677 &self,
678 _chunk: usize,
679 _index: usize,
680 ) -> Option<&dyn PolarsObjectSafe> {
681 invalid_operation_panic!(get_object_chunked_unchecked, self)
682 }
683
684 fn as_any(&self) -> &dyn Any;
687
688 fn as_any_mut(&mut self) -> &mut dyn Any;
691
692 fn as_phys_any(&self) -> &dyn Any;
695
696 fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
697
698 #[cfg(feature = "checked_arithmetic")]
699 fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
700 polars_bail!(opq = checked_div, self._dtype());
701 }
702
703 #[cfg(feature = "rolling_window")]
704 fn rolling_map(
707 &self,
708 _f: &dyn Fn(&Series) -> PolarsResult<Series>,
709 _options: RollingOptionsFixedWindow,
710 ) -> PolarsResult<Series> {
711 polars_bail!(opq = rolling_map, self._dtype());
712 }
713}
714
715impl dyn SeriesTrait + '_ {
716 pub fn unpack<T: PolarsPhysicalType>(&self) -> PolarsResult<&ChunkedArray<T>> {
717 polars_ensure!(&T::get_static_dtype() == self.dtype(), unpack);
718 Ok(self.as_ref())
719 }
720}