use std::any::Any;
use std::borrow::Cow;
#[cfg(feature = "temporal")]
use std::sync::Arc;
use polars_arrow::prelude::QuantileInterpolOptions;
#[cfg(feature = "object")]
use crate::chunked_array::object::PolarsObjectSafe;
pub use crate::prelude::ChunkCompare;
use crate::prelude::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IsSorted {
Ascending,
Descending,
Not,
}
macro_rules! invalid_operation {
($s:expr) => {
Err(PolarsError::InvalidOperation(
format!(
"this operation is not implemented/valid for this dtype: {:?}",
$s._dtype()
)
.into(),
))
};
}
macro_rules! invalid_operation_panic {
($s:expr) => {
panic!(
"this operation is not implemented/valid for this dtype: {:?}",
$s._dtype()
)
};
}
pub(crate) mod private {
use ahash::RandomState;
use super::*;
use crate::chunked_array::ops::compare_inner::{PartialEqInner, PartialOrdInner};
#[cfg(feature = "rows")]
use crate::frame::groupby::GroupsProxy;
pub trait PrivateSeriesNumeric {
fn bit_repr_is_large(&self) -> bool {
false
}
fn bit_repr_large(&self) -> UInt64Chunked {
unimplemented!()
}
fn bit_repr_small(&self) -> UInt32Chunked {
unimplemented!()
}
}
pub trait PrivateSeries {
#[cfg(feature = "object")]
fn get_list_builder(
&self,
_name: &str,
_values_capacity: usize,
_list_capacity: usize,
) -> Box<dyn ListBuilderTrait> {
invalid_operation_panic!(self)
}
fn _field(&self) -> Cow<Field> {
invalid_operation_panic!(self)
}
fn _dtype(&self) -> &DataType {
unimplemented!()
}
fn compute_len(&mut self) {
unimplemented!()
}
fn explode_by_offsets(&self, _offsets: &[i64]) -> Series {
invalid_operation_panic!(self)
}
#[cfg(feature = "cum_agg")]
fn _cummax(&self, _reverse: bool) -> Series {
panic!("operation cummax not supported for this dtype")
}
#[cfg(feature = "cum_agg")]
fn _cummin(&self, _reverse: bool) -> Series {
panic!("operation cummin not supported for this dtype")
}
fn _set_sorted(&mut self, _is_sorted: IsSorted) {
invalid_operation_panic!(self)
}
unsafe fn equal_element(
&self,
_idx_self: usize,
_idx_other: usize,
_other: &Series,
) -> bool {
invalid_operation_panic!(self)
}
#[allow(clippy::wrong_self_convention)]
fn into_partial_eq_inner<'a>(&'a self) -> Box<dyn PartialEqInner + 'a> {
invalid_operation_panic!(self)
}
#[allow(clippy::wrong_self_convention)]
fn into_partial_ord_inner<'a>(&'a self) -> Box<dyn PartialOrdInner + 'a> {
invalid_operation_panic!(self)
}
fn vec_hash(&self, _build_hasher: RandomState, _buf: &mut Vec<u64>) -> PolarsResult<()> {
invalid_operation!(self)
}
fn vec_hash_combine(
&self,
_build_hasher: RandomState,
_hashes: &mut [u64],
) -> PolarsResult<()> {
invalid_operation!(self)
}
unsafe fn agg_min(&self, groups: &GroupsProxy) -> Series {
Series::full_null(self._field().name(), groups.len(), self._dtype())
}
unsafe fn agg_max(&self, groups: &GroupsProxy) -> Series {
Series::full_null(self._field().name(), groups.len(), self._dtype())
}
unsafe fn agg_sum(&self, groups: &GroupsProxy) -> Series {
Series::full_null(self._field().name(), groups.len(), self._dtype())
}
unsafe fn agg_std(&self, groups: &GroupsProxy, _ddof: u8) -> Series {
Series::full_null(self._field().name(), groups.len(), self._dtype())
}
unsafe fn agg_var(&self, groups: &GroupsProxy, _ddof: u8) -> Series {
Series::full_null(self._field().name(), groups.len(), self._dtype())
}
unsafe fn agg_list(&self, groups: &GroupsProxy) -> Series {
Series::full_null(self._field().name(), groups.len(), self._dtype())
}
fn zip_outer_join_column(
&self,
_right_column: &Series,
_opt_join_tuples: &[(Option<IdxSize>, Option<IdxSize>)],
) -> Series {
invalid_operation_panic!(self)
}
fn subtract(&self, _rhs: &Series) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn add_to(&self, _rhs: &Series) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn multiply(&self, _rhs: &Series) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn divide(&self, _rhs: &Series) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn remainder(&self, _rhs: &Series) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn group_tuples(&self, _multithreaded: bool, _sorted: bool) -> PolarsResult<GroupsProxy> {
invalid_operation!(self)
}
fn zip_with_same_type(
&self,
_mask: &BooleanChunked,
_other: &Series,
) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
#[cfg(feature = "sort_multiple")]
fn argsort_multiple(&self, _by: &[Series], _reverse: &[bool]) -> PolarsResult<IdxCa> {
Err(PolarsError::InvalidOperation(
"argsort_multiple is not implemented for this Series".into(),
))
}
}
}
pub trait SeriesTrait:
Send + Sync + private::PrivateSeries + private::PrivateSeriesNumeric
{
fn is_sorted(&self) -> IsSorted {
IsSorted::Not
}
fn rename(&mut self, name: &str);
fn bitand(&self, _other: &Series) -> PolarsResult<Series> {
Err(PolarsError::InvalidOperation(
format!(
"bitwise 'AND' operation not supported for dtype {:?}",
self.dtype()
)
.into(),
))
}
fn bitor(&self, _other: &Series) -> PolarsResult<Series> {
Err(PolarsError::InvalidOperation(
format!(
"bitwise 'OR' operation not supported for dtype {:?}",
self.dtype()
)
.into(),
))
}
fn bitxor(&self, _other: &Series) -> PolarsResult<Series> {
Err(PolarsError::InvalidOperation(
format!(
"bitwise 'XOR' operation not supported for dtype {:?}",
self.dtype()
)
.into(),
))
}
fn chunk_lengths(&self) -> ChunkIdIter {
invalid_operation_panic!(self)
}
fn name(&self) -> &str {
invalid_operation_panic!(self)
}
fn field(&self) -> Cow<Field> {
self._field()
}
fn dtype(&self) -> &DataType {
self._dtype()
}
fn chunks(&self) -> &Vec<ArrayRef>;
fn n_chunks(&self) -> usize {
self.chunks().len()
}
fn shrink_to_fit(&mut self) {
panic!("shrink to fit not supported for dtype {:?}", self.dtype())
}
fn limit(&self, num_elements: usize) -> Series {
self.slice(0, num_elements)
}
fn slice(&self, _offset: i64, _length: usize) -> Series {
invalid_operation_panic!(self)
}
#[doc(hidden)]
fn append(&mut self, _other: &Series) -> PolarsResult<()> {
invalid_operation_panic!(self)
}
#[doc(hidden)]
fn extend(&mut self, _other: &Series) -> PolarsResult<()> {
invalid_operation_panic!(self)
}
fn filter(&self, _filter: &BooleanChunked) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
#[doc(hidden)]
#[cfg(feature = "chunked_ids")]
unsafe fn _take_chunked_unchecked(&self, by: &[ChunkId], sorted: IsSorted) -> Series;
#[doc(hidden)]
#[cfg(feature = "chunked_ids")]
unsafe fn _take_opt_chunked_unchecked(&self, by: &[Option<ChunkId>]) -> Series;
fn take_iter(&self, _iter: &mut dyn TakeIterator) -> PolarsResult<Series>;
unsafe fn take_iter_unchecked(&self, _iter: &mut dyn TakeIterator) -> Series;
unsafe fn take_unchecked(&self, _idx: &IdxCa) -> PolarsResult<Series>;
unsafe fn take_opt_iter_unchecked(&self, _iter: &mut dyn TakeIteratorNulls) -> Series;
#[cfg(feature = "take_opt_iter")]
#[cfg_attr(docsrs, doc(cfg(feature = "take_opt_iter")))]
fn take_opt_iter(&self, _iter: &mut dyn TakeIteratorNulls) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn take(&self, _indices: &IdxCa) -> PolarsResult<Series>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn rechunk(&self) -> Series {
invalid_operation_panic!(self)
}
fn take_every(&self, n: usize) -> Series;
fn drop_nulls(&self) -> Series {
if self.null_count() == 0 {
Series(self.clone_inner())
} else {
self.filter(&self.is_not_null()).unwrap()
}
}
fn mean(&self) -> Option<f64> {
None
}
fn median(&self) -> Option<f64> {
None
}
fn new_from_index(&self, _index: usize, _length: usize) -> Series {
invalid_operation_panic!(self)
}
fn cast(&self, _data_type: &DataType) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn get(&self, _index: usize) -> PolarsResult<AnyValue> {
invalid_operation_panic!(self)
}
#[cfg(feature = "private")]
unsafe fn get_unchecked(&self, _index: usize) -> AnyValue {
invalid_operation_panic!(self)
}
fn sort_with(&self, _options: SortOptions) -> Series {
invalid_operation_panic!(self)
}
#[allow(unused)]
fn argsort(&self, options: SortOptions) -> IdxCa {
invalid_operation_panic!(self)
}
fn null_count(&self) -> usize {
invalid_operation_panic!(self)
}
fn has_validity(&self) -> bool;
fn unique(&self) -> PolarsResult<Series> {
invalid_operation!(self)
}
fn n_unique(&self) -> PolarsResult<usize> {
invalid_operation_panic!(self)
}
fn arg_unique(&self) -> PolarsResult<IdxCa> {
invalid_operation_panic!(self)
}
fn arg_min(&self) -> Option<usize> {
None
}
fn arg_max(&self) -> Option<usize> {
None
}
fn is_null(&self) -> BooleanChunked {
invalid_operation_panic!(self)
}
fn is_not_null(&self) -> BooleanChunked {
invalid_operation_panic!(self)
}
fn is_unique(&self) -> PolarsResult<BooleanChunked> {
invalid_operation_panic!(self)
}
fn is_duplicated(&self) -> PolarsResult<BooleanChunked> {
invalid_operation_panic!(self)
}
fn reverse(&self) -> Series {
invalid_operation_panic!(self)
}
fn as_single_ptr(&mut self) -> PolarsResult<usize> {
Err(PolarsError::InvalidOperation(
"operation 'as_single_ptr' not supported".into(),
))
}
fn shift(&self, _periods: i64) -> Series {
invalid_operation_panic!(self)
}
fn fill_null(&self, _strategy: FillNullStrategy) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
fn _sum_as_series(&self) -> Series {
invalid_operation_panic!(self)
}
fn max_as_series(&self) -> Series {
invalid_operation_panic!(self)
}
fn min_as_series(&self) -> Series {
invalid_operation_panic!(self)
}
fn median_as_series(&self) -> Series {
Series::full_null(self.name(), 1, self.dtype())
}
fn var_as_series(&self, _ddof: u8) -> Series {
Series::full_null(self.name(), 1, self.dtype())
}
fn std_as_series(&self, _ddof: u8) -> Series {
Series::full_null(self.name(), 1, self.dtype())
}
fn quantile_as_series(
&self,
_quantile: f64,
_interpol: QuantileInterpolOptions,
) -> PolarsResult<Series> {
Ok(Series::full_null(self.name(), 1, self.dtype()))
}
fn fmt_list(&self) -> String {
"fmt implemented".into()
}
fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
invalid_operation_panic!(self)
}
#[cfg(feature = "object")]
#[cfg_attr(docsrs, doc(cfg(feature = "object")))]
fn get_object(&self, _index: usize) -> Option<&dyn PolarsObjectSafe> {
invalid_operation_panic!(self)
}
fn as_any(&self) -> &dyn Any {
invalid_operation_panic!(self)
}
fn as_any_mut(&mut self) -> &mut dyn Any {
invalid_operation_panic!(self)
}
fn peak_max(&self) -> BooleanChunked {
invalid_operation_panic!(self)
}
fn peak_min(&self) -> BooleanChunked {
invalid_operation_panic!(self)
}
#[cfg(feature = "is_in")]
#[cfg_attr(docsrs, doc(cfg(feature = "is_in")))]
fn is_in(&self, _other: &Series) -> PolarsResult<BooleanChunked> {
invalid_operation_panic!(self)
}
#[cfg(feature = "repeat_by")]
#[cfg_attr(docsrs, doc(cfg(feature = "repeat_by")))]
fn repeat_by(&self, _by: &IdxCa) -> ListChunked {
invalid_operation_panic!(self)
}
#[cfg(feature = "checked_arithmetic")]
#[cfg_attr(docsrs, doc(cfg(feature = "checked_arithmetic")))]
fn checked_div(&self, _rhs: &Series) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
#[cfg(feature = "is_first")]
#[cfg_attr(docsrs, doc(cfg(feature = "is_first")))]
fn is_first(&self) -> PolarsResult<BooleanChunked> {
invalid_operation_panic!(self)
}
#[cfg(feature = "mode")]
#[cfg_attr(docsrs, doc(cfg(feature = "mode")))]
fn mode(&self) -> PolarsResult<Series> {
invalid_operation_panic!(self)
}
#[cfg(feature = "rolling_window")]
#[cfg_attr(docsrs, doc(cfg(feature = "rolling_window")))]
fn rolling_apply(
&self,
_f: &dyn Fn(&Series) -> Series,
_options: RollingOptionsFixedWindow,
) -> PolarsResult<Series> {
panic!("rolling apply not implemented for this dtype. Only implemented for numeric data.")
}
#[cfg(feature = "concat_str")]
#[cfg_attr(docsrs, doc(cfg(feature = "concat_str")))]
fn str_concat(&self, _delimiter: &str) -> Utf8Chunked {
invalid_operation_panic!(self)
}
}
impl<'a> (dyn SeriesTrait + 'a) {
pub fn unpack<N: 'static>(&self) -> PolarsResult<&ChunkedArray<N>>
where
N: PolarsDataType,
{
if &N::get_dtype() == self.dtype() {
Ok(self.as_ref())
} else {
Err(PolarsError::SchemaMisMatch(
"cannot unpack Series; data types don't match".into(),
))
}
}
}