1use std::any::Any;
2use std::borrow::Cow;
3
4use arrow::bitmap::{Bitmap, BitmapBuilder};
5use polars_compute::rolling::QuantileMethod;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::chunked_array::cast::CastOptions;
10#[cfg(feature = "object")]
11use crate::chunked_array::object::PolarsObjectSafe;
12use crate::prelude::*;
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16pub enum IsSorted {
17 Ascending,
18 Descending,
19 Not,
20}
21
22impl IsSorted {
23 pub fn reverse(self) -> Self {
24 use IsSorted::*;
25 match self {
26 Ascending => Descending,
27 Descending => Ascending,
28 Not => Not,
29 }
30 }
31}
32
33pub enum BitRepr {
34 Small(UInt32Chunked),
35 Large(UInt64Chunked),
36}
37
38pub(crate) mod private {
39 use polars_utils::aliases::PlSeedableRandomStateQuality;
40
41 use super::*;
42 use crate::chunked_array::flags::StatisticsFlags;
43 use crate::chunked_array::ops::compare_inner::{TotalEqInner, TotalOrdInner};
44
45 pub trait PrivateSeriesNumeric {
46 fn bit_repr(&self) -> Option<BitRepr>;
50 }
51
52 pub trait PrivateSeries {
53 #[cfg(feature = "object")]
54 fn get_list_builder(
55 &self,
56 _name: PlSmallStr,
57 _values_capacity: usize,
58 _list_capacity: usize,
59 ) -> Box<dyn ListBuilderTrait> {
60 invalid_operation_panic!(get_list_builder, self)
61 }
62
63 fn _field(&self) -> Cow<Field>;
65
66 fn _dtype(&self) -> &DataType;
67
68 fn compute_len(&mut self);
69
70 fn _get_flags(&self) -> StatisticsFlags;
71
72 fn _set_flags(&mut self, flags: StatisticsFlags);
73
74 unsafe fn equal_element(
75 &self,
76 _idx_self: usize,
77 _idx_other: usize,
78 _other: &Series,
79 ) -> bool {
80 invalid_operation_panic!(equal_element, self)
81 }
82 #[expect(clippy::wrong_self_convention)]
83 fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a>;
84 #[expect(clippy::wrong_self_convention)]
85 fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a>;
86
87 fn vec_hash(
88 &self,
89 _build_hasher: PlSeedableRandomStateQuality,
90 _buf: &mut Vec<u64>,
91 ) -> PolarsResult<()> {
92 polars_bail!(opq = vec_hash, self._dtype());
93 }
94 fn vec_hash_combine(
95 &self,
96 _build_hasher: PlSeedableRandomStateQuality,
97 _hashes: &mut [u64],
98 ) -> PolarsResult<()> {
99 polars_bail!(opq = vec_hash_combine, self._dtype());
100 }
101
102 #[cfg(feature = "algorithm_group_by")]
106 unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
107 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
108 }
109 #[cfg(feature = "algorithm_group_by")]
113 unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
114 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
115 }
116 #[cfg(feature = "algorithm_group_by")]
119 unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
120 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
121 }
122 #[cfg(feature = "algorithm_group_by")]
126 unsafe fn agg_std(&self, groups: &GroupsType, _ddof: u8) -> Series {
127 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
128 }
129 #[cfg(feature = "algorithm_group_by")]
133 unsafe fn agg_var(&self, groups: &GroupsType, _ddof: u8) -> Series {
134 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
135 }
136 #[cfg(feature = "algorithm_group_by")]
140 unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
141 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
142 }
143
144 #[cfg(feature = "bitwise")]
148 unsafe fn agg_and(&self, groups: &GroupsType) -> Series {
149 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
150 }
151
152 #[cfg(feature = "bitwise")]
156 unsafe fn agg_or(&self, groups: &GroupsType) -> Series {
157 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
158 }
159
160 #[cfg(feature = "bitwise")]
164 unsafe fn agg_xor(&self, groups: &GroupsType) -> Series {
165 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
166 }
167
168 fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
169 polars_bail!(opq = subtract, self._dtype());
170 }
171 fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
172 polars_bail!(opq = add, self._dtype());
173 }
174 fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
175 polars_bail!(opq = multiply, self._dtype());
176 }
177 fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
178 polars_bail!(opq = divide, self._dtype());
179 }
180 fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
181 polars_bail!(opq = remainder, self._dtype());
182 }
183 #[cfg(feature = "algorithm_group_by")]
184 fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsType> {
185 polars_bail!(opq = group_tuples, self._dtype());
186 }
187 #[cfg(feature = "zip_with")]
188 fn zip_with_same_type(
189 &self,
190 _mask: &BooleanChunked,
191 _other: &Series,
192 ) -> PolarsResult<Series> {
193 polars_bail!(opq = zip_with_same_type, self._dtype());
194 }
195
196 #[allow(unused_variables)]
197 fn arg_sort_multiple(
198 &self,
199 by: &[Column],
200 _options: &SortMultipleOptions,
201 ) -> PolarsResult<IdxCa> {
202 polars_bail!(opq = arg_sort_multiple, self._dtype());
203 }
204 }
205}
206
207pub trait SeriesTrait:
208 Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
209{
210 fn rename(&mut self, name: PlSmallStr);
212
213 fn chunk_lengths(&self) -> ChunkLenIter;
215
216 fn name(&self) -> &PlSmallStr;
218
219 fn field(&self) -> Cow<Field> {
221 self._field()
222 }
223
224 fn dtype(&self) -> &DataType {
226 self._dtype()
227 }
228
229 fn chunks(&self) -> &Vec<ArrayRef>;
231
232 unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef>;
237
238 fn n_chunks(&self) -> usize {
240 self.chunks().len()
241 }
242
243 fn shrink_to_fit(&mut self) {
245 }
247
248 fn limit(&self, num_elements: usize) -> Series {
250 self.slice(0, num_elements)
251 }
252
253 fn slice(&self, _offset: i64, _length: usize) -> Series;
258
259 fn split_at(&self, _offset: i64) -> (Series, Series);
264
265 fn append(&mut self, other: &Series) -> PolarsResult<()>;
266 fn append_owned(&mut self, other: Series) -> PolarsResult<()>;
267
268 #[doc(hidden)]
269 fn extend(&mut self, _other: &Series) -> PolarsResult<()>;
270
271 fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series>;
273
274 fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
280
281 unsafe fn take_unchecked(&self, _idx: &IdxCa) -> Series;
288
289 fn take_slice(&self, _indices: &[IdxSize]) -> PolarsResult<Series>;
293
294 unsafe fn take_slice_unchecked(&self, _idx: &[IdxSize]) -> Series;
299
300 fn len(&self) -> usize;
302
303 fn is_empty(&self) -> bool {
305 self.len() == 0
306 }
307
308 fn rechunk(&self) -> Series;
310
311 fn rechunk_validity(&self) -> Option<Bitmap> {
312 if self.chunks().len() == 1 {
313 return self.chunks()[0].validity().cloned();
314 }
315
316 if !self.has_nulls() || self.is_empty() {
317 return None;
318 }
319
320 let mut bm = BitmapBuilder::with_capacity(self.len());
321 for arr in self.chunks() {
322 if let Some(v) = arr.validity() {
323 bm.extend_from_bitmap(v);
324 } else {
325 bm.extend_constant(arr.len(), true);
326 }
327 }
328 bm.into_opt_validity()
329 }
330
331 fn drop_nulls(&self) -> Series {
333 if self.null_count() == 0 {
334 Series(self.clone_inner())
335 } else {
336 self.filter(&self.is_not_null()).unwrap()
337 }
338 }
339
340 fn _sum_as_f64(&self) -> f64 {
342 invalid_operation_panic!(_sum_as_f64, self)
343 }
344
345 fn mean(&self) -> Option<f64> {
348 None
349 }
350
351 fn std(&self, _ddof: u8) -> Option<f64> {
354 None
355 }
356
357 fn var(&self, _ddof: u8) -> Option<f64> {
360 None
361 }
362
363 fn median(&self) -> Option<f64> {
366 None
367 }
368
369 fn new_from_index(&self, _index: usize, _length: usize) -> Series;
380
381 fn cast(&self, _dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
382
383 fn get(&self, index: usize) -> PolarsResult<AnyValue> {
386 polars_ensure!(index < self.len(), oob = index, self.len());
387 let value = unsafe { self.get_unchecked(index) };
389 Ok(value)
390 }
391
392 unsafe fn get_unchecked(&self, _index: usize) -> AnyValue;
400
401 fn sort_with(&self, _options: SortOptions) -> PolarsResult<Series> {
402 polars_bail!(opq = sort_with, self._dtype());
403 }
404
405 #[allow(unused)]
407 fn arg_sort(&self, options: SortOptions) -> IdxCa {
408 invalid_operation_panic!(arg_sort, self)
409 }
410
411 fn null_count(&self) -> usize;
413
414 fn has_nulls(&self) -> bool;
416
417 fn unique(&self) -> PolarsResult<Series> {
419 polars_bail!(opq = unique, self._dtype());
420 }
421
422 fn n_unique(&self) -> PolarsResult<usize> {
426 polars_bail!(opq = n_unique, self._dtype());
427 }
428
429 fn arg_unique(&self) -> PolarsResult<IdxCa> {
431 polars_bail!(opq = arg_unique, self._dtype());
432 }
433
434 fn is_null(&self) -> BooleanChunked;
436
437 fn is_not_null(&self) -> BooleanChunked;
439
440 fn reverse(&self) -> Series;
442
443 fn as_single_ptr(&mut self) -> PolarsResult<usize> {
446 polars_bail!(opq = as_single_ptr, self._dtype());
447 }
448
449 fn shift(&self, _periods: i64) -> Series;
476
477 fn sum_reduce(&self) -> PolarsResult<Scalar> {
482 polars_bail!(opq = sum, self._dtype());
483 }
484 fn max_reduce(&self) -> PolarsResult<Scalar> {
486 polars_bail!(opq = max, self._dtype());
487 }
488 fn min_reduce(&self) -> PolarsResult<Scalar> {
490 polars_bail!(opq = min, self._dtype());
491 }
492 fn median_reduce(&self) -> PolarsResult<Scalar> {
494 polars_bail!(opq = median, self._dtype());
495 }
496 fn var_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
498 polars_bail!(opq = var, self._dtype());
499 }
500 fn std_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
502 polars_bail!(opq = std, self._dtype());
503 }
504 fn quantile_reduce(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Scalar> {
506 polars_bail!(opq = quantile, self._dtype());
507 }
508 fn and_reduce(&self) -> PolarsResult<Scalar> {
510 polars_bail!(opq = and_reduce, self._dtype());
511 }
512 fn or_reduce(&self) -> PolarsResult<Scalar> {
514 polars_bail!(opq = or_reduce, self._dtype());
515 }
516 fn xor_reduce(&self) -> PolarsResult<Scalar> {
518 polars_bail!(opq = xor_reduce, self._dtype());
519 }
520
521 fn first(&self) -> Scalar {
525 let dt = self.dtype();
526 let av = self.get(0).map_or(AnyValue::Null, AnyValue::into_static);
527
528 Scalar::new(dt.clone(), av)
529 }
530
531 fn last(&self) -> Scalar {
535 let dt = self.dtype();
536 let av = if self.len() == 0 {
537 AnyValue::Null
538 } else {
539 unsafe { self.get_unchecked(self.len() - 1) }.into_static()
541 };
542
543 Scalar::new(dt.clone(), av)
544 }
545
546 #[cfg(feature = "approx_unique")]
547 fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
548 polars_bail!(opq = approx_n_unique, self._dtype());
549 }
550
551 fn clone_inner(&self) -> Arc<dyn SeriesTrait>;
553
554 #[cfg(feature = "object")]
555 fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
557 invalid_operation_panic!(get_object, self)
558 }
559
560 #[cfg(feature = "object")]
561 unsafe fn get_object_chunked_unchecked(
566 &self,
567 _chunk: usize,
568 _index: usize,
569 ) -> Option<&dyn PolarsObjectSafe> {
570 invalid_operation_panic!(get_object_chunked_unchecked, self)
571 }
572
573 fn as_any(&self) -> &dyn Any;
576
577 fn as_any_mut(&mut self) -> &mut dyn Any;
580
581 fn as_phys_any(&self) -> &dyn Any;
584
585 fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
586
587 #[cfg(feature = "checked_arithmetic")]
588 fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
589 polars_bail!(opq = checked_div, self._dtype());
590 }
591
592 #[cfg(feature = "rolling_window")]
593 fn rolling_map(
596 &self,
597 _f: &dyn Fn(&Series) -> Series,
598 _options: RollingOptionsFixedWindow,
599 ) -> PolarsResult<Series> {
600 polars_bail!(opq = rolling_map, self._dtype());
601 }
602}
603
604impl (dyn SeriesTrait + '_) {
605 pub fn unpack<N>(&self) -> PolarsResult<&ChunkedArray<N>>
606 where
607 N: 'static + PolarsDataType<IsLogical = FalseT>,
608 {
609 polars_ensure!(&N::get_dtype() == self.dtype(), unpack);
610 Ok(self.as_ref())
611 }
612}