1use arrow::offset::OffsetsBuffer;
3use polars_compute::rolling::QuantileMethod;
4
5use crate::prelude::*;
6
7pub(crate) mod aggregate;
8pub(crate) mod any_value;
9pub(crate) mod append;
10mod apply;
11#[cfg(feature = "approx_unique")]
12mod approx_n_unique;
13pub mod arity;
14mod bit_repr;
15mod bits;
16#[cfg(feature = "bitwise")]
17mod bitwise_reduce;
18pub(crate) mod chunkops;
19pub(crate) mod compare_inner;
20#[cfg(feature = "dtype-decimal")]
21mod decimal;
22pub(crate) mod downcast;
23pub(crate) mod explode;
24mod explode_and_offsets;
25mod extend;
26pub mod fill_null;
27mod filter;
28pub mod float_sorted_arg_max;
29mod for_each;
30pub mod full;
31pub mod gather;
32mod nesting_utils;
33pub(crate) mod nulls;
34mod reverse;
35#[cfg(feature = "rolling_window")]
36pub(crate) mod rolling_window;
37pub mod row_encode;
38pub mod search_sorted;
39mod set;
40mod shift;
41pub mod sort;
42#[cfg(feature = "algorithm_group_by")]
43pub(crate) mod unique;
44#[cfg(feature = "zip_with")]
45pub mod zip;
46
47pub use chunkops::_set_check_length;
48pub use nesting_utils::ChunkNestingUtils;
49#[cfg(feature = "serde-lazy")]
50use serde::{Deserialize, Serialize};
51pub use sort::options::*;
52
53use crate::chunked_array::cast::CastOptions;
54use crate::series::{BitRepr, IsSorted};
55pub trait Reinterpret {
56 fn reinterpret_signed(&self) -> Series {
57 unimplemented!()
58 }
59
60 fn reinterpret_unsigned(&self) -> Series {
61 unimplemented!()
62 }
63}
64
65pub(crate) trait ToBitRepr {
69 fn to_bit_repr(&self) -> BitRepr;
70}
71
72pub trait ChunkAnyValue {
73 unsafe fn get_any_value_unchecked(&self, index: usize) -> AnyValue<'_>;
79
80 fn get_any_value(&self, index: usize) -> PolarsResult<AnyValue<'_>>;
82}
83
84pub trait ChunkAnyValueBypassValidity {
85 unsafe fn get_any_value_bypass_validity(&self, index: usize) -> AnyValue<'_>;
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94#[cfg_attr(feature = "dsl-schema", derive(schemars::JsonSchema))]
95pub struct ExplodeOptions {
96 pub empty_as_null: bool,
98 pub keep_nulls: bool,
100}
101
102pub trait ChunkExplode {
104 fn explode(&self, options: ExplodeOptions) -> PolarsResult<Series> {
105 self.explode_and_offsets(options).map(|t| t.0)
106 }
107 fn offsets(&self) -> PolarsResult<OffsetsBuffer<i64>>;
108 fn explode_and_offsets(
109 &self,
110 options: ExplodeOptions,
111 ) -> PolarsResult<(Series, OffsetsBuffer<i64>)>;
112}
113
114pub trait ChunkBytes {
115 fn to_byte_slices(&self) -> Vec<&[u8]>;
116}
117
118#[cfg(feature = "rolling_window")]
122pub trait ChunkRollApply: AsRefDataType {
123 fn rolling_map(
124 &self,
125 f: &dyn Fn(&Series) -> PolarsResult<Series>,
126 options: RollingOptionsFixedWindow,
127 ) -> PolarsResult<Series>
128 where
129 Self: Sized;
130}
131
132pub trait ChunkTake<Idx: ?Sized>: ChunkTakeUnchecked<Idx> {
133 fn take(&self, indices: &Idx) -> PolarsResult<Self>
135 where
136 Self: Sized;
137}
138
139pub trait ChunkTakeUnchecked<Idx: ?Sized> {
140 unsafe fn take_unchecked(&self, indices: &Idx) -> Self;
145}
146
147pub trait ChunkSet<'a, A, B> {
152 fn scatter_single<I: IntoIterator<Item = IdxSize>>(
164 &'a self,
165 idx: I,
166 opt_value: Option<A>,
167 ) -> PolarsResult<Self>
168 where
169 Self: Sized;
170
171 fn scatter_with<I: IntoIterator<Item = IdxSize>, F>(
183 &'a self,
184 idx: I,
185 f: F,
186 ) -> PolarsResult<Self>
187 where
188 Self: Sized,
189 F: Fn(Option<A>) -> Option<B>;
190 fn set(&'a self, mask: &BooleanChunked, opt_value: Option<A>) -> PolarsResult<Self>
202 where
203 Self: Sized;
204}
205
206pub trait ChunkCast {
208 fn cast(&self, dtype: &DataType) -> PolarsResult<Series> {
210 self.cast_with_options(dtype, CastOptions::NonStrict)
211 }
212
213 fn cast_with_options(&self, dtype: &DataType, options: CastOptions) -> PolarsResult<Series>;
215
216 unsafe fn cast_unchecked(&self, dtype: &DataType) -> PolarsResult<Series>;
222}
223
224pub trait ChunkApply<'a, T> {
227 type FuncRet;
228
229 #[must_use]
243 fn apply_values<F>(&'a self, f: F) -> Self
244 where
245 F: Fn(T) -> Self::FuncRet + Copy;
246
247 #[must_use]
249 fn apply<F>(&'a self, f: F) -> Self
250 where
251 F: Fn(Option<T>) -> Option<Self::FuncRet> + Copy;
252
253 fn apply_to_slice<F, S>(&'a self, f: F, slice: &mut [S])
255 where
257 F: Fn(Option<T>, &S) -> S;
258}
259
260pub trait ChunkAgg<T> {
262 fn sum(&self) -> Option<T> {
266 None
267 }
268
269 fn _sum_as_f64(&self) -> f64;
270
271 fn min(&self) -> Option<T> {
272 None
273 }
274
275 fn max(&self) -> Option<T> {
278 None
279 }
280
281 fn min_max(&self) -> Option<(T, T)> {
282 Some((self.min()?, self.max()?))
283 }
284
285 fn mean(&self) -> Option<f64> {
288 None
289 }
290}
291
292pub trait ChunkQuantile<T> {
294 fn median(&self) -> Option<T> {
297 None
298 }
299 fn quantile(&self, _quantile: f64, _method: QuantileMethod) -> PolarsResult<Option<T>> {
302 Ok(None)
303 }
304}
305
306pub trait ChunkVar {
308 fn var(&self, _ddof: u8) -> Option<f64> {
310 None
311 }
312
313 fn std(&self, _ddof: u8) -> Option<f64> {
315 None
316 }
317}
318
319#[cfg(feature = "bitwise")]
321pub trait ChunkBitwiseReduce {
322 type Physical;
323
324 fn and_reduce(&self) -> Option<Self::Physical>;
325 fn or_reduce(&self) -> Option<Self::Physical>;
326 fn xor_reduce(&self) -> Option<Self::Physical>;
327}
328
329pub trait ChunkCompareEq<Rhs> {
346 type Item;
347
348 fn equal(&self, rhs: Rhs) -> Self::Item;
350
351 fn equal_missing(&self, rhs: Rhs) -> Self::Item;
353
354 fn not_equal(&self, rhs: Rhs) -> Self::Item;
356
357 fn not_equal_missing(&self, rhs: Rhs) -> Self::Item;
359}
360
361pub trait ChunkCompareIneq<Rhs> {
364 type Item;
365
366 fn gt(&self, rhs: Rhs) -> Self::Item;
368
369 fn gt_eq(&self, rhs: Rhs) -> Self::Item;
371
372 fn lt(&self, rhs: Rhs) -> Self::Item;
374
375 fn lt_eq(&self, rhs: Rhs) -> Self::Item;
377}
378
379pub trait ChunkUnique {
381 fn unique(&self) -> PolarsResult<Self>
384 where
385 Self: Sized;
386
387 fn arg_unique(&self) -> PolarsResult<IdxCa>;
390
391 fn n_unique(&self) -> PolarsResult<usize> {
393 self.arg_unique().map(|v| v.len())
394 }
395
396 fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)>;
400}
401
402#[cfg(feature = "approx_unique")]
403pub trait ChunkApproxNUnique {
404 fn approx_n_unique(&self) -> IdxSize;
405}
406
407pub trait ChunkSort<T: PolarsDataType> {
409 #[allow(unused_variables)]
410 fn sort_with(&self, options: SortOptions) -> ChunkedArray<T>;
411
412 fn sort(&self, descending: bool) -> ChunkedArray<T>;
414
415 fn arg_sort(&self, options: SortOptions) -> IdxCa;
417
418 #[allow(unused_variables)]
420 fn arg_sort_multiple(
421 &self,
422 by: &[Column],
423 _options: &SortMultipleOptions,
424 ) -> PolarsResult<IdxCa> {
425 polars_bail!(opq = arg_sort_multiple, T::get_static_dtype());
426 }
427}
428
429pub type FillNullLimit = Option<IdxSize>;
430
431#[derive(Copy, Clone, Debug, PartialEq, Hash)]
432#[cfg_attr(feature = "serde-lazy", derive(Serialize, Deserialize))]
433#[cfg_attr(feature = "dsl-schema", derive(schemars::JsonSchema))]
434pub enum FillNullStrategy {
435 Backward(FillNullLimit),
437 Forward(FillNullLimit),
439 Mean,
441 Min,
443 Max,
445 Zero,
447 One,
449}
450
451impl FillNullStrategy {
452 pub fn is_elementwise(&self) -> bool {
453 matches!(self, Self::One | Self::Zero)
454 }
455}
456
457pub trait ChunkFillNullValue<T> {
459 fn fill_null_with_values(&self, value: T) -> PolarsResult<Self>
461 where
462 Self: Sized;
463}
464
465pub trait ChunkFull<T> {
467 fn full(name: PlSmallStr, value: T, length: usize) -> Self
469 where
470 Self: Sized;
471}
472
473pub trait ChunkFullNull {
474 fn full_null(_name: PlSmallStr, _length: usize) -> Self
475 where
476 Self: Sized;
477}
478
479pub trait ChunkReverse {
481 fn reverse(&self) -> Self;
483}
484
485pub trait ChunkFilter<T: PolarsDataType> {
487 fn filter(&self, filter: &BooleanChunked) -> PolarsResult<ChunkedArray<T>>
498 where
499 Self: Sized;
500}
501
502pub trait ChunkExpandAtIndex<T: PolarsDataType> {
504 fn new_from_index(&self, index: usize, length: usize) -> ChunkedArray<T>;
506}
507
508macro_rules! impl_chunk_expand {
509 ($self:ident, $length:ident, $index:ident) => {{
510 if $self.is_empty() {
511 return $self.clone();
512 }
513 let opt_val = $self.get($index);
514 match opt_val {
515 Some(val) => ChunkedArray::full($self.name().clone(), val, $length),
516 None => ChunkedArray::full_null($self.name().clone(), $length),
517 }
518 }};
519}
520
521impl<T: PolarsNumericType> ChunkExpandAtIndex<T> for ChunkedArray<T>
522where
523 ChunkedArray<T>: ChunkFull<T::Native>,
524{
525 fn new_from_index(&self, index: usize, length: usize) -> ChunkedArray<T> {
526 let mut out = impl_chunk_expand!(self, length, index);
527 out.set_sorted_flag(IsSorted::Ascending);
528 out
529 }
530}
531
532impl ChunkExpandAtIndex<BooleanType> for BooleanChunked {
533 fn new_from_index(&self, index: usize, length: usize) -> BooleanChunked {
534 let mut out = impl_chunk_expand!(self, length, index);
535 out.set_sorted_flag(IsSorted::Ascending);
536 out
537 }
538}
539
540impl ChunkExpandAtIndex<StringType> for StringChunked {
541 fn new_from_index(&self, index: usize, length: usize) -> StringChunked {
542 let mut out = impl_chunk_expand!(self, length, index);
543 out.set_sorted_flag(IsSorted::Ascending);
544 out
545 }
546}
547
548impl ChunkExpandAtIndex<BinaryType> for BinaryChunked {
549 fn new_from_index(&self, index: usize, length: usize) -> BinaryChunked {
550 let mut out = impl_chunk_expand!(self, length, index);
551 out.set_sorted_flag(IsSorted::Ascending);
552 out
553 }
554}
555
556impl ChunkExpandAtIndex<BinaryOffsetType> for BinaryOffsetChunked {
557 fn new_from_index(&self, index: usize, length: usize) -> BinaryOffsetChunked {
558 let mut out = impl_chunk_expand!(self, length, index);
559 out.set_sorted_flag(IsSorted::Ascending);
560 out
561 }
562}
563
564impl ChunkExpandAtIndex<ListType> for ListChunked {
565 fn new_from_index(&self, index: usize, length: usize) -> ListChunked {
566 let opt_val = self.get_as_series(index);
567 match opt_val {
568 Some(val) => {
569 let mut ca = ListChunked::full(self.name().clone(), &val, length);
570 unsafe { ca.to_logical(self.inner_dtype().clone()) };
571 ca
572 },
573 None => {
574 ListChunked::full_null_with_dtype(self.name().clone(), length, self.inner_dtype())
575 },
576 }
577 }
578}
579
580#[cfg(feature = "dtype-struct")]
581impl ChunkExpandAtIndex<StructType> for StructChunked {
582 fn new_from_index(&self, index: usize, length: usize) -> ChunkedArray<StructType> {
583 let (chunk_idx, idx) = self.index_to_chunked_index(index);
584 let chunk = self.downcast_chunks().get(chunk_idx).unwrap();
585 let chunk = if chunk.is_null(idx) {
586 new_null_array(chunk.dtype().clone(), length)
587 } else {
588 let values = chunk
589 .values()
590 .iter()
591 .map(|arr| {
592 let s = Series::try_from((PlSmallStr::EMPTY, arr.clone())).unwrap();
593 let s = s.new_from_index(idx, length);
594 s.chunks()[0].clone()
595 })
596 .collect::<Vec<_>>();
597
598 StructArray::new(chunk.dtype().clone(), length, values, None).boxed()
599 };
600
601 unsafe { self.copy_with_chunks(vec![chunk]) }
603 }
604}
605
606#[cfg(feature = "dtype-array")]
607impl ChunkExpandAtIndex<FixedSizeListType> for ArrayChunked {
608 fn new_from_index(&self, index: usize, length: usize) -> ArrayChunked {
609 let opt_val = self.get_as_series(index);
610 match opt_val {
611 Some(val) => {
612 let mut ca = ArrayChunked::full(self.name().clone(), &val, length);
613 unsafe { ca.to_logical(self.inner_dtype().clone()) };
614 ca
615 },
616 None => ArrayChunked::full_null_with_dtype(
617 self.name().clone(),
618 length,
619 self.inner_dtype(),
620 self.width(),
621 ),
622 }
623 }
624}
625
626#[cfg(feature = "object")]
627impl<T: PolarsObject> ChunkExpandAtIndex<ObjectType<T>> for ObjectChunked<T> {
628 fn new_from_index(&self, index: usize, length: usize) -> ObjectChunked<T> {
629 let opt_val = self.get(index);
630 match opt_val {
631 Some(val) => ObjectChunked::<T>::full(self.name().clone(), val.clone(), length),
632 None => ObjectChunked::<T>::full_null(self.name().clone(), length),
633 }
634 }
635}
636
637pub trait ChunkShiftFill<T: PolarsDataType, V> {
639 fn shift_and_fill(&self, periods: i64, fill_value: V) -> ChunkedArray<T>;
642}
643
644pub trait ChunkShift<T: PolarsDataType> {
645 fn shift(&self, periods: i64) -> ChunkedArray<T>;
646}
647
648pub trait ChunkZip<T: PolarsDataType> {
650 fn zip_with(
653 &self,
654 mask: &BooleanChunked,
655 other: &ChunkedArray<T>,
656 ) -> PolarsResult<ChunkedArray<T>>;
657}
658
659pub trait ChunkApplyKernel<A: Array> {
661 #[must_use]
663 fn apply_kernel(&self, f: &dyn Fn(&A) -> ArrayRef) -> Self;
664
665 fn apply_kernel_cast<S>(&self, f: &dyn Fn(&A) -> ArrayRef) -> ChunkedArray<S>
667 where
668 S: PolarsDataType;
669}
670
671#[cfg(feature = "is_first_distinct")]
672pub trait IsFirstDistinct<T: PolarsDataType> {
674 fn is_first_distinct(&self) -> PolarsResult<BooleanChunked> {
675 polars_bail!(opq = is_first_distinct, T::get_static_dtype());
676 }
677}
678
679#[cfg(feature = "is_last_distinct")]
680pub trait IsLastDistinct<T: PolarsDataType> {
682 fn is_last_distinct(&self) -> PolarsResult<BooleanChunked> {
683 polars_bail!(opq = is_last_distinct, T::get_static_dtype());
684 }
685}