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-struct")]
203 pub fn try_struct(&self) -> Option<&StructChunked> {
204 #[cfg(debug_assertions)]
205 {
206 if let DataType::Struct(_) = self.dtype() {
207 let any = self.as_any();
208 assert!(any.is::<StructChunked>());
209 }
210 }
211 try_unpack_chunked!(self, DataType::Struct(_) => StructChunked)
212 }
213
214 pub fn try_null(&self) -> Option<&NullChunked> {
216 try_unpack_chunked!(self, DataType::Null => NullChunked)
217 }
218 pub fn i8(&self) -> PolarsResult<&Int8Chunked> {
220 self.try_i8()
221 .ok_or_else(|| unpack_chunked_err!(self => "Int8"))
222 }
223
224 pub fn i16(&self) -> PolarsResult<&Int16Chunked> {
226 self.try_i16()
227 .ok_or_else(|| unpack_chunked_err!(self => "Int16"))
228 }
229
230 pub fn i32(&self) -> PolarsResult<&Int32Chunked> {
246 self.try_i32()
247 .ok_or_else(|| unpack_chunked_err!(self => "Int32"))
248 }
249
250 pub fn i64(&self) -> PolarsResult<&Int64Chunked> {
252 self.try_i64()
253 .ok_or_else(|| unpack_chunked_err!(self => "Int64"))
254 }
255
256 #[cfg(feature = "dtype-i128")]
258 pub fn i128(&self) -> PolarsResult<&Int128Chunked> {
259 self.try_i128()
260 .ok_or_else(|| unpack_chunked_err!(self => "Int128"))
261 }
262
263 #[cfg(feature = "dtype-f16")]
265 pub fn f16(&self) -> PolarsResult<&Float16Chunked> {
266 self.try_f16()
267 .ok_or_else(|| unpack_chunked_err!(self => "Float16"))
268 }
269
270 pub fn f32(&self) -> PolarsResult<&Float32Chunked> {
272 self.try_f32()
273 .ok_or_else(|| unpack_chunked_err!(self => "Float32"))
274 }
275
276 pub fn f64(&self) -> PolarsResult<&Float64Chunked> {
278 self.try_f64()
279 .ok_or_else(|| unpack_chunked_err!(self => "Float64"))
280 }
281
282 pub fn u8(&self) -> PolarsResult<&UInt8Chunked> {
284 self.try_u8()
285 .ok_or_else(|| unpack_chunked_err!(self => "UInt8"))
286 }
287
288 pub fn u16(&self) -> PolarsResult<&UInt16Chunked> {
290 self.try_u16()
291 .ok_or_else(|| unpack_chunked_err!(self => "UInt16"))
292 }
293
294 pub fn u32(&self) -> PolarsResult<&UInt32Chunked> {
296 self.try_u32()
297 .ok_or_else(|| unpack_chunked_err!(self => "UInt32"))
298 }
299
300 pub fn u64(&self) -> PolarsResult<&UInt64Chunked> {
302 self.try_u64()
303 .ok_or_else(|| unpack_chunked_err!(self => "UInt64"))
304 }
305
306 #[cfg(feature = "dtype-u128")]
308 pub fn u128(&self) -> PolarsResult<&UInt128Chunked> {
309 self.try_u128()
310 .ok_or_else(|| unpack_chunked_err!(self => "UInt128"))
311 }
312
313 pub fn bool(&self) -> PolarsResult<&BooleanChunked> {
315 self.try_bool()
316 .ok_or_else(|| unpack_chunked_err!(self => "Boolean"))
317 }
318
319 pub fn str(&self) -> PolarsResult<&StringChunked> {
321 self.try_str()
322 .ok_or_else(|| unpack_chunked_err!(self => "String"))
323 }
324
325 pub fn binary(&self) -> PolarsResult<&BinaryChunked> {
327 self.try_binary()
328 .ok_or_else(|| unpack_chunked_err!(self => "Binary"))
329 }
330
331 pub fn binary_offset(&self) -> PolarsResult<&BinaryOffsetChunked> {
333 self.try_binary_offset()
334 .ok_or_else(|| unpack_chunked_err!(self => "BinaryOffset"))
335 }
336
337 #[cfg(feature = "dtype-time")]
339 pub fn time(&self) -> PolarsResult<&TimeChunked> {
340 self.try_time()
341 .ok_or_else(|| unpack_chunked_err!(self => "Time"))
342 }
343
344 #[cfg(feature = "dtype-date")]
346 pub fn date(&self) -> PolarsResult<&DateChunked> {
347 self.try_date()
348 .ok_or_else(|| unpack_chunked_err!(self => "Date"))
349 }
350
351 #[cfg(feature = "dtype-datetime")]
353 pub fn datetime(&self) -> PolarsResult<&DatetimeChunked> {
354 self.try_datetime()
355 .ok_or_else(|| unpack_chunked_err!(self => "Datetime"))
356 }
357
358 #[cfg(feature = "dtype-duration")]
360 pub fn duration(&self) -> PolarsResult<&DurationChunked> {
361 self.try_duration()
362 .ok_or_else(|| unpack_chunked_err!(self => "Duration"))
363 }
364
365 #[cfg(feature = "dtype-decimal")]
367 pub fn decimal(&self) -> PolarsResult<&DecimalChunked> {
368 self.try_decimal()
369 .ok_or_else(|| unpack_chunked_err!(self => "Decimal"))
370 }
371
372 pub fn list(&self) -> PolarsResult<&ListChunked> {
374 self.try_list()
375 .ok_or_else(|| unpack_chunked_err!(self => "List"))
376 }
377
378 #[cfg(feature = "dtype-array")]
380 pub fn array(&self) -> PolarsResult<&ArrayChunked> {
381 self.try_array()
382 .ok_or_else(|| unpack_chunked_err!(self => "Array"))
383 }
384
385 #[cfg(feature = "dtype-categorical")]
387 pub fn cat<T: PolarsCategoricalType>(&self) -> PolarsResult<&CategoricalChunked<T>> {
388 self.try_cat::<T>()
389 .ok_or_else(|| unpack_chunked_err!(self => "Enum | Categorical"))
390 }
391
392 #[cfg(feature = "dtype-categorical")]
394 pub fn cat8(&self) -> PolarsResult<&CategoricalChunked<Categorical8Type>> {
395 self.try_cat8()
396 .ok_or_else(|| unpack_chunked_err!(self => "Enum8 | Categorical8"))
397 }
398
399 #[cfg(feature = "dtype-categorical")]
401 pub fn cat16(&self) -> PolarsResult<&CategoricalChunked<Categorical16Type>> {
402 self.try_cat16()
403 .ok_or_else(|| unpack_chunked_err!(self => "Enum16 | Categorical16"))
404 }
405
406 #[cfg(feature = "dtype-categorical")]
408 pub fn cat32(&self) -> PolarsResult<&CategoricalChunked<Categorical32Type>> {
409 self.try_cat32()
410 .ok_or_else(|| unpack_chunked_err!(self => "Enum32 | Categorical32"))
411 }
412
413 #[cfg(feature = "dtype-struct")]
415 pub fn struct_(&self) -> PolarsResult<&StructChunked> {
416 #[cfg(debug_assertions)]
417 {
418 if let DataType::Struct(_) = self.dtype() {
419 let any = self.as_any();
420 assert!(any.is::<StructChunked>());
421 }
422 }
423
424 self.try_struct()
425 .ok_or_else(|| unpack_chunked_err!(self => "Struct"))
426 }
427
428 #[cfg(feature = "dtype-extension")]
430 pub fn ext(&self) -> PolarsResult<&ExtensionChunked> {
431 self.try_ext()
432 .ok_or_else(|| unpack_chunked_err!(self => "Extension"))
433 }
434
435 pub fn null(&self) -> PolarsResult<&NullChunked> {
437 self.try_null()
438 .ok_or_else(|| unpack_chunked_err!(self => "Null"))
439 }
440}