Path: blob/main/crates/polars-core/src/series/ops/downcast.rs
6940 views
#![allow(unsafe_op_in_unsafe_fn)]1use crate::prelude::*;2use crate::series::implementations::null::NullChunked;34macro_rules! unpack_chunked_err {5($series:expr => $name:expr) => {6polars_err!(SchemaMismatch: "invalid series dtype: expected `{}`, got `{}` for series with name `{}`", $name, $series.dtype(), $series.name())7};8}910macro_rules! try_unpack_chunked {11($series:expr, $expected:pat $(if $guard: expr)? => $ca:ty) => {12match $series.dtype() {13$expected $(if $guard)? => {14// Check downcast in debug compiles15#[cfg(debug_assertions)]16{17Some($series.as_ref().as_any().downcast_ref::<$ca>().unwrap())18}19#[cfg(not(debug_assertions))]20unsafe {21Some(&*($series.as_ref() as *const dyn SeriesTrait as *const $ca))22}23},24_ => None,25}26};27}2829impl Series {30/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int8`]31pub fn try_i8(&self) -> Option<&Int8Chunked> {32try_unpack_chunked!(self, DataType::Int8 => Int8Chunked)33}3435/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int16`]36pub fn try_i16(&self) -> Option<&Int16Chunked> {37try_unpack_chunked!(self, DataType::Int16 => Int16Chunked)38}3940/// Unpack to [`ChunkedArray`]41/// ```42/// # use polars_core::prelude::*;43/// let s = Series::new("foo".into(), [1i32 ,2, 3]);44/// let s_squared: Series = s.i32()45/// .unwrap()46/// .into_iter()47/// .map(|opt_v| {48/// match opt_v {49/// Some(v) => Some(v * v),50/// None => None, // null value51/// }52/// }).collect();53/// ```54/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int32`]55pub fn try_i32(&self) -> Option<&Int32Chunked> {56try_unpack_chunked!(self, DataType::Int32 => Int32Chunked)57}5859/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int64`]60pub fn try_i64(&self) -> Option<&Int64Chunked> {61try_unpack_chunked!(self, DataType::Int64 => Int64Chunked)62}6364/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int128`]65#[cfg(feature = "dtype-i128")]66pub fn try_i128(&self) -> Option<&Int128Chunked> {67try_unpack_chunked!(self, DataType::Int128 => Int128Chunked)68}6970/// Unpack to [`ChunkedArray`] of dtype [`DataType::Float32`]71pub fn try_f32(&self) -> Option<&Float32Chunked> {72try_unpack_chunked!(self, DataType::Float32 => Float32Chunked)73}7475/// Unpack to [`ChunkedArray`] of dtype [`DataType::Float64`]76pub fn try_f64(&self) -> Option<&Float64Chunked> {77try_unpack_chunked!(self, DataType::Float64 => Float64Chunked)78}7980/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt8`]81pub fn try_u8(&self) -> Option<&UInt8Chunked> {82try_unpack_chunked!(self, DataType::UInt8 => UInt8Chunked)83}8485/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt16`]86pub fn try_u16(&self) -> Option<&UInt16Chunked> {87try_unpack_chunked!(self, DataType::UInt16 => UInt16Chunked)88}8990/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt32`]91pub fn try_u32(&self) -> Option<&UInt32Chunked> {92try_unpack_chunked!(self, DataType::UInt32 => UInt32Chunked)93}9495/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt64`]96pub fn try_u64(&self) -> Option<&UInt64Chunked> {97try_unpack_chunked!(self, DataType::UInt64 => UInt64Chunked)98}99100/// Unpack to [`ChunkedArray`] of dtype [`DataType::Boolean`]101pub fn try_bool(&self) -> Option<&BooleanChunked> {102try_unpack_chunked!(self, DataType::Boolean => BooleanChunked)103}104105/// Unpack to [`ChunkedArray`] of dtype [`DataType::String`]106pub fn try_str(&self) -> Option<&StringChunked> {107try_unpack_chunked!(self, DataType::String => StringChunked)108}109110/// Unpack to [`ChunkedArray`] of dtype [`DataType::Binary`]111pub fn try_binary(&self) -> Option<&BinaryChunked> {112try_unpack_chunked!(self, DataType::Binary => BinaryChunked)113}114115/// Unpack to [`ChunkedArray`] of dtype [`DataType::Binary`]116pub fn try_binary_offset(&self) -> Option<&BinaryOffsetChunked> {117try_unpack_chunked!(self, DataType::BinaryOffset => BinaryOffsetChunked)118}119120/// Unpack to [`ChunkedArray`] of dtype [`DataType::Time`]121#[cfg(feature = "dtype-time")]122pub fn try_time(&self) -> Option<&TimeChunked> {123try_unpack_chunked!(self, DataType::Time => TimeChunked)124}125126/// Unpack to [`ChunkedArray`] of dtype [`DataType::Date`]127#[cfg(feature = "dtype-date")]128pub fn try_date(&self) -> Option<&DateChunked> {129try_unpack_chunked!(self, DataType::Date => DateChunked)130}131132/// Unpack to [`ChunkedArray`] of dtype [`DataType::Datetime`]133#[cfg(feature = "dtype-datetime")]134pub fn try_datetime(&self) -> Option<&DatetimeChunked> {135try_unpack_chunked!(self, DataType::Datetime(_, _) => DatetimeChunked)136}137138/// Unpack to [`ChunkedArray`] of dtype [`DataType::Duration`]139#[cfg(feature = "dtype-duration")]140pub fn try_duration(&self) -> Option<&DurationChunked> {141try_unpack_chunked!(self, DataType::Duration(_) => DurationChunked)142}143144/// Unpack to [`ChunkedArray`] of dtype [`DataType::Decimal`]145#[cfg(feature = "dtype-decimal")]146pub fn try_decimal(&self) -> Option<&DecimalChunked> {147try_unpack_chunked!(self, DataType::Decimal(_, _) => DecimalChunked)148}149150/// Unpack to [`ChunkedArray`] of dtype list151pub fn try_list(&self) -> Option<&ListChunked> {152try_unpack_chunked!(self, DataType::List(_) => ListChunked)153}154155/// Unpack to [`ChunkedArray`] of dtype [`DataType::Array`]156#[cfg(feature = "dtype-array")]157pub fn try_array(&self) -> Option<&ArrayChunked> {158try_unpack_chunked!(self, DataType::Array(_, _) => ArrayChunked)159}160161#[cfg(feature = "dtype-categorical")]162pub fn try_cat<T: PolarsCategoricalType>(&self) -> Option<&CategoricalChunked<T>> {163try_unpack_chunked!(self, dt @ DataType::Enum(_, _) | dt @ DataType::Categorical(_, _) if dt.cat_physical().unwrap() == T::physical() => CategoricalChunked<T>)164}165166/// Unpack to [`ChunkedArray`] of dtype [`DataType::Categorical`] or [`DataType::Enum`] with a physical type of UInt8.167#[cfg(feature = "dtype-categorical")]168pub fn try_cat8(&self) -> Option<&Categorical8Chunked> {169self.try_cat::<Categorical8Type>()170}171172#[cfg(feature = "dtype-categorical")]173pub fn try_cat16(&self) -> Option<&Categorical16Chunked> {174self.try_cat::<Categorical16Type>()175}176177#[cfg(feature = "dtype-categorical")]178pub fn try_cat32(&self) -> Option<&Categorical32Chunked> {179self.try_cat::<Categorical32Type>()180}181182/// Unpack to [`ChunkedArray`] of dtype [`DataType::Struct`]183#[cfg(feature = "dtype-struct")]184pub fn try_struct(&self) -> Option<&StructChunked> {185#[cfg(debug_assertions)]186{187if let DataType::Struct(_) = self.dtype() {188let any = self.as_any();189assert!(any.is::<StructChunked>());190}191}192try_unpack_chunked!(self, DataType::Struct(_) => StructChunked)193}194195/// Unpack to [`ChunkedArray`] of dtype [`DataType::Null`]196pub fn try_null(&self) -> Option<&NullChunked> {197try_unpack_chunked!(self, DataType::Null => NullChunked)198}199/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int8`]200pub fn i8(&self) -> PolarsResult<&Int8Chunked> {201self.try_i8()202.ok_or_else(|| unpack_chunked_err!(self => "Int8"))203}204205/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int16`]206pub fn i16(&self) -> PolarsResult<&Int16Chunked> {207self.try_i16()208.ok_or_else(|| unpack_chunked_err!(self => "Int16"))209}210211/// Unpack to [`ChunkedArray`]212/// ```213/// # use polars_core::prelude::*;214/// let s = Series::new("foo".into(), [1i32 ,2, 3]);215/// let s_squared: Series = s.i32()216/// .unwrap()217/// .into_iter()218/// .map(|opt_v| {219/// match opt_v {220/// Some(v) => Some(v * v),221/// None => None, // null value222/// }223/// }).collect();224/// ```225/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int32`]226pub fn i32(&self) -> PolarsResult<&Int32Chunked> {227self.try_i32()228.ok_or_else(|| unpack_chunked_err!(self => "Int32"))229}230231/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int64`]232pub fn i64(&self) -> PolarsResult<&Int64Chunked> {233self.try_i64()234.ok_or_else(|| unpack_chunked_err!(self => "Int64"))235}236237/// Unpack to [`ChunkedArray`] of dtype [`DataType::Int128`]238#[cfg(feature = "dtype-i128")]239pub fn i128(&self) -> PolarsResult<&Int128Chunked> {240self.try_i128()241.ok_or_else(|| unpack_chunked_err!(self => "Int128"))242}243244/// Unpack to [`ChunkedArray`] of dtype [`DataType::Float32`]245pub fn f32(&self) -> PolarsResult<&Float32Chunked> {246self.try_f32()247.ok_or_else(|| unpack_chunked_err!(self => "Float32"))248}249250/// Unpack to [`ChunkedArray`] of dtype [`DataType::Float64`]251pub fn f64(&self) -> PolarsResult<&Float64Chunked> {252self.try_f64()253.ok_or_else(|| unpack_chunked_err!(self => "Float64"))254}255256/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt8`]257pub fn u8(&self) -> PolarsResult<&UInt8Chunked> {258self.try_u8()259.ok_or_else(|| unpack_chunked_err!(self => "UInt8"))260}261262/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt16`]263pub fn u16(&self) -> PolarsResult<&UInt16Chunked> {264self.try_u16()265.ok_or_else(|| unpack_chunked_err!(self => "UInt16"))266}267268/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt32`]269pub fn u32(&self) -> PolarsResult<&UInt32Chunked> {270self.try_u32()271.ok_or_else(|| unpack_chunked_err!(self => "UInt32"))272}273274/// Unpack to [`ChunkedArray`] of dtype [`DataType::UInt64`]275pub fn u64(&self) -> PolarsResult<&UInt64Chunked> {276self.try_u64()277.ok_or_else(|| unpack_chunked_err!(self => "UInt64"))278}279280/// Unpack to [`ChunkedArray`] of dtype [`DataType::Boolean`]281pub fn bool(&self) -> PolarsResult<&BooleanChunked> {282self.try_bool()283.ok_or_else(|| unpack_chunked_err!(self => "Boolean"))284}285286/// Unpack to [`ChunkedArray`] of dtype [`DataType::String`]287pub fn str(&self) -> PolarsResult<&StringChunked> {288self.try_str()289.ok_or_else(|| unpack_chunked_err!(self => "String"))290}291292/// Unpack to [`ChunkedArray`] of dtype [`DataType::Binary`]293pub fn binary(&self) -> PolarsResult<&BinaryChunked> {294self.try_binary()295.ok_or_else(|| unpack_chunked_err!(self => "Binary"))296}297298/// Unpack to [`ChunkedArray`] of dtype [`DataType::Binary`]299pub fn binary_offset(&self) -> PolarsResult<&BinaryOffsetChunked> {300self.try_binary_offset()301.ok_or_else(|| unpack_chunked_err!(self => "BinaryOffset"))302}303304/// Unpack to [`ChunkedArray`] of dtype [`DataType::Time`]305#[cfg(feature = "dtype-time")]306pub fn time(&self) -> PolarsResult<&TimeChunked> {307self.try_time()308.ok_or_else(|| unpack_chunked_err!(self => "Time"))309}310311/// Unpack to [`ChunkedArray`] of dtype [`DataType::Date`]312#[cfg(feature = "dtype-date")]313pub fn date(&self) -> PolarsResult<&DateChunked> {314self.try_date()315.ok_or_else(|| unpack_chunked_err!(self => "Date"))316}317318/// Unpack to [`ChunkedArray`] of dtype [`DataType::Datetime`]319#[cfg(feature = "dtype-datetime")]320pub fn datetime(&self) -> PolarsResult<&DatetimeChunked> {321self.try_datetime()322.ok_or_else(|| unpack_chunked_err!(self => "Datetime"))323}324325/// Unpack to [`ChunkedArray`] of dtype [`DataType::Duration`]326#[cfg(feature = "dtype-duration")]327pub fn duration(&self) -> PolarsResult<&DurationChunked> {328self.try_duration()329.ok_or_else(|| unpack_chunked_err!(self => "Duration"))330}331332/// Unpack to [`ChunkedArray`] of dtype [`DataType::Decimal`]333#[cfg(feature = "dtype-decimal")]334pub fn decimal(&self) -> PolarsResult<&DecimalChunked> {335self.try_decimal()336.ok_or_else(|| unpack_chunked_err!(self => "Decimal"))337}338339/// Unpack to [`ChunkedArray`] of dtype list340pub fn list(&self) -> PolarsResult<&ListChunked> {341self.try_list()342.ok_or_else(|| unpack_chunked_err!(self => "List"))343}344345/// Unpack to [`ChunkedArray`] of dtype [`DataType::Array`]346#[cfg(feature = "dtype-array")]347pub fn array(&self) -> PolarsResult<&ArrayChunked> {348self.try_array()349.ok_or_else(|| unpack_chunked_err!(self => "Array"))350}351352/// Unpack to [`ChunkedArray`] of dtype [`DataType::Categorical`] or [`DataType::Enum`].353#[cfg(feature = "dtype-categorical")]354pub fn cat<T: PolarsCategoricalType>(&self) -> PolarsResult<&CategoricalChunked<T>> {355self.try_cat::<T>()356.ok_or_else(|| unpack_chunked_err!(self => "Enum | Categorical"))357}358359/// Unpack to [`ChunkedArray`] of dtype [`DataType::Categorical`] or [`DataType::Enum`] with a physical type of UInt8.360#[cfg(feature = "dtype-categorical")]361pub fn cat8(&self) -> PolarsResult<&CategoricalChunked<Categorical8Type>> {362self.try_cat8()363.ok_or_else(|| unpack_chunked_err!(self => "Enum8 | Categorical8"))364}365366/// Unpack to [`ChunkedArray`] of dtype [`DataType::Categorical`] or [`DataType::Enum`] with a physical type of UInt16.367#[cfg(feature = "dtype-categorical")]368pub fn cat16(&self) -> PolarsResult<&CategoricalChunked<Categorical16Type>> {369self.try_cat16()370.ok_or_else(|| unpack_chunked_err!(self => "Enum16 | Categorical16"))371}372373/// Unpack to [`ChunkedArray`] of dtype [`DataType::Categorical`] or [`DataType::Enum`] with a physical type of UInt32.374#[cfg(feature = "dtype-categorical")]375pub fn cat32(&self) -> PolarsResult<&CategoricalChunked<Categorical32Type>> {376self.try_cat32()377.ok_or_else(|| unpack_chunked_err!(self => "Enum32 | Categorical32"))378}379380/// Unpack to [`ChunkedArray`] of dtype [`DataType::Struct`]381#[cfg(feature = "dtype-struct")]382pub fn struct_(&self) -> PolarsResult<&StructChunked> {383#[cfg(debug_assertions)]384{385if let DataType::Struct(_) = self.dtype() {386let any = self.as_any();387assert!(any.is::<StructChunked>());388}389}390391self.try_struct()392.ok_or_else(|| unpack_chunked_err!(self => "Struct"))393}394395/// Unpack to [`ChunkedArray`] of dtype [`DataType::Null`]396pub fn null(&self) -> PolarsResult<&NullChunked> {397self.try_null()398.ok_or_else(|| unpack_chunked_err!(self => "Null"))399}400}401402403