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 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 #[cfg(feature = "dtype-u128")]
103 pub fn try_u128(&self) -> Option<&UInt128Chunked> {
104 try_unpack_chunked!(self, DataType::UInt128 => UInt128Chunked)
105 }
106
107 pub fn try_bool(&self) -> Option<&BooleanChunked> {
109 try_unpack_chunked!(self, DataType::Boolean => BooleanChunked)
110 }
111
112 pub fn try_str(&self) -> Option<&StringChunked> {
114 try_unpack_chunked!(self, DataType::String => StringChunked)
115 }
116
117 pub fn try_binary(&self) -> Option<&BinaryChunked> {
119 try_unpack_chunked!(self, DataType::Binary => BinaryChunked)
120 }
121
122 pub fn try_binary_offset(&self) -> Option<&BinaryOffsetChunked> {
124 try_unpack_chunked!(self, DataType::BinaryOffset => BinaryOffsetChunked)
125 }
126
127 #[cfg(feature = "dtype-time")]
129 pub fn try_time(&self) -> Option<&TimeChunked> {
130 try_unpack_chunked!(self, DataType::Time => TimeChunked)
131 }
132
133 #[cfg(feature = "dtype-date")]
135 pub fn try_date(&self) -> Option<&DateChunked> {
136 try_unpack_chunked!(self, DataType::Date => DateChunked)
137 }
138
139 #[cfg(feature = "dtype-datetime")]
141 pub fn try_datetime(&self) -> Option<&DatetimeChunked> {
142 try_unpack_chunked!(self, DataType::Datetime(_, _) => DatetimeChunked)
143 }
144
145 #[cfg(feature = "dtype-duration")]
147 pub fn try_duration(&self) -> Option<&DurationChunked> {
148 try_unpack_chunked!(self, DataType::Duration(_) => DurationChunked)
149 }
150
151 #[cfg(feature = "dtype-decimal")]
153 pub fn try_decimal(&self) -> Option<&DecimalChunked> {
154 try_unpack_chunked!(self, DataType::Decimal(_, _) => DecimalChunked)
155 }
156
157 pub fn try_list(&self) -> Option<&ListChunked> {
159 try_unpack_chunked!(self, DataType::List(_) => ListChunked)
160 }
161
162 #[cfg(feature = "dtype-array")]
164 pub fn try_array(&self) -> Option<&ArrayChunked> {
165 try_unpack_chunked!(self, DataType::Array(_, _) => ArrayChunked)
166 }
167
168 #[cfg(feature = "dtype-categorical")]
169 pub fn try_cat<T: PolarsCategoricalType>(&self) -> Option<&CategoricalChunked<T>> {
170 try_unpack_chunked!(self, dt @ DataType::Enum(_, _) | dt @ DataType::Categorical(_, _) if dt.cat_physical().unwrap() == T::physical() => CategoricalChunked<T>)
171 }
172
173 #[cfg(feature = "dtype-categorical")]
175 pub fn try_cat8(&self) -> Option<&Categorical8Chunked> {
176 self.try_cat::<Categorical8Type>()
177 }
178
179 #[cfg(feature = "dtype-categorical")]
180 pub fn try_cat16(&self) -> Option<&Categorical16Chunked> {
181 self.try_cat::<Categorical16Type>()
182 }
183
184 #[cfg(feature = "dtype-categorical")]
185 pub fn try_cat32(&self) -> Option<&Categorical32Chunked> {
186 self.try_cat::<Categorical32Type>()
187 }
188
189 #[cfg(feature = "dtype-extension")]
191 pub fn try_ext(&self) -> Option<&ExtensionChunked> {
192 try_unpack_chunked!(self, DataType::Extension(_, _) => ExtensionChunked)
193 }
194
195 #[cfg(feature = "dtype-struct")]
197 pub fn try_struct(&self) -> Option<&StructChunked> {
198 #[cfg(debug_assertions)]
199 {
200 if let DataType::Struct(_) = self.dtype() {
201 let any = self.as_any();
202 assert!(any.is::<StructChunked>());
203 }
204 }
205 try_unpack_chunked!(self, DataType::Struct(_) => StructChunked)
206 }
207
208 pub fn try_null(&self) -> Option<&NullChunked> {
210 try_unpack_chunked!(self, DataType::Null => NullChunked)
211 }
212 pub fn i8(&self) -> PolarsResult<&Int8Chunked> {
214 self.try_i8()
215 .ok_or_else(|| unpack_chunked_err!(self => "Int8"))
216 }
217
218 pub fn i16(&self) -> PolarsResult<&Int16Chunked> {
220 self.try_i16()
221 .ok_or_else(|| unpack_chunked_err!(self => "Int16"))
222 }
223
224 pub fn i32(&self) -> PolarsResult<&Int32Chunked> {
240 self.try_i32()
241 .ok_or_else(|| unpack_chunked_err!(self => "Int32"))
242 }
243
244 pub fn i64(&self) -> PolarsResult<&Int64Chunked> {
246 self.try_i64()
247 .ok_or_else(|| unpack_chunked_err!(self => "Int64"))
248 }
249
250 #[cfg(feature = "dtype-i128")]
252 pub fn i128(&self) -> PolarsResult<&Int128Chunked> {
253 self.try_i128()
254 .ok_or_else(|| unpack_chunked_err!(self => "Int128"))
255 }
256
257 pub fn f32(&self) -> PolarsResult<&Float32Chunked> {
259 self.try_f32()
260 .ok_or_else(|| unpack_chunked_err!(self => "Float32"))
261 }
262
263 pub fn f64(&self) -> PolarsResult<&Float64Chunked> {
265 self.try_f64()
266 .ok_or_else(|| unpack_chunked_err!(self => "Float64"))
267 }
268
269 pub fn u8(&self) -> PolarsResult<&UInt8Chunked> {
271 self.try_u8()
272 .ok_or_else(|| unpack_chunked_err!(self => "UInt8"))
273 }
274
275 pub fn u16(&self) -> PolarsResult<&UInt16Chunked> {
277 self.try_u16()
278 .ok_or_else(|| unpack_chunked_err!(self => "UInt16"))
279 }
280
281 pub fn u32(&self) -> PolarsResult<&UInt32Chunked> {
283 self.try_u32()
284 .ok_or_else(|| unpack_chunked_err!(self => "UInt32"))
285 }
286
287 pub fn u64(&self) -> PolarsResult<&UInt64Chunked> {
289 self.try_u64()
290 .ok_or_else(|| unpack_chunked_err!(self => "UInt64"))
291 }
292
293 #[cfg(feature = "dtype-u128")]
295 pub fn u128(&self) -> PolarsResult<&UInt128Chunked> {
296 self.try_u128()
297 .ok_or_else(|| unpack_chunked_err!(self => "UInt128"))
298 }
299
300 pub fn bool(&self) -> PolarsResult<&BooleanChunked> {
302 self.try_bool()
303 .ok_or_else(|| unpack_chunked_err!(self => "Boolean"))
304 }
305
306 pub fn str(&self) -> PolarsResult<&StringChunked> {
308 self.try_str()
309 .ok_or_else(|| unpack_chunked_err!(self => "String"))
310 }
311
312 pub fn binary(&self) -> PolarsResult<&BinaryChunked> {
314 self.try_binary()
315 .ok_or_else(|| unpack_chunked_err!(self => "Binary"))
316 }
317
318 pub fn binary_offset(&self) -> PolarsResult<&BinaryOffsetChunked> {
320 self.try_binary_offset()
321 .ok_or_else(|| unpack_chunked_err!(self => "BinaryOffset"))
322 }
323
324 #[cfg(feature = "dtype-time")]
326 pub fn time(&self) -> PolarsResult<&TimeChunked> {
327 self.try_time()
328 .ok_or_else(|| unpack_chunked_err!(self => "Time"))
329 }
330
331 #[cfg(feature = "dtype-date")]
333 pub fn date(&self) -> PolarsResult<&DateChunked> {
334 self.try_date()
335 .ok_or_else(|| unpack_chunked_err!(self => "Date"))
336 }
337
338 #[cfg(feature = "dtype-datetime")]
340 pub fn datetime(&self) -> PolarsResult<&DatetimeChunked> {
341 self.try_datetime()
342 .ok_or_else(|| unpack_chunked_err!(self => "Datetime"))
343 }
344
345 #[cfg(feature = "dtype-duration")]
347 pub fn duration(&self) -> PolarsResult<&DurationChunked> {
348 self.try_duration()
349 .ok_or_else(|| unpack_chunked_err!(self => "Duration"))
350 }
351
352 #[cfg(feature = "dtype-decimal")]
354 pub fn decimal(&self) -> PolarsResult<&DecimalChunked> {
355 self.try_decimal()
356 .ok_or_else(|| unpack_chunked_err!(self => "Decimal"))
357 }
358
359 pub fn list(&self) -> PolarsResult<&ListChunked> {
361 self.try_list()
362 .ok_or_else(|| unpack_chunked_err!(self => "List"))
363 }
364
365 #[cfg(feature = "dtype-array")]
367 pub fn array(&self) -> PolarsResult<&ArrayChunked> {
368 self.try_array()
369 .ok_or_else(|| unpack_chunked_err!(self => "Array"))
370 }
371
372 #[cfg(feature = "dtype-categorical")]
374 pub fn cat<T: PolarsCategoricalType>(&self) -> PolarsResult<&CategoricalChunked<T>> {
375 self.try_cat::<T>()
376 .ok_or_else(|| unpack_chunked_err!(self => "Enum | Categorical"))
377 }
378
379 #[cfg(feature = "dtype-categorical")]
381 pub fn cat8(&self) -> PolarsResult<&CategoricalChunked<Categorical8Type>> {
382 self.try_cat8()
383 .ok_or_else(|| unpack_chunked_err!(self => "Enum8 | Categorical8"))
384 }
385
386 #[cfg(feature = "dtype-categorical")]
388 pub fn cat16(&self) -> PolarsResult<&CategoricalChunked<Categorical16Type>> {
389 self.try_cat16()
390 .ok_or_else(|| unpack_chunked_err!(self => "Enum16 | Categorical16"))
391 }
392
393 #[cfg(feature = "dtype-categorical")]
395 pub fn cat32(&self) -> PolarsResult<&CategoricalChunked<Categorical32Type>> {
396 self.try_cat32()
397 .ok_or_else(|| unpack_chunked_err!(self => "Enum32 | Categorical32"))
398 }
399
400 #[cfg(feature = "dtype-struct")]
402 pub fn struct_(&self) -> PolarsResult<&StructChunked> {
403 #[cfg(debug_assertions)]
404 {
405 if let DataType::Struct(_) = self.dtype() {
406 let any = self.as_any();
407 assert!(any.is::<StructChunked>());
408 }
409 }
410
411 self.try_struct()
412 .ok_or_else(|| unpack_chunked_err!(self => "Struct"))
413 }
414
415 #[cfg(feature = "dtype-extension")]
417 pub fn ext(&self) -> PolarsResult<&ExtensionChunked> {
418 self.try_ext()
419 .ok_or_else(|| unpack_chunked_err!(self => "Extension"))
420 }
421
422 pub fn null(&self) -> PolarsResult<&NullChunked> {
424 self.try_null()
425 .ok_or_else(|| unpack_chunked_err!(self => "Null"))
426 }
427}