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::*;
13use crate::utils::{first_non_null, last_non_null};
14
15#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[cfg_attr(feature = "dsl-schema", derive(schemars::JsonSchema))]
18pub enum IsSorted {
19 Ascending,
20 Descending,
21 Not,
22}
23
24impl IsSorted {
25 pub fn reverse(self) -> Self {
26 use IsSorted::*;
27 match self {
28 Ascending => Descending,
29 Descending => Ascending,
30 Not => Not,
31 }
32 }
33}
34
35pub enum BitRepr {
36 U8(UInt8Chunked),
37 U16(UInt16Chunked),
38 U32(UInt32Chunked),
39 U64(UInt64Chunked),
40 #[cfg(feature = "dtype-u128")]
41 U128(UInt128Chunked),
42}
43
44pub(crate) mod private {
45 use polars_utils::aliases::PlSeedableRandomStateQuality;
46
47 use super::*;
48 use crate::chunked_array::flags::StatisticsFlags;
49 use crate::chunked_array::ops::compare_inner::{TotalEqInner, TotalOrdInner};
50
51 pub trait PrivateSeriesNumeric {
52 fn bit_repr(&self) -> Option<BitRepr>;
56 }
57
58 pub trait PrivateSeries {
59 #[cfg(feature = "object")]
60 fn get_list_builder(
61 &self,
62 _name: PlSmallStr,
63 _values_capacity: usize,
64 _list_capacity: usize,
65 ) -> Box<dyn ListBuilderTrait> {
66 invalid_operation_panic!(get_list_builder, self)
67 }
68
69 fn _field(&self) -> Cow<'_, Field>;
71
72 fn _dtype(&self) -> &DataType;
73
74 fn compute_len(&mut self);
75
76 fn _get_flags(&self) -> StatisticsFlags;
77
78 fn _set_flags(&mut self, flags: StatisticsFlags);
79
80 unsafe fn equal_element(
81 &self,
82 _idx_self: usize,
83 _idx_other: usize,
84 _other: &Series,
85 ) -> bool {
86 invalid_operation_panic!(equal_element, self)
87 }
88 #[expect(clippy::wrong_self_convention)]
89 fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a>;
90 #[expect(clippy::wrong_self_convention)]
91 fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a>;
92
93 fn vec_hash(
94 &self,
95 _build_hasher: PlSeedableRandomStateQuality,
96 _buf: &mut Vec<u64>,
97 ) -> PolarsResult<()>;
98 fn vec_hash_combine(
99 &self,
100 _build_hasher: PlSeedableRandomStateQuality,
101 _hashes: &mut [u64],
102 ) -> PolarsResult<()>;
103
104 #[cfg(feature = "algorithm_group_by")]
108 unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
109 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
110 }
111 #[cfg(feature = "algorithm_group_by")]
115 unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
116 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
117 }
118 #[cfg(feature = "algorithm_group_by")]
121 unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
122 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
123 }
124 #[cfg(feature = "algorithm_group_by")]
128 unsafe fn agg_std(&self, groups: &GroupsType, _ddof: u8) -> Series {
129 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
130 }
131 #[cfg(feature = "algorithm_group_by")]
135 unsafe fn agg_var(&self, groups: &GroupsType, _ddof: u8) -> Series {
136 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
137 }
138 #[cfg(feature = "algorithm_group_by")]
142 unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
143 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
144 }
145
146 #[cfg(feature = "bitwise")]
150 unsafe fn agg_and(&self, groups: &GroupsType) -> Series {
151 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
152 }
153
154 #[cfg(feature = "bitwise")]
158 unsafe fn agg_or(&self, groups: &GroupsType) -> Series {
159 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
160 }
161
162 #[cfg(feature = "bitwise")]
166 unsafe fn agg_xor(&self, groups: &GroupsType) -> Series {
167 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
168 }
169
170 fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
171 polars_bail!(opq = subtract, self._dtype());
172 }
173 fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
174 polars_bail!(opq = add, self._dtype());
175 }
176 fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
177 polars_bail!(opq = multiply, self._dtype());
178 }
179 fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
180 polars_bail!(opq = divide, self._dtype());
181 }
182 fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
183 polars_bail!(opq = remainder, self._dtype());
184 }
185 #[cfg(feature = "algorithm_group_by")]
186 fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsType> {
187 polars_bail!(opq = group_tuples, self._dtype());
188 }
189 #[cfg(feature = "zip_with")]
190 fn zip_with_same_type(
191 &self,
192 _mask: &BooleanChunked,
193 _other: &Series,
194 ) -> PolarsResult<Series> {
195 polars_bail!(opq = zip_with_same_type, self._dtype());
196 }
197
198 #[allow(unused_variables)]
199 fn arg_sort_multiple(
200 &self,
201 by: &[Column],
202 _options: &SortMultipleOptions,
203 ) -> PolarsResult<IdxCa> {
204 polars_bail!(opq = arg_sort_multiple, self._dtype());
205 }
206 }
207}
208
209pub trait SeriesTrait:
210 Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
211{
212 fn rename(&mut self, name: PlSmallStr);
214
215 fn chunk_lengths(&self) -> ChunkLenIter<'_>;
217
218 fn name(&self) -> &PlSmallStr;
220
221 fn field(&self) -> Cow<'_, Field> {
223 self._field()
224 }
225
226 fn dtype(&self) -> &DataType {
228 self._dtype()
229 }
230
231 fn chunks(&self) -> &Vec<ArrayRef>;
233
234 unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef>;
239
240 fn n_chunks(&self) -> usize {
242 self.chunks().len()
243 }
244
245 fn shrink_to_fit(&mut self) {
247 }
249
250 fn limit(&self, num_elements: usize) -> Series {
252 self.slice(0, num_elements)
253 }
254
255 fn slice(&self, _offset: i64, _length: usize) -> Series;
260
261 fn split_at(&self, _offset: i64) -> (Series, Series);
266
267 fn append(&mut self, other: &Series) -> PolarsResult<()>;
268 fn append_owned(&mut self, other: Series) -> PolarsResult<()>;
269
270 #[doc(hidden)]
271 fn extend(&mut self, _other: &Series) -> PolarsResult<()>;
272
273 fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series>;
275
276 fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
282
283 unsafe fn take_unchecked(&self, _idx: &IdxCa) -> Series;
290
291 fn take_slice(&self, _indices: &[IdxSize]) -> PolarsResult<Series>;
295
296 unsafe fn take_slice_unchecked(&self, _idx: &[IdxSize]) -> Series;
301
302 fn len(&self) -> usize;
304
305 fn is_empty(&self) -> bool {
307 self.len() == 0
308 }
309
310 fn rechunk(&self) -> Series;
312
313 fn rechunk_validity(&self) -> Option<Bitmap> {
314 if self.chunks().len() == 1 {
315 return self.chunks()[0].validity().cloned();
316 }
317
318 if !self.has_nulls() || self.is_empty() {
319 return None;
320 }
321
322 let mut bm = BitmapBuilder::with_capacity(self.len());
323 for arr in self.chunks() {
324 if let Some(v) = arr.validity() {
325 bm.extend_from_bitmap(v);
326 } else {
327 bm.extend_constant(arr.len(), true);
328 }
329 }
330 bm.into_opt_validity()
331 }
332
333 fn drop_nulls(&self) -> Series {
335 if self.null_count() == 0 {
336 Series(self.clone_inner())
337 } else {
338 self.filter(&self.is_not_null()).unwrap()
339 }
340 }
341
342 fn _sum_as_f64(&self) -> f64 {
344 invalid_operation_panic!(_sum_as_f64, self)
345 }
346
347 fn mean(&self) -> Option<f64> {
350 None
351 }
352
353 fn std(&self, _ddof: u8) -> Option<f64> {
356 None
357 }
358
359 fn var(&self, _ddof: u8) -> Option<f64> {
362 None
363 }
364
365 fn median(&self) -> Option<f64> {
368 None
369 }
370
371 fn new_from_index(&self, _index: usize, _length: usize) -> Series;
382
383 fn trim_lists_to_normalized_offsets(&self) -> Option<Series> {
388 None
389 }
390
391 fn propagate_nulls(&self) -> Option<Series> {
396 None
397 }
398
399 fn deposit(&self, validity: &Bitmap) -> Series;
400
401 fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>);
403
404 fn cast(&self, _dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
405
406 fn get(&self, index: usize) -> PolarsResult<AnyValue<'_>> {
409 polars_ensure!(index < self.len(), oob = index, self.len());
410 let value = unsafe { self.get_unchecked(index) };
412 Ok(value)
413 }
414
415 unsafe fn get_unchecked(&self, _index: usize) -> AnyValue<'_>;
423
424 fn sort_with(&self, _options: SortOptions) -> PolarsResult<Series> {
425 polars_bail!(opq = sort_with, self._dtype());
426 }
427
428 #[allow(unused)]
430 fn arg_sort(&self, options: SortOptions) -> IdxCa {
431 invalid_operation_panic!(arg_sort, self)
432 }
433
434 fn null_count(&self) -> usize;
436
437 fn has_nulls(&self) -> bool;
439
440 fn unique(&self) -> PolarsResult<Series> {
442 polars_bail!(opq = unique, self._dtype());
443 }
444
445 fn n_unique(&self) -> PolarsResult<usize> {
449 polars_bail!(opq = n_unique, self._dtype());
450 }
451
452 fn arg_unique(&self) -> PolarsResult<IdxCa> {
454 polars_bail!(opq = arg_unique, self._dtype());
455 }
456
457 fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)>;
461
462 fn is_null(&self) -> BooleanChunked;
464
465 fn is_not_null(&self) -> BooleanChunked;
467
468 fn reverse(&self) -> Series;
470
471 fn as_single_ptr(&mut self) -> PolarsResult<usize> {
474 polars_bail!(opq = as_single_ptr, self._dtype());
475 }
476
477 fn shift(&self, _periods: i64) -> Series;
504
505 fn sum_reduce(&self) -> PolarsResult<Scalar> {
510 polars_bail!(opq = sum, self._dtype());
511 }
512 fn max_reduce(&self) -> PolarsResult<Scalar> {
514 polars_bail!(opq = max, self._dtype());
515 }
516 fn min_reduce(&self) -> PolarsResult<Scalar> {
518 polars_bail!(opq = min, self._dtype());
519 }
520 fn median_reduce(&self) -> PolarsResult<Scalar> {
522 polars_bail!(opq = median, self._dtype());
523 }
524 fn mean_reduce(&self) -> PolarsResult<Scalar> {
526 polars_bail!(opq = mean, self._dtype());
527 }
528 fn var_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
530 polars_bail!(opq = var, self._dtype());
531 }
532 fn std_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
534 polars_bail!(opq = std, self._dtype());
535 }
536 fn quantile_reduce(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Scalar> {
538 polars_bail!(opq = quantile, self._dtype());
539 }
540 fn and_reduce(&self) -> PolarsResult<Scalar> {
542 polars_bail!(opq = and_reduce, self._dtype());
543 }
544 fn or_reduce(&self) -> PolarsResult<Scalar> {
546 polars_bail!(opq = or_reduce, self._dtype());
547 }
548 fn xor_reduce(&self) -> PolarsResult<Scalar> {
550 polars_bail!(opq = xor_reduce, self._dtype());
551 }
552
553 fn first(&self) -> Scalar {
557 let dt = self.dtype();
558 let av = self.get(0).map_or(AnyValue::Null, AnyValue::into_static);
559
560 Scalar::new(dt.clone(), av)
561 }
562
563 fn first_non_null(&self) -> Scalar {
567 let av = if self.len() == 0 {
568 AnyValue::Null
569 } else {
570 let idx = if self.has_nulls() {
571 first_non_null(self.chunks().iter().map(|c| c.as_ref())).unwrap_or(0)
572 } else {
573 0
574 };
575 self.get(idx).map_or(AnyValue::Null, AnyValue::into_static)
576 };
577 Scalar::new(self.dtype().clone(), av)
578 }
579
580 fn last(&self) -> Scalar {
584 let dt = self.dtype();
585 let av = if self.len() == 0 {
586 AnyValue::Null
587 } else {
588 unsafe { self.get_unchecked(self.len() - 1) }.into_static()
590 };
591
592 Scalar::new(dt.clone(), av)
593 }
594
595 fn last_non_null(&self) -> Scalar {
599 let n = self.len();
600 let av = if n == 0 {
601 AnyValue::Null
602 } else {
603 let idx = if self.has_nulls() {
604 last_non_null(self.chunks().iter().map(|c| c.as_ref()), n).unwrap_or(n - 1)
605 } else {
606 n - 1
607 };
608 unsafe { self.get_unchecked(idx) }.into_static()
610 };
611 Scalar::new(self.dtype().clone(), av)
612 }
613
614 #[cfg(feature = "approx_unique")]
615 fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
616 polars_bail!(opq = approx_n_unique, self._dtype());
617 }
618
619 fn clone_inner(&self) -> Arc<dyn SeriesTrait>;
621
622 #[cfg(feature = "object")]
623 fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
625 invalid_operation_panic!(get_object, self)
626 }
627
628 #[cfg(feature = "object")]
629 unsafe fn get_object_chunked_unchecked(
634 &self,
635 _chunk: usize,
636 _index: usize,
637 ) -> Option<&dyn PolarsObjectSafe> {
638 invalid_operation_panic!(get_object_chunked_unchecked, self)
639 }
640
641 fn as_any(&self) -> &dyn Any;
644
645 fn as_any_mut(&mut self) -> &mut dyn Any;
648
649 fn as_phys_any(&self) -> &dyn Any;
652
653 fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
654
655 #[cfg(feature = "checked_arithmetic")]
656 fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
657 polars_bail!(opq = checked_div, self._dtype());
658 }
659
660 #[cfg(feature = "rolling_window")]
661 fn rolling_map(
664 &self,
665 _f: &dyn Fn(&Series) -> PolarsResult<Series>,
666 _options: RollingOptionsFixedWindow,
667 ) -> PolarsResult<Series> {
668 polars_bail!(opq = rolling_map, self._dtype());
669 }
670}
671
672impl dyn SeriesTrait + '_ {
673 pub fn unpack<T: PolarsPhysicalType>(&self) -> PolarsResult<&ChunkedArray<T>> {
674 polars_ensure!(&T::get_static_dtype() == self.dtype(), unpack);
675 Ok(self.as_ref())
676 }
677}