polars_core/series/ops/
downcast.rs1#![allow(unsafe_op_in_unsafe_fn)]
2use crate::prelude::*;
3use crate::series::implementations::null::NullChunked;
4
5macro_rules! unpack_chunked_err {
6    ($series:expr => $name:expr) => {
7        polars_err!(SchemaMismatch: "invalid series dtype: expected `{}`, got `{}` for series with name `{}`", $name, $series.dtype(), $series.name())
8    };
9}
10
11macro_rules! try_unpack_chunked {
12    ($series:expr, $expected:pat => $ca:ty) => {
13        match $series.dtype() {
14            $expected => {
15                #[cfg(debug_assertions)]
17                {
18                    Some($series.as_ref().as_any().downcast_ref::<$ca>().unwrap())
19                }
20                #[cfg(not(debug_assertions))]
21                unsafe {
22                    Some(&*($series.as_ref() as *const dyn SeriesTrait as *const $ca))
23                }
24            },
25            _ => None,
26        }
27    };
28}
29
30impl Series {
31    pub fn try_i8(&self) -> Option<&Int8Chunked> {
33        try_unpack_chunked!(self, DataType::Int8 => Int8Chunked)
34    }
35
36    pub fn try_i16(&self) -> Option<&Int16Chunked> {
38        try_unpack_chunked!(self, DataType::Int16 => Int16Chunked)
39    }
40
41    pub fn try_i32(&self) -> Option<&Int32Chunked> {
57        try_unpack_chunked!(self, DataType::Int32 => Int32Chunked)
58    }
59
60    pub fn try_i64(&self) -> Option<&Int64Chunked> {
62        try_unpack_chunked!(self, DataType::Int64 => Int64Chunked)
63    }
64
65    #[cfg(feature = "dtype-i128")]
67    pub fn try_i128(&self) -> Option<&Int128Chunked> {
68        try_unpack_chunked!(self, DataType::Int128 => Int128Chunked)
69    }
70
71    pub fn try_f32(&self) -> Option<&Float32Chunked> {
73        try_unpack_chunked!(self, DataType::Float32 => Float32Chunked)
74    }
75
76    pub fn try_f64(&self) -> Option<&Float64Chunked> {
78        try_unpack_chunked!(self, DataType::Float64 => Float64Chunked)
79    }
80
81    pub fn try_u8(&self) -> Option<&UInt8Chunked> {
83        try_unpack_chunked!(self, DataType::UInt8 => UInt8Chunked)
84    }
85
86    pub fn try_u16(&self) -> Option<&UInt16Chunked> {
88        try_unpack_chunked!(self, DataType::UInt16 => UInt16Chunked)
89    }
90
91    pub fn try_u32(&self) -> Option<&UInt32Chunked> {
93        try_unpack_chunked!(self, DataType::UInt32 => UInt32Chunked)
94    }
95
96    pub fn try_u64(&self) -> Option<&UInt64Chunked> {
98        try_unpack_chunked!(self, DataType::UInt64 => UInt64Chunked)
99    }
100
101    pub fn try_bool(&self) -> Option<&BooleanChunked> {
103        try_unpack_chunked!(self, DataType::Boolean => BooleanChunked)
104    }
105
106    pub fn try_str(&self) -> Option<&StringChunked> {
108        try_unpack_chunked!(self, DataType::String => StringChunked)
109    }
110
111    pub fn try_binary(&self) -> Option<&BinaryChunked> {
113        try_unpack_chunked!(self, DataType::Binary => BinaryChunked)
114    }
115
116    pub fn try_binary_offset(&self) -> Option<&BinaryOffsetChunked> {
118        try_unpack_chunked!(self, DataType::BinaryOffset => BinaryOffsetChunked)
119    }
120
121    #[cfg(feature = "dtype-time")]
123    pub fn try_time(&self) -> Option<&TimeChunked> {
124        try_unpack_chunked!(self, DataType::Time => TimeChunked)
125    }
126
127    #[cfg(feature = "dtype-date")]
129    pub fn try_date(&self) -> Option<&DateChunked> {
130        try_unpack_chunked!(self, DataType::Date => DateChunked)
131    }
132
133    #[cfg(feature = "dtype-datetime")]
135    pub fn try_datetime(&self) -> Option<&DatetimeChunked> {
136        try_unpack_chunked!(self, DataType::Datetime(_, _) => DatetimeChunked)
137    }
138
139    #[cfg(feature = "dtype-duration")]
141    pub fn try_duration(&self) -> Option<&DurationChunked> {
142        try_unpack_chunked!(self, DataType::Duration(_) => DurationChunked)
143    }
144
145    #[cfg(feature = "dtype-decimal")]
147    pub fn try_decimal(&self) -> Option<&DecimalChunked> {
148        try_unpack_chunked!(self, DataType::Decimal(_, _) => DecimalChunked)
149    }
150
151    pub fn try_list(&self) -> Option<&ListChunked> {
153        try_unpack_chunked!(self, DataType::List(_) => ListChunked)
154    }
155
156    #[cfg(feature = "dtype-array")]
158    pub fn try_array(&self) -> Option<&ArrayChunked> {
159        try_unpack_chunked!(self, DataType::Array(_, _) => ArrayChunked)
160    }
161
162    #[cfg(feature = "dtype-categorical")]
164    pub fn try_categorical(&self) -> Option<&CategoricalChunked> {
165        try_unpack_chunked!(self, DataType::Categorical(_, _) | DataType::Enum(_, _) => CategoricalChunked)
166    }
167
168    #[cfg(feature = "dtype-struct")]
170    pub fn try_struct(&self) -> Option<&StructChunked> {
171        #[cfg(debug_assertions)]
172        {
173            if let DataType::Struct(_) = self.dtype() {
174                let any = self.as_any();
175                assert!(any.is::<StructChunked>());
176            }
177        }
178        try_unpack_chunked!(self, DataType::Struct(_) => StructChunked)
179    }
180
181    pub fn try_null(&self) -> Option<&NullChunked> {
183        try_unpack_chunked!(self, DataType::Null => NullChunked)
184    }
185    pub fn i8(&self) -> PolarsResult<&Int8Chunked> {
187        self.try_i8()
188            .ok_or_else(|| unpack_chunked_err!(self => "Int8"))
189    }
190
191    pub fn i16(&self) -> PolarsResult<&Int16Chunked> {
193        self.try_i16()
194            .ok_or_else(|| unpack_chunked_err!(self => "Int16"))
195    }
196
197    pub fn i32(&self) -> PolarsResult<&Int32Chunked> {
213        self.try_i32()
214            .ok_or_else(|| unpack_chunked_err!(self => "Int32"))
215    }
216
217    pub fn i64(&self) -> PolarsResult<&Int64Chunked> {
219        self.try_i64()
220            .ok_or_else(|| unpack_chunked_err!(self => "Int64"))
221    }
222
223    #[cfg(feature = "dtype-i128")]
225    pub fn i128(&self) -> PolarsResult<&Int128Chunked> {
226        self.try_i128()
227            .ok_or_else(|| unpack_chunked_err!(self => "Int128"))
228    }
229
230    pub fn f32(&self) -> PolarsResult<&Float32Chunked> {
232        self.try_f32()
233            .ok_or_else(|| unpack_chunked_err!(self => "Float32"))
234    }
235
236    pub fn f64(&self) -> PolarsResult<&Float64Chunked> {
238        self.try_f64()
239            .ok_or_else(|| unpack_chunked_err!(self => "Float64"))
240    }
241
242    pub fn u8(&self) -> PolarsResult<&UInt8Chunked> {
244        self.try_u8()
245            .ok_or_else(|| unpack_chunked_err!(self => "UInt8"))
246    }
247
248    pub fn u16(&self) -> PolarsResult<&UInt16Chunked> {
250        self.try_u16()
251            .ok_or_else(|| unpack_chunked_err!(self => "UInt16"))
252    }
253
254    pub fn u32(&self) -> PolarsResult<&UInt32Chunked> {
256        self.try_u32()
257            .ok_or_else(|| unpack_chunked_err!(self => "UInt32"))
258    }
259
260    pub fn u64(&self) -> PolarsResult<&UInt64Chunked> {
262        self.try_u64()
263            .ok_or_else(|| unpack_chunked_err!(self => "UInt64"))
264    }
265
266    pub fn bool(&self) -> PolarsResult<&BooleanChunked> {
268        self.try_bool()
269            .ok_or_else(|| unpack_chunked_err!(self => "Boolean"))
270    }
271
272    pub fn str(&self) -> PolarsResult<&StringChunked> {
274        self.try_str()
275            .ok_or_else(|| unpack_chunked_err!(self => "String"))
276    }
277
278    pub fn binary(&self) -> PolarsResult<&BinaryChunked> {
280        self.try_binary()
281            .ok_or_else(|| unpack_chunked_err!(self => "Binary"))
282    }
283
284    pub fn binary_offset(&self) -> PolarsResult<&BinaryOffsetChunked> {
286        self.try_binary_offset()
287            .ok_or_else(|| unpack_chunked_err!(self => "BinaryOffset"))
288    }
289
290    #[cfg(feature = "dtype-time")]
292    pub fn time(&self) -> PolarsResult<&TimeChunked> {
293        self.try_time()
294            .ok_or_else(|| unpack_chunked_err!(self => "Time"))
295    }
296
297    #[cfg(feature = "dtype-date")]
299    pub fn date(&self) -> PolarsResult<&DateChunked> {
300        self.try_date()
301            .ok_or_else(|| unpack_chunked_err!(self => "Date"))
302    }
303
304    #[cfg(feature = "dtype-datetime")]
306    pub fn datetime(&self) -> PolarsResult<&DatetimeChunked> {
307        self.try_datetime()
308            .ok_or_else(|| unpack_chunked_err!(self => "Datetime"))
309    }
310
311    #[cfg(feature = "dtype-duration")]
313    pub fn duration(&self) -> PolarsResult<&DurationChunked> {
314        self.try_duration()
315            .ok_or_else(|| unpack_chunked_err!(self => "Duration"))
316    }
317
318    #[cfg(feature = "dtype-decimal")]
320    pub fn decimal(&self) -> PolarsResult<&DecimalChunked> {
321        self.try_decimal()
322            .ok_or_else(|| unpack_chunked_err!(self => "Decimal"))
323    }
324
325    pub fn list(&self) -> PolarsResult<&ListChunked> {
327        self.try_list()
328            .ok_or_else(|| unpack_chunked_err!(self => "List"))
329    }
330
331    #[cfg(feature = "dtype-array")]
333    pub fn array(&self) -> PolarsResult<&ArrayChunked> {
334        self.try_array()
335            .ok_or_else(|| unpack_chunked_err!(self => "FixedSizeList"))
336    }
337
338    #[cfg(feature = "dtype-categorical")]
340    pub fn categorical(&self) -> PolarsResult<&CategoricalChunked> {
341        self.try_categorical()
342            .ok_or_else(|| unpack_chunked_err!(self => "Enum | Categorical"))
343    }
344
345    #[cfg(feature = "dtype-struct")]
347    pub fn struct_(&self) -> PolarsResult<&StructChunked> {
348        #[cfg(debug_assertions)]
349        {
350            if let DataType::Struct(_) = self.dtype() {
351                let any = self.as_any();
352                assert!(any.is::<StructChunked>());
353            }
354        }
355
356        self.try_struct()
357            .ok_or_else(|| unpack_chunked_err!(self => "Struct"))
358    }
359
360    pub fn null(&self) -> PolarsResult<&NullChunked> {
362        self.try_null()
363            .ok_or_else(|| unpack_chunked_err!(self => "Null"))
364    }
365}