1use std::any::Any;
2use std::borrow::Cow;
3
4use arrow::bitmap::{Bitmap, BitmapBuilder};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use crate::chunked_array::cast::CastOptions;
9#[cfg(feature = "object")]
10use crate::chunked_array::object::PolarsObjectSafe;
11use crate::prelude::*;
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
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 Small(UInt32Chunked),
34 Large(UInt64Chunked),
35}
36
37pub(crate) mod private {
38 use super::*;
39 use crate::chunked_array::flags::StatisticsFlags;
40 use crate::chunked_array::ops::compare_inner::{TotalEqInner, TotalOrdInner};
41
42 pub trait PrivateSeriesNumeric {
43 fn bit_repr(&self) -> Option<BitRepr>;
47 }
48
49 pub trait PrivateSeries {
50 #[cfg(feature = "object")]
51 fn get_list_builder(
52 &self,
53 _name: PlSmallStr,
54 _values_capacity: usize,
55 _list_capacity: usize,
56 ) -> Box<dyn ListBuilderTrait> {
57 invalid_operation_panic!(get_list_builder, self)
58 }
59
60 fn _field(&self) -> Cow<Field>;
62
63 fn _dtype(&self) -> &DataType;
64
65 fn compute_len(&mut self);
66
67 fn _get_flags(&self) -> StatisticsFlags;
68
69 fn _set_flags(&mut self, flags: StatisticsFlags);
70
71 unsafe fn equal_element(
72 &self,
73 _idx_self: usize,
74 _idx_other: usize,
75 _other: &Series,
76 ) -> bool {
77 invalid_operation_panic!(equal_element, self)
78 }
79 #[expect(clippy::wrong_self_convention)]
80 fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a>;
81 #[expect(clippy::wrong_self_convention)]
82 fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a>;
83
84 fn vec_hash(&self, _build_hasher: PlRandomState, _buf: &mut Vec<u64>) -> PolarsResult<()> {
85 polars_bail!(opq = vec_hash, self._dtype());
86 }
87 fn vec_hash_combine(
88 &self,
89 _build_hasher: PlRandomState,
90 _hashes: &mut [u64],
91 ) -> PolarsResult<()> {
92 polars_bail!(opq = vec_hash_combine, self._dtype());
93 }
94
95 #[cfg(feature = "algorithm_group_by")]
99 unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
100 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
101 }
102 #[cfg(feature = "algorithm_group_by")]
106 unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
107 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
108 }
109 #[cfg(feature = "algorithm_group_by")]
112 unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
113 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
114 }
115 #[cfg(feature = "algorithm_group_by")]
119 unsafe fn agg_std(&self, groups: &GroupsType, _ddof: u8) -> Series {
120 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
121 }
122 #[cfg(feature = "algorithm_group_by")]
126 unsafe fn agg_var(&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_list(&self, groups: &GroupsType) -> Series {
134 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
135 }
136
137 #[cfg(feature = "bitwise")]
141 unsafe fn agg_and(&self, groups: &GroupsType) -> Series {
142 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
143 }
144
145 #[cfg(feature = "bitwise")]
149 unsafe fn agg_or(&self, groups: &GroupsType) -> Series {
150 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
151 }
152
153 #[cfg(feature = "bitwise")]
157 unsafe fn agg_xor(&self, groups: &GroupsType) -> Series {
158 Series::full_null(self._field().name().clone(), groups.len(), self._dtype())
159 }
160
161 fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
162 polars_bail!(opq = subtract, self._dtype());
163 }
164 fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
165 polars_bail!(opq = add, self._dtype());
166 }
167 fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
168 polars_bail!(opq = multiply, self._dtype());
169 }
170 fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
171 polars_bail!(opq = divide, self._dtype());
172 }
173 fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
174 polars_bail!(opq = remainder, self._dtype());
175 }
176 #[cfg(feature = "algorithm_group_by")]
177 fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsType> {
178 polars_bail!(opq = group_tuples, self._dtype());
179 }
180 #[cfg(feature = "zip_with")]
181 fn zip_with_same_type(
182 &self,
183 _mask: &BooleanChunked,
184 _other: &Series,
185 ) -> PolarsResult<Series> {
186 polars_bail!(opq = zip_with_same_type, self._dtype());
187 }
188
189 #[allow(unused_variables)]
190 fn arg_sort_multiple(
191 &self,
192 by: &[Column],
193 _options: &SortMultipleOptions,
194 ) -> PolarsResult<IdxCa> {
195 polars_bail!(opq = arg_sort_multiple, self._dtype());
196 }
197 }
198}
199
200pub trait SeriesTrait:
201 Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
202{
203 fn rename(&mut self, name: PlSmallStr);
205
206 fn chunk_lengths(&self) -> ChunkLenIter;
208
209 fn name(&self) -> &PlSmallStr;
211
212 fn field(&self) -> Cow<Field> {
214 self._field()
215 }
216
217 fn dtype(&self) -> &DataType {
219 self._dtype()
220 }
221
222 fn chunks(&self) -> &Vec<ArrayRef>;
224
225 unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef>;
230
231 fn n_chunks(&self) -> usize {
233 self.chunks().len()
234 }
235
236 fn shrink_to_fit(&mut self) {
238 }
240
241 fn limit(&self, num_elements: usize) -> Series {
243 self.slice(0, num_elements)
244 }
245
246 fn slice(&self, _offset: i64, _length: usize) -> Series;
251
252 fn split_at(&self, _offset: i64) -> (Series, Series);
257
258 fn append(&mut self, other: &Series) -> PolarsResult<()>;
259 fn append_owned(&mut self, other: Series) -> PolarsResult<()>;
260
261 #[doc(hidden)]
262 fn extend(&mut self, _other: &Series) -> PolarsResult<()>;
263
264 fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series>;
266
267 fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
273
274 unsafe fn take_unchecked(&self, _idx: &IdxCa) -> Series;
281
282 fn take_slice(&self, _indices: &[IdxSize]) -> PolarsResult<Series>;
286
287 unsafe fn take_slice_unchecked(&self, _idx: &[IdxSize]) -> Series;
292
293 fn len(&self) -> usize;
295
296 fn is_empty(&self) -> bool {
298 self.len() == 0
299 }
300
301 fn rechunk(&self) -> Series;
303
304 fn rechunk_validity(&self) -> Option<Bitmap> {
305 if self.chunks().len() == 1 {
306 return self.chunks()[0].validity().cloned();
307 }
308
309 if !self.has_nulls() || self.is_empty() {
310 return None;
311 }
312
313 let mut bm = BitmapBuilder::with_capacity(self.len());
314 for arr in self.chunks() {
315 if let Some(v) = arr.validity() {
316 bm.extend_from_bitmap(v);
317 } else {
318 bm.extend_constant(arr.len(), true);
319 }
320 }
321 bm.into_opt_validity()
322 }
323
324 fn drop_nulls(&self) -> Series {
326 if self.null_count() == 0 {
327 Series(self.clone_inner())
328 } else {
329 self.filter(&self.is_not_null()).unwrap()
330 }
331 }
332
333 fn _sum_as_f64(&self) -> f64 {
335 invalid_operation_panic!(_sum_as_f64, self)
336 }
337
338 fn mean(&self) -> Option<f64> {
341 None
342 }
343
344 fn std(&self, _ddof: u8) -> Option<f64> {
347 None
348 }
349
350 fn var(&self, _ddof: u8) -> Option<f64> {
353 None
354 }
355
356 fn median(&self) -> Option<f64> {
359 None
360 }
361
362 fn new_from_index(&self, _index: usize, _length: usize) -> Series;
373
374 fn cast(&self, _dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
375
376 fn get(&self, index: usize) -> PolarsResult<AnyValue> {
379 polars_ensure!(index < self.len(), oob = index, self.len());
380 let value = unsafe { self.get_unchecked(index) };
382 Ok(value)
383 }
384
385 unsafe fn get_unchecked(&self, _index: usize) -> AnyValue;
393
394 fn sort_with(&self, _options: SortOptions) -> PolarsResult<Series> {
395 polars_bail!(opq = sort_with, self._dtype());
396 }
397
398 #[allow(unused)]
400 fn arg_sort(&self, options: SortOptions) -> IdxCa {
401 invalid_operation_panic!(arg_sort, self)
402 }
403
404 fn null_count(&self) -> usize;
406
407 fn has_nulls(&self) -> bool;
409
410 fn unique(&self) -> PolarsResult<Series> {
412 polars_bail!(opq = unique, self._dtype());
413 }
414
415 fn n_unique(&self) -> PolarsResult<usize> {
419 polars_bail!(opq = n_unique, self._dtype());
420 }
421
422 fn arg_unique(&self) -> PolarsResult<IdxCa> {
424 polars_bail!(opq = arg_unique, self._dtype());
425 }
426
427 fn is_null(&self) -> BooleanChunked;
429
430 fn is_not_null(&self) -> BooleanChunked;
432
433 fn reverse(&self) -> Series;
435
436 fn as_single_ptr(&mut self) -> PolarsResult<usize> {
439 polars_bail!(opq = as_single_ptr, self._dtype());
440 }
441
442 fn shift(&self, _periods: i64) -> Series;
469
470 fn sum_reduce(&self) -> PolarsResult<Scalar> {
475 polars_bail!(opq = sum, self._dtype());
476 }
477 fn max_reduce(&self) -> PolarsResult<Scalar> {
479 polars_bail!(opq = max, self._dtype());
480 }
481 fn min_reduce(&self) -> PolarsResult<Scalar> {
483 polars_bail!(opq = min, self._dtype());
484 }
485 fn median_reduce(&self) -> PolarsResult<Scalar> {
487 polars_bail!(opq = median, self._dtype());
488 }
489 fn var_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
491 polars_bail!(opq = var, self._dtype());
492 }
493 fn std_reduce(&self, _ddof: u8) -> PolarsResult<Scalar> {
495 polars_bail!(opq = std, self._dtype());
496 }
497 fn quantile_reduce(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Scalar> {
499 polars_bail!(opq = quantile, self._dtype());
500 }
501 fn and_reduce(&self) -> PolarsResult<Scalar> {
503 polars_bail!(opq = and_reduce, self._dtype());
504 }
505 fn or_reduce(&self) -> PolarsResult<Scalar> {
507 polars_bail!(opq = or_reduce, self._dtype());
508 }
509 fn xor_reduce(&self) -> PolarsResult<Scalar> {
511 polars_bail!(opq = xor_reduce, self._dtype());
512 }
513
514 fn first(&self) -> Scalar {
518 let dt = self.dtype();
519 let av = self.get(0).map_or(AnyValue::Null, AnyValue::into_static);
520
521 Scalar::new(dt.clone(), av)
522 }
523
524 fn last(&self) -> Scalar {
528 let dt = self.dtype();
529 let av = if self.len() == 0 {
530 AnyValue::Null
531 } else {
532 unsafe { self.get_unchecked(self.len() - 1) }.into_static()
534 };
535
536 Scalar::new(dt.clone(), av)
537 }
538
539 #[cfg(feature = "approx_unique")]
540 fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
541 polars_bail!(opq = approx_n_unique, self._dtype());
542 }
543
544 fn clone_inner(&self) -> Arc<dyn SeriesTrait>;
546
547 #[cfg(feature = "object")]
548 fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
550 invalid_operation_panic!(get_object, self)
551 }
552
553 #[cfg(feature = "object")]
554 unsafe fn get_object_chunked_unchecked(
559 &self,
560 _chunk: usize,
561 _index: usize,
562 ) -> Option<&dyn PolarsObjectSafe> {
563 invalid_operation_panic!(get_object_chunked_unchecked, self)
564 }
565
566 fn as_any(&self) -> &dyn Any;
569
570 fn as_any_mut(&mut self) -> &mut dyn Any;
573
574 fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
575
576 #[cfg(feature = "checked_arithmetic")]
577 fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
578 polars_bail!(opq = checked_div, self._dtype());
579 }
580
581 #[cfg(feature = "rolling_window")]
582 fn rolling_map(
585 &self,
586 _f: &dyn Fn(&Series) -> Series,
587 _options: RollingOptionsFixedWindow,
588 ) -> PolarsResult<Series> {
589 polars_bail!(opq = rolling_map, self._dtype());
590 }
591}
592
593impl (dyn SeriesTrait + '_) {
594 pub fn unpack<N>(&self) -> PolarsResult<&ChunkedArray<N>>
595 where
596 N: 'static + PolarsDataType<IsLogical = FalseT>,
597 {
598 polars_ensure!(&N::get_dtype() == self.dtype(), unpack);
599 Ok(self.as_ref())
600 }
601}