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 $(if $guard: expr)? => $ca:ty) => {
13 match $series.dtype() {
14 $expected $(if $guard)? => {
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 #[cfg(feature = "dtype-f16")]
73 pub fn try_f16(&self) -> Option<&Float16Chunked> {
74 try_unpack_chunked!(self, DataType::Float16 => Float16Chunked)
75 }
76
77 pub fn try_f32(&self) -> Option<&Float32Chunked> {
79 try_unpack_chunked!(self, DataType::Float32 => Float32Chunked)
80 }
81
82 pub fn try_f64(&self) -> Option<&Float64Chunked> {
84 try_unpack_chunked!(self, DataType::Float64 => Float64Chunked)
85 }
86
87 pub fn try_u8(&self) -> Option<&UInt8Chunked> {
89 try_unpack_chunked!(self, DataType::UInt8 => UInt8Chunked)
90 }
91
92 pub fn try_u16(&self) -> Option<&UInt16Chunked> {
94 try_unpack_chunked!(self, DataType::UInt16 => UInt16Chunked)
95 }
96
97 pub fn try_u32(&self) -> Option<&UInt32Chunked> {
99 try_unpack_chunked!(self, DataType::UInt32 => UInt32Chunked)
100 }
101
102 pub fn try_u64(&self) -> Option<&UInt64Chunked> {
104 try_unpack_chunked!(self, DataType::UInt64 => UInt64Chunked)
105 }
106
107 #[cfg(feature = "dtype-u128")]
109 pub fn try_u128(&self) -> Option<&UInt128Chunked> {
110 try_unpack_chunked!(self, DataType::UInt128 => UInt128Chunked)
111 }
112
113 pub fn try_bool(&self) -> Option<&BooleanChunked> {
115 try_unpack_chunked!(self, DataType::Boolean => BooleanChunked)
116 }
117
118 pub fn try_str(&self) -> Option<&StringChunked> {
120 try_unpack_chunked!(self, DataType::String => StringChunked)
121 }
122
123 pub fn try_binary(&self) -> Option<&BinaryChunked> {
125 try_unpack_chunked!(self, DataType::Binary => BinaryChunked)
126 }
127
128 pub fn try_binary_offset(&self) -> Option<&BinaryOffsetChunked> {
130 try_unpack_chunked!(self, DataType::BinaryOffset => BinaryOffsetChunked)
131 }
132
133 #[cfg(feature = "dtype-time")]
135 pub fn try_time(&self) -> Option<&TimeChunked> {
136 try_unpack_chunked!(self, DataType::Time => TimeChunked)
137 }
138
139 #[cfg(feature = "dtype-date")]
141 pub fn try_date(&self) -> Option<&DateChunked> {
142 try_unpack_chunked!(self, DataType::Date => DateChunked)
143 }
144
145 #[cfg(feature = "dtype-datetime")]
147 pub fn try_datetime(&self) -> Option<&DatetimeChunked> {
148 try_unpack_chunked!(self, DataType::Datetime(_, _) => DatetimeChunked)
149 }
150
151 #[cfg(feature = "dtype-duration")]
153 pub fn try_duration(&self) -> Option<&DurationChunked> {
154 try_unpack_chunked!(self, DataType::Duration(_) => DurationChunked)
155 }
156
157 #[cfg(feature = "dtype-decimal")]
159 pub fn try_decimal(&self) -> Option<&DecimalChunked> {
160 try_unpack_chunked!(self, DataType::Decimal(_, _) => DecimalChunked)
161 }
162
163 pub fn try_list(&self) -> Option<&ListChunked> {
165 try_unpack_chunked!(self, DataType::List(_) => ListChunked)
166 }
167
168 #[cfg(feature = "dtype-array")]
170 pub fn try_array(&self) -> Option<&ArrayChunked> {
171 try_unpack_chunked!(self, DataType::Array(_, _) => ArrayChunked)
172 }
173
174 #[cfg(feature = "dtype-categorical")]
175 pub fn try_cat<T: PolarsCategoricalType>(&self) -> Option<&CategoricalChunked<T>> {
176 try_unpack_chunked!(self, dt @ DataType::Enum(_, _) | dt @ DataType::Categorical(_, _) if dt.cat_physical().unwrap() == T::physical() => CategoricalChunked<T>)
177 }
178
179 #[cfg(feature = "dtype-categorical")]
181 pub fn try_cat8(&self) -> Option<&Categorical8Chunked> {
182 self.try_cat::<Categorical8Type>()
183 }
184
185 #[cfg(feature = "dtype-categorical")]
186 pub fn try_cat16(&self) -> Option<&Categorical16Chunked> {
187 self.try_cat::<Categorical16Type>()
188 }
189
190 #[cfg(feature = "dtype-categorical")]
191 pub fn try_cat32(&self) -> Option<&Categorical32Chunked> {
192 self.try_cat::<Categorical32Type>()
193 }
194
195 #[cfg(feature = "dtype-extension")]
197 pub fn try_ext(&self) -> Option<&ExtensionChunked> {
198 try_unpack_chunked!(self, DataType::Extension(_, _) => ExtensionChunked)
199 }
200
201 #[cfg(feature = "dtype-map")]
203 pub fn try_map(&self) -> Option<&MapChunked> {
204 try_unpack_chunked!(self, DataType::Map(_, _) => MapChunked)
205 }
206
207 #[cfg(feature = "dtype-struct")]
209 pub fn try_struct(&self) -> Option<&StructChunked> {
210 #[cfg(debug_assertions)]
211 {
212 if let DataType::Struct(_) = self.dtype() {
213 let any = self.as_any();
214 assert!(any.is::<StructChunked>());
215 }
216 }
217 try_unpack_chunked!(self, DataType::Struct(_) => StructChunked)
218 }
219
220 pub fn try_null(&self) -> Option<&NullChunked> {
222 try_unpack_chunked!(self, DataType::Null => NullChunked)
223 }
224 pub fn i8(&self) -> PolarsResult<&Int8Chunked> {
226 self.try_i8()
227 .ok_or_else(|| unpack_chunked_err!(self => "Int8"))
228 }
229
230 pub fn i16(&self) -> PolarsResult<&Int16Chunked> {
232 self.try_i16()
233 .ok_or_else(|| unpack_chunked_err!(self => "Int16"))
234 }
235
236 pub fn i32(&self) -> PolarsResult<&Int32Chunked> {
252 self.try_i32()
253 .ok_or_else(|| unpack_chunked_err!(self => "Int32"))
254 }
255
256 pub fn i64(&self) -> PolarsResult<&Int64Chunked> {
258 self.try_i64()
259 .ok_or_else(|| unpack_chunked_err!(self => "Int64"))
260 }
261
262 #[cfg(feature = "dtype-i128")]
264 pub fn i128(&self) -> PolarsResult<&Int128Chunked> {
265 self.try_i128()
266 .ok_or_else(|| unpack_chunked_err!(self => "Int128"))
267 }
268
269 #[cfg(feature = "dtype-f16")]
271 pub fn f16(&self) -> PolarsResult<&Float16Chunked> {
272 self.try_f16()
273 .ok_or_else(|| unpack_chunked_err!(self => "Float16"))
274 }
275
276 pub fn f32(&self) -> PolarsResult<&Float32Chunked> {
278 self.try_f32()
279 .ok_or_else(|| unpack_chunked_err!(self => "Float32"))
280 }
281
282 pub fn f64(&self) -> PolarsResult<&Float64Chunked> {
284 self.try_f64()
285 .ok_or_else(|| unpack_chunked_err!(self => "Float64"))
286 }
287
288 pub fn u8(&self) -> PolarsResult<&UInt8Chunked> {
290 self.try_u8()
291 .ok_or_else(|| unpack_chunked_err!(self => "UInt8"))
292 }
293
294 pub fn u16(&self) -> PolarsResult<&UInt16Chunked> {
296 self.try_u16()
297 .ok_or_else(|| unpack_chunked_err!(self => "UInt16"))
298 }
299
300 pub fn u32(&self) -> PolarsResult<&UInt32Chunked> {
302 self.try_u32()
303 .ok_or_else(|| unpack_chunked_err!(self => "UInt32"))
304 }
305
306 pub fn u64(&self) -> PolarsResult<&UInt64Chunked> {
308 self.try_u64()
309 .ok_or_else(|| unpack_chunked_err!(self => "UInt64"))
310 }
311
312 #[cfg(feature = "dtype-u128")]
314 pub fn u128(&self) -> PolarsResult<&UInt128Chunked> {
315 self.try_u128()
316 .ok_or_else(|| unpack_chunked_err!(self => "UInt128"))
317 }
318
319 pub fn bool(&self) -> PolarsResult<&BooleanChunked> {
321 self.try_bool()
322 .ok_or_else(|| unpack_chunked_err!(self => "Boolean"))
323 }
324
325 pub fn str(&self) -> PolarsResult<&StringChunked> {
327 self.try_str()
328 .ok_or_else(|| unpack_chunked_err!(self => "String"))
329 }
330
331 pub fn binary(&self) -> PolarsResult<&BinaryChunked> {
333 self.try_binary()
334 .ok_or_else(|| unpack_chunked_err!(self => "Binary"))
335 }
336
337 pub fn binary_offset(&self) -> PolarsResult<&BinaryOffsetChunked> {
339 self.try_binary_offset()
340 .ok_or_else(|| unpack_chunked_err!(self => "BinaryOffset"))
341 }
342
343 #[cfg(feature = "dtype-time")]
345 pub fn time(&self) -> PolarsResult<&TimeChunked> {
346 self.try_time()
347 .ok_or_else(|| unpack_chunked_err!(self => "Time"))
348 }
349
350 #[cfg(feature = "dtype-date")]
352 pub fn date(&self) -> PolarsResult<&DateChunked> {
353 self.try_date()
354 .ok_or_else(|| unpack_chunked_err!(self => "Date"))
355 }
356
357 #[cfg(feature = "dtype-datetime")]
359 pub fn datetime(&self) -> PolarsResult<&DatetimeChunked> {
360 self.try_datetime()
361 .ok_or_else(|| unpack_chunked_err!(self => "Datetime"))
362 }
363
364 #[cfg(feature = "dtype-duration")]
366 pub fn duration(&self) -> PolarsResult<&DurationChunked> {
367 self.try_duration()
368 .ok_or_else(|| unpack_chunked_err!(self => "Duration"))
369 }
370
371 #[cfg(feature = "dtype-decimal")]
373 pub fn decimal(&self) -> PolarsResult<&DecimalChunked> {
374 self.try_decimal()
375 .ok_or_else(|| unpack_chunked_err!(self => "Decimal"))
376 }
377
378 pub fn list(&self) -> PolarsResult<&ListChunked> {
380 self.try_list()
381 .ok_or_else(|| unpack_chunked_err!(self => "List"))
382 }
383
384 #[cfg(feature = "dtype-array")]
386 pub fn array(&self) -> PolarsResult<&ArrayChunked> {
387 self.try_array()
388 .ok_or_else(|| unpack_chunked_err!(self => "Array"))
389 }
390
391 #[cfg(feature = "dtype-categorical")]
393 pub fn cat<T: PolarsCategoricalType>(&self) -> PolarsResult<&CategoricalChunked<T>> {
394 self.try_cat::<T>()
395 .ok_or_else(|| unpack_chunked_err!(self => "Enum | Categorical"))
396 }
397
398 #[cfg(feature = "dtype-categorical")]
400 pub fn cat8(&self) -> PolarsResult<&CategoricalChunked<Categorical8Type>> {
401 self.try_cat8()
402 .ok_or_else(|| unpack_chunked_err!(self => "Enum8 | Categorical8"))
403 }
404
405 #[cfg(feature = "dtype-categorical")]
407 pub fn cat16(&self) -> PolarsResult<&CategoricalChunked<Categorical16Type>> {
408 self.try_cat16()
409 .ok_or_else(|| unpack_chunked_err!(self => "Enum16 | Categorical16"))
410 }
411
412 #[cfg(feature = "dtype-categorical")]
414 pub fn cat32(&self) -> PolarsResult<&CategoricalChunked<Categorical32Type>> {
415 self.try_cat32()
416 .ok_or_else(|| unpack_chunked_err!(self => "Enum32 | Categorical32"))
417 }
418
419 #[cfg(feature = "dtype-struct")]
421 pub fn struct_(&self) -> PolarsResult<&StructChunked> {
422 #[cfg(debug_assertions)]
423 {
424 if let DataType::Struct(_) = self.dtype() {
425 let any = self.as_any();
426 assert!(any.is::<StructChunked>());
427 }
428 }
429
430 self.try_struct()
431 .ok_or_else(|| unpack_chunked_err!(self => "Struct"))
432 }
433
434 #[cfg(feature = "dtype-extension")]
436 pub fn ext(&self) -> PolarsResult<&ExtensionChunked> {
437 self.try_ext()
438 .ok_or_else(|| unpack_chunked_err!(self => "Extension"))
439 }
440
441 #[cfg(feature = "dtype-map")]
443 pub fn map(&self) -> PolarsResult<&MapChunked> {
444 self.try_map()
445 .ok_or_else(|| unpack_chunked_err!(self => "Map"))
446 }
447
448 pub fn null(&self) -> PolarsResult<&NullChunked> {
450 self.try_null()
451 .ok_or_else(|| unpack_chunked_err!(self => "Null"))
452 }
453}