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))]
16#[cfg_attr(feature = "dsl-schema", derive(schemars::JsonSchema))]
17pub enum IsSorted {
18 Ascending,
19 Descending,
20 Not,
21}
22
23impl IsSorted {
24 pub fn reverse(self) -> Self {
25 use IsSorted::*;
26 match self {
27 Ascending => Descending,
28 Descending => Ascending,
29 Not => Not,
30 }
31 }
32}
33
34pub enum BitRepr {
35 U32(UInt32Chunked),
36 U64(UInt64Chunked),
37 #[cfg(feature = "dtype-i128")]
38 I128(Int128Chunked),
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 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 unsafe fn equal_element(
78 &self,
79 _idx_self: usize,
80 _idx_other: usize,
81 _other: &Series,
82 ) -> bool {
83 invalid_operation_panic!(equal_element, self)
84 }
85 #[expect(clippy::wrong_self_convention)]
86 fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a>;
87 #[expect(clippy::wrong_self_convention)]
88 fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a>;
89
90 fn vec_hash(
91 &self,
92 _build_hasher: PlSeedableRandomStateQuality,
93 _buf: &mut Vec<u64>,
94 ) -> PolarsResult<()>;
95 fn vec_hash_combine(
96 &self,
97 _build_hasher: PlSeedableRandomStateQuality,
98 _hashes: &mut [u64],
99 ) -> PolarsResult<()>;
100
101 #[cfg(feature = "algorithm_group_by")]
105 unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
106 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
107 }
108 #[cfg(feature = "algorithm_group_by")]
112 unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
113 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
114 }
115 #[cfg(feature = "algorithm_group_by")]
118 unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
119 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
120 }
121 #[cfg(feature = "algorithm_group_by")]
125 unsafe fn agg_std(&self, groups: &GroupsType, _ddof: u8) -> Series {
126 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
127 }
128 #[cfg(feature = "algorithm_group_by")]
132 unsafe fn agg_var(&self, groups: &GroupsType, _ddof: u8) -> Series {
133 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
134 }
135 #[cfg(feature = "algorithm_group_by")]
139 unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
140 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
141 }
142
143 #[cfg(feature = "bitwise")]
147 unsafe fn agg_and(&self, groups: &GroupsType) -> Series {
148 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
149 }
150
151 #[cfg(feature = "bitwise")]
155 unsafe fn agg_or(&self, groups: &GroupsType) -> Series {
156 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
157 }
158
159 #[cfg(feature = "bitwise")]
163 unsafe fn agg_xor(&self, groups: &GroupsType) -> Series {
164 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
165 }
166
167 fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
168 polars_bail!(opq = subtract, self._dtype());
169 }
170 fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
171 polars_bail!(opq = add, self._dtype());
172 }
173 fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
174 polars_bail!(opq = multiply, self._dtype());
175 }
176 fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
177 polars_bail!(opq = divide, self._dtype());
178 }
179 fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
180 polars_bail!(opq = remainder, self._dtype());
181 }
182 #[cfg(feature = "algorithm_group_by")]
183 fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsType> {
184 polars_bail!(opq = group_tuples, self._dtype());
185 }
186 #[cfg(feature = "zip_with")]
187 fn zip_with_same_type(
188 &self,
189 _mask: &BooleanChunked,
190 _other: &Series,
191 ) -> PolarsResult<Series> {
192 polars_bail!(opq = zip_with_same_type, self._dtype());
193 }
194
195 #[allow(unused_variables)]
196 fn arg_sort_multiple(
197 &self,
198 by: &[Column],
199 _options: &SortMultipleOptions,
200 ) -> PolarsResult<IdxCa> {
201 polars_bail!(opq = arg_sort_multiple, self._dtype());
202 }
203 }
204}
205
206pub trait SeriesTrait:
207 Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
208{
209 fn rename(&mut self, name: PlSmallStr);
211
212 fn chunk_lengths(&self) -> ChunkLenIter<'_>;
214
215 fn name(&self) -> &PlSmallStr;
217
218 fn field(&self) -> Cow<'_, Field> {
220 self._field()
221 }
222
223 fn dtype(&self) -> &DataType {
225 self._dtype()
226 }
227
228 fn chunks(&self) -> &Vec<ArrayRef>;
230
231 unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef>;
236
237 fn n_chunks(&self) -> usize {
239 self.chunks().len()
240 }
241
242 fn shrink_to_fit(&mut self) {
244 }
246
247 fn limit(&self, num_elements: usize) -> Series {
249 self.slice(0, num_elements)
250 }
251
252 fn slice(&self, _offset: i64, _length: usize) -> Series;
257
258 fn split_at(&self, _offset: i64) -> (Series, Series);
263
264 fn append(&mut self, other: &Series) -> PolarsResult<()>;
265 fn append_owned(&mut self, other: Series) -> PolarsResult<()>;
266
267 #[doc(hidden)]
268 fn extend(&mut self, _other: &Series) -> PolarsResult<()>;
269
270 fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series>;
272
273 fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
279
280 unsafe fn take_unchecked(&self, _idx: &IdxCa) -> Series;
287
288 fn take_slice(&self, _indices: &[IdxSize]) -> PolarsResult<Series>;
292
293 unsafe fn take_slice_unchecked(&self, _idx: &[IdxSize]) -> Series;
298
299 fn len(&self) -> usize;
301
302 fn is_empty(&self) -> bool {
304 self.len() == 0
305 }
306
307 fn rechunk(&self) -> Series;
309
310 fn rechunk_validity(&self) -> Option<Bitmap> {
311 if self.chunks().len() == 1 {
312 return self.chunks()[0].validity().cloned();
313 }
314
315 if !self.has_nulls() || self.is_empty() {
316 return None;
317 }
318
319 let mut bm = BitmapBuilder::with_capacity(self.len());
320 for arr in self.chunks() {
321 if let Some(v) = arr.validity() {
322 bm.extend_from_bitmap(v);
323 } else {
324 bm.extend_constant(arr.len(), true);
325 }
326 }
327 bm.into_opt_validity()
328 }
329
330 fn drop_nulls(&self) -> Series {
332 if self.null_count() == 0 {
333 Series(self.clone_inner())
334 } else {
335 self.filter(&self.is_not_null()).unwrap()
336 }
337 }
338
339 fn _sum_as_f64(&self) -> f64 {
341 invalid_operation_panic!(_sum_as_f64, self)
342 }
343
344 fn mean(&self) -> Option<f64> {
347 None
348 }
349
350 fn std(&self, _ddof: u8) -> Option<f64> {
353 None
354 }
355
356 fn var(&self, _ddof: u8) -> Option<f64> {
359 None
360 }
361
362 fn median(&self) -> Option<f64> {
365 None
366 }
367
368 fn new_from_index(&self, _index: usize, _length: usize) -> Series;
379
380 fn trim_lists_to_normalized_offsets(&self) -> Option<Series> {
385 None
386 }
387
388 fn propagate_nulls(&self) -> Option<Series> {
393 None
394 }
395
396 fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>);
398
399 fn cast(&self, _dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
400
401 fn get(&self, index: usize) -> PolarsResult<AnyValue<'_>> {
404 polars_ensure!(index < self.len(), oob = index, self.len());
405 let value = unsafe { self.get_unchecked(index) };
407 Ok(value)
408 }
409
410 unsafe fn get_unchecked(&self, _index: usize) -> AnyValue<'_>;
418
419 fn sort_with(&self, _options: SortOptions) -> PolarsResult<Series> {
420 polars_bail!(opq = sort_with, self._dtype());
421 }
422
423 #[allow(unused)]
425 fn arg_sort(&self, options: SortOptions) -> IdxCa {
426 invalid_operation_panic!(arg_sort, self)
427 }
428
429 fn null_count(&self) -> usize;
431
432 fn has_nulls(&self) -> bool;
434
435 fn unique(&self) -> PolarsResult<Series> {
437 polars_bail!(opq = unique, self._dtype());
438 }
439
440 fn n_unique(&self) -> PolarsResult<usize> {
444 polars_bail!(opq = n_unique, self._dtype());
445 }
446
447 fn arg_unique(&self) -> PolarsResult<IdxCa> {
449 polars_bail!(opq = arg_unique, self._dtype());
450 }
451
452 fn is_null(&self) -> BooleanChunked;
454
455 fn is_not_null(&self) -> BooleanChunked;
457
458 fn reverse(&self) -> Series;
460
461 fn as_single_ptr(&mut self) -> PolarsResult<usize> {
464 polars_bail!(opq = as_single_ptr, self._dtype());
465 }
466
467 fn shift(&self, _periods: i64) -> Series;
494
495 fn sum_reduce(&self) -> PolarsResult<Scalar> {
500 polars_bail!(opq = sum, self._dtype());
501 }
502 fn max_reduce(&self) -> PolarsResult<Scalar> {
504 polars_bail!(opq = max, self._dtype());
505 }
506 fn min_reduce(&self) -> PolarsResult<Scalar> {
508 polars_bail!(opq = min, self._dtype());
509 }
510 fn median_reduce(&self) -> PolarsResult<Scalar> {
512 polars_bail!(opq = median, self._dtype());
513 }
514 fn var_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
516 polars_bail!(opq = var, self._dtype());
517 }
518 fn std_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
520 polars_bail!(opq = std, self._dtype());
521 }
522 fn quantile_reduce(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Scalar> {
524 polars_bail!(opq = quantile, self._dtype());
525 }
526 fn and_reduce(&self) -> PolarsResult<Scalar> {
528 polars_bail!(opq = and_reduce, self._dtype());
529 }
530 fn or_reduce(&self) -> PolarsResult<Scalar> {
532 polars_bail!(opq = or_reduce, self._dtype());
533 }
534 fn xor_reduce(&self) -> PolarsResult<Scalar> {
536 polars_bail!(opq = xor_reduce, self._dtype());
537 }
538
539 fn first(&self) -> Scalar {
543 let dt = self.dtype();
544 let av = self.get(0).map_or(AnyValue::Null, AnyValue::into_static);
545
546 Scalar::new(dt.clone(), av)
547 }
548
549 fn last(&self) -> Scalar {
553 let dt = self.dtype();
554 let av = if self.len() == 0 {
555 AnyValue::Null
556 } else {
557 unsafe { self.get_unchecked(self.len() - 1) }.into_static()
559 };
560
561 Scalar::new(dt.clone(), av)
562 }
563
564 #[cfg(feature = "approx_unique")]
565 fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
566 polars_bail!(opq = approx_n_unique, self._dtype());
567 }
568
569 fn clone_inner(&self) -> Arc<dyn SeriesTrait>;
571
572 #[cfg(feature = "object")]
573 fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
575 invalid_operation_panic!(get_object, self)
576 }
577
578 #[cfg(feature = "object")]
579 unsafe fn get_object_chunked_unchecked(
584 &self,
585 _chunk: usize,
586 _index: usize,
587 ) -> Option<&dyn PolarsObjectSafe> {
588 invalid_operation_panic!(get_object_chunked_unchecked, self)
589 }
590
591 fn as_any(&self) -> &dyn Any;
594
595 fn as_any_mut(&mut self) -> &mut dyn Any;
598
599 fn as_phys_any(&self) -> &dyn Any;
602
603 fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
604
605 #[cfg(feature = "checked_arithmetic")]
606 fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
607 polars_bail!(opq = checked_div, self._dtype());
608 }
609
610 #[cfg(feature = "rolling_window")]
611 fn rolling_map(
614 &self,
615 _f: &dyn Fn(&Series) -> Series,
616 _options: RollingOptionsFixedWindow,
617 ) -> PolarsResult<Series> {
618 polars_bail!(opq = rolling_map, self._dtype());
619 }
620}
621
622impl (dyn SeriesTrait + '_) {
623 pub fn unpack<T: PolarsPhysicalType>(&self) -> PolarsResult<&ChunkedArray<T>> {
624 polars_ensure!(&T::get_static_dtype() == self.dtype(), unpack);
625 Ok(self.as_ref())
626 }
627}