Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-compute/src/cast/mod.rs
8424 views
1
//! Defines different casting operators such as [`cast`] or [`primitive_to_binary`].
2
3
mod binary_to;
4
mod binview_to;
5
mod boolean_to;
6
#[cfg(feature = "dtype-decimal")]
7
mod decimal_to;
8
mod dictionary_to;
9
mod primitive_to;
10
mod utf8_to;
11
12
use arrow::bitmap::MutableBitmap;
13
pub use binary_to::*;
14
#[cfg(feature = "dtype-decimal")]
15
pub use binview_to::binview_to_decimal;
16
use binview_to::utf8view_to_primitive_dyn;
17
pub use binview_to::utf8view_to_utf8;
18
pub use boolean_to::*;
19
#[cfg(feature = "dtype-decimal")]
20
pub use decimal_to::*;
21
pub mod temporal;
22
use arrow::array::*;
23
use arrow::datatypes::*;
24
use arrow::match_integer_type;
25
use arrow::offset::{Offset, Offsets};
26
use binview_to::{
27
binview_to_dictionary, utf8view_to_date32_dyn, utf8view_to_dictionary,
28
utf8view_to_naive_timestamp_dyn, view_to_binary,
29
};
30
pub use binview_to::{binview_to_fixed_size_list_dyn, binview_to_primitive_dyn};
31
use dictionary_to::*;
32
use polars_error::{PolarsResult, polars_bail, polars_ensure, polars_err};
33
use polars_utils::IdxSize;
34
use polars_utils::float16::pf16;
35
pub use primitive_to::*;
36
use temporal::utf8view_to_timestamp;
37
pub use utf8_to::*;
38
39
/// options defining how Cast kernels behave
40
#[derive(Clone, Copy, Debug, Default)]
41
pub struct CastOptionsImpl {
42
/// default to false
43
/// whether an overflowing cast should be converted to `None` (default), or be wrapped (i.e. `256i16 as u8 = 0` vectorized).
44
/// Settings this to `true` is 5-6x faster for numeric types.
45
pub wrapped: bool,
46
/// default to false
47
/// whether to cast to an integer at the best-effort
48
pub partial: bool,
49
}
50
51
impl CastOptionsImpl {
52
pub fn unchecked() -> Self {
53
Self {
54
wrapped: true,
55
partial: false,
56
}
57
}
58
}
59
60
impl CastOptionsImpl {
61
fn with_wrapped(&self, v: bool) -> Self {
62
let mut option = *self;
63
option.wrapped = v;
64
option
65
}
66
}
67
68
macro_rules! primitive_dyn {
69
($from:expr, $expr:tt) => {{
70
let from = $from.as_any().downcast_ref().unwrap();
71
Ok(Box::new($expr(from)))
72
}};
73
($from:expr, $expr:tt, $to:expr) => {{
74
let from = $from.as_any().downcast_ref().unwrap();
75
Ok(Box::new($expr(from, $to)))
76
}};
77
($from:expr, $expr:tt, $from_t:expr, $to:expr) => {{
78
let from = $from.as_any().downcast_ref().unwrap();
79
Ok(Box::new($expr(from, $from_t, $to)))
80
}};
81
($from:expr, $expr:tt, $arg1:expr, $arg2:expr, $arg3:expr) => {{
82
let from = $from.as_any().downcast_ref().unwrap();
83
Ok(Box::new($expr(from, $arg1, $arg2, $arg3)))
84
}};
85
}
86
87
fn cast_struct(
88
array: &StructArray,
89
to_type: &ArrowDataType,
90
options: CastOptionsImpl,
91
) -> PolarsResult<StructArray> {
92
let values = array.values();
93
let fields = StructArray::get_fields(to_type);
94
let new_values = values
95
.iter()
96
.zip(fields)
97
.map(|(arr, field)| cast(arr.as_ref(), field.dtype(), options))
98
.collect::<PolarsResult<Vec<_>>>()?;
99
100
Ok(StructArray::new(
101
to_type.clone(),
102
array.len(),
103
new_values,
104
array.validity().cloned(),
105
))
106
}
107
108
fn cast_list<O: Offset>(
109
array: &ListArray<O>,
110
to_type: &ArrowDataType,
111
options: CastOptionsImpl,
112
) -> PolarsResult<ListArray<O>> {
113
let values = array.values();
114
let new_values = cast(
115
values.as_ref(),
116
ListArray::<O>::get_child_type(to_type),
117
options,
118
)?;
119
120
Ok(ListArray::<O>::new(
121
to_type.clone(),
122
array.offsets().clone(),
123
new_values,
124
array.validity().cloned(),
125
))
126
}
127
128
fn cast_list_to_large_list(array: &ListArray<i32>, to_type: &ArrowDataType) -> ListArray<i64> {
129
let offsets = array.offsets().into();
130
131
ListArray::<i64>::new(
132
to_type.clone(),
133
offsets,
134
array.values().clone(),
135
array.validity().cloned(),
136
)
137
}
138
139
fn cast_large_to_list(array: &ListArray<i64>, to_type: &ArrowDataType) -> ListArray<i32> {
140
let offsets = array.offsets().try_into().expect("Convertme to error");
141
142
ListArray::<i32>::new(
143
to_type.clone(),
144
offsets,
145
array.values().clone(),
146
array.validity().cloned(),
147
)
148
}
149
150
fn cast_fixed_size_list_to_list<O: Offset>(
151
fixed: &FixedSizeListArray,
152
to_type: &ArrowDataType,
153
options: CastOptionsImpl,
154
) -> PolarsResult<ListArray<O>> {
155
let new_values = cast(
156
fixed.values().as_ref(),
157
ListArray::<O>::get_child_type(to_type),
158
options,
159
)?;
160
161
let offsets = (0..=fixed.len())
162
.map(|ix| O::from_as_usize(ix * fixed.size()))
163
.collect::<Vec<_>>();
164
// SAFETY: offsets _are_ monotonically increasing
165
let offsets = unsafe { Offsets::new_unchecked(offsets) };
166
167
Ok(ListArray::<O>::new(
168
to_type.clone(),
169
offsets.into(),
170
new_values,
171
fixed.validity().cloned(),
172
))
173
}
174
175
pub(super) fn cast_list_to_fixed_size_list<O: Offset>(
176
list: &ListArray<O>,
177
inner: &Field,
178
size: usize,
179
options: CastOptionsImpl,
180
) -> PolarsResult<FixedSizeListArray> {
181
let null_cnt = list.null_count();
182
let new_values = if null_cnt == 0 {
183
let start_offset = list.offsets().first().to_usize();
184
let offsets = list.offsets().buffer();
185
186
let mut is_valid = true;
187
for (i, offset) in offsets.iter().enumerate() {
188
is_valid &= offset.to_usize() == start_offset + i * size;
189
}
190
191
polars_ensure!(is_valid, ComputeError: "not all elements have the specified width {size}");
192
193
let sliced_values = list
194
.values()
195
.sliced(start_offset, list.offsets().range().to_usize());
196
cast(sliced_values.as_ref(), inner.dtype(), options)?
197
} else {
198
let offsets = list.offsets().as_slice();
199
// Check the lengths of each list are equal to the fixed size.
200
// SAFETY: we know the index is in bound.
201
let mut expected_offset = unsafe { *offsets.get_unchecked(0) } + O::from_as_usize(size);
202
for i in 1..=list.len() {
203
// SAFETY: we know the index is in bound.
204
let current_offset = unsafe { *offsets.get_unchecked(i) };
205
if list.is_null(i - 1) {
206
expected_offset = current_offset + O::from_as_usize(size);
207
} else {
208
polars_ensure!(current_offset == expected_offset, ComputeError:
209
"not all elements have the specified width {size}");
210
expected_offset += O::from_as_usize(size);
211
}
212
}
213
214
// Build take indices for the values. This is used to fill in the null slots.
215
let mut indices =
216
MutablePrimitiveArray::<IdxSize>::with_capacity(list.values().len() + null_cnt * size);
217
for i in 0..list.len() {
218
if list.is_null(i) {
219
indices.extend_constant(size, None)
220
} else {
221
// SAFETY: we know the index is in bound.
222
let current_offset = unsafe { *offsets.get_unchecked(i) };
223
for j in 0..size {
224
indices.push(Some(
225
(current_offset + O::from_as_usize(j)).to_usize() as IdxSize
226
));
227
}
228
}
229
}
230
let take_values =
231
unsafe { crate::gather::take_unchecked(list.values().as_ref(), &indices.freeze()) };
232
233
cast(take_values.as_ref(), inner.dtype(), options)?
234
};
235
236
FixedSizeListArray::try_new(
237
ArrowDataType::FixedSizeList(Box::new(inner.clone()), size),
238
list.len(),
239
new_values,
240
list.validity().cloned(),
241
)
242
.map_err(|_| polars_err!(ComputeError: "not all elements have the specified width {size}"))
243
}
244
245
fn cast_list_uint8_to_binary<O: Offset>(list: &ListArray<O>) -> PolarsResult<BinaryViewArray> {
246
let mut views = Vec::with_capacity(list.len());
247
let mut result_validity = MutableBitmap::from_len_set(list.len());
248
249
let u8array: &PrimitiveArray<u8> = list.values().as_any().downcast_ref().unwrap();
250
let slice = u8array.values().as_slice();
251
let mut cloned_buffers = vec![u8array.values().clone()];
252
let mut buf_index = 0;
253
let mut previous_buf_lengths = 0;
254
let validity = list.validity();
255
let internal_validity = list.values().validity();
256
let offsets = list.offsets();
257
258
let mut all_views_inline = true;
259
260
// In a View for BinaryViewArray, both length and offset are u32.
261
#[cfg(not(test))]
262
const MAX_BUF_SIZE: usize = u32::MAX as usize;
263
264
// This allows us to test some invariants without using 4GB of RAM; see mod
265
// tests below.
266
#[cfg(test)]
267
const MAX_BUF_SIZE: usize = 15;
268
269
for index in 0..list.len() {
270
// Check if there's a null instead of a list:
271
if let Some(validity) = validity {
272
// SAFETY: We are generating indexes limited to < list.len().
273
debug_assert!(index < validity.len());
274
if unsafe { !validity.get_bit_unchecked(index) } {
275
debug_assert!(index < result_validity.len());
276
unsafe {
277
result_validity.set_unchecked(index, false);
278
}
279
views.push(View::default());
280
continue;
281
}
282
}
283
284
// SAFETY: We are generating indexes limited to < list.len().
285
debug_assert!(index < offsets.len());
286
let (start, end) = unsafe { offsets.start_end_unchecked(index) };
287
let length = end - start;
288
polars_ensure!(
289
length <= MAX_BUF_SIZE,
290
InvalidOperation:
291
"when casting to BinaryView, list lengths must be <= {MAX_BUF_SIZE}"
292
);
293
294
// Check if the list contains nulls:
295
if let Some(internal_validity) = internal_validity {
296
if internal_validity.null_count_range(start, length) > 0 {
297
debug_assert!(index < result_validity.len());
298
unsafe {
299
result_validity.set_unchecked(index, false);
300
}
301
views.push(View::default());
302
continue;
303
}
304
}
305
306
if end - previous_buf_lengths > MAX_BUF_SIZE {
307
// View offsets must fit in u32 (or smaller value when running Rust
308
// tests), and we've determined the end of the next view will be
309
// past that.
310
buf_index += 1;
311
let (previous, next) = cloned_buffers
312
.last()
313
.unwrap()
314
.split_at(start - previous_buf_lengths);
315
debug_assert!(previous.len() <= MAX_BUF_SIZE);
316
previous_buf_lengths += previous.len();
317
*(cloned_buffers.last_mut().unwrap()) = previous;
318
cloned_buffers.push(next);
319
}
320
let view = View::new_from_bytes(
321
&slice[start..end],
322
buf_index,
323
(start - previous_buf_lengths) as u32,
324
);
325
if !view.is_inline() {
326
all_views_inline = false;
327
}
328
debug_assert_eq!(
329
unsafe { view.get_slice_unchecked(&cloned_buffers) },
330
&slice[start..end]
331
);
332
views.push(view);
333
}
334
335
// Optimization: don't actually need buffers if Views are all inline.
336
if all_views_inline {
337
cloned_buffers.clear();
338
}
339
340
let result = if cfg!(debug_assertions) {
341
// A safer wrapper around new_unchecked_unknown_md; it shouldn't ever
342
// fail in practice.
343
BinaryViewArrayGeneric::try_new(
344
ArrowDataType::BinaryView,
345
views.into(),
346
cloned_buffers.into(),
347
result_validity.into(),
348
)?
349
} else {
350
unsafe {
351
BinaryViewArrayGeneric::new_unchecked_unknown_md(
352
ArrowDataType::BinaryView,
353
views.into(),
354
cloned_buffers.into(),
355
result_validity.into(),
356
// We could compute this ourselves, but we want to make this code
357
// match debug_assertions path as much as possible.
358
None,
359
)
360
}
361
};
362
363
Ok(result)
364
}
365
366
pub fn cast_default(array: &dyn Array, to_type: &ArrowDataType) -> PolarsResult<Box<dyn Array>> {
367
cast(array, to_type, Default::default())
368
}
369
370
pub fn cast_unchecked(array: &dyn Array, to_type: &ArrowDataType) -> PolarsResult<Box<dyn Array>> {
371
cast(array, to_type, CastOptionsImpl::unchecked())
372
}
373
374
/// Cast `array` to the provided data type and return a new [`Array`] with
375
/// type `to_type`, if possible.
376
///
377
/// Behavior:
378
/// * PrimitiveArray to PrimitiveArray: overflowing cast will be None
379
/// * Boolean to Utf8: `true` => '1', `false` => `0`
380
/// * Utf8 to numeric: strings that can't be parsed to numbers return null, float strings
381
/// in integer casts return null
382
/// * Numeric to boolean: 0 returns `false`, any other value returns `true`
383
/// * List to List: the underlying data type is cast
384
/// * Fixed Size List to List: the underlying data type is cast
385
/// * List to Fixed Size List: the offsets are checked for valid order, then the
386
/// underlying type is cast.
387
/// * List of UInt8 to Binary: the list of integers becomes binary data, nulls in the list means it becomes a null
388
/// * Struct to Struct: the underlying fields are cast.
389
/// * PrimitiveArray to List: a list array with 1 value per slot is created
390
/// * Date32 and Date64: precision lost when going to higher interval
391
/// * Time32 and Time64: precision lost when going to higher interval
392
/// * Timestamp and Date{32|64}: precision lost when going to higher interval
393
/// * Temporal to/from backing primitive: zero-copy with data type change
394
///
395
/// Unsupported Casts
396
/// * non-`StructArray` to `StructArray` or `StructArray` to non-`StructArray`
397
/// * List to primitive (other than UInt8)
398
/// * Utf8 to boolean
399
/// * Interval and duration
400
pub fn cast(
401
array: &dyn Array,
402
to_type: &ArrowDataType,
403
options: CastOptionsImpl,
404
) -> PolarsResult<Box<dyn Array>> {
405
use ArrowDataType::*;
406
let from_type = array.dtype();
407
408
// clone array if types are the same
409
if from_type == to_type {
410
return Ok(clone(array));
411
}
412
413
let as_options = options.with_wrapped(true);
414
match (from_type, to_type) {
415
(Null, _) | (_, Null) => Ok(new_null_array(to_type.clone(), array.len())),
416
(Struct(from_fd), Struct(to_fd)) => {
417
polars_ensure!(from_fd.len() == to_fd.len(), InvalidOperation: "Cannot cast struct with different number of fields.");
418
cast_struct(array.as_any().downcast_ref().unwrap(), to_type, options).map(|x| x.boxed())
419
},
420
(Struct(_), _) | (_, Struct(_)) => polars_bail!(InvalidOperation:
421
"Cannot cast from struct to other types"
422
),
423
(Dictionary(index_type, ..), _) => match_integer_type!(index_type, |$T| {
424
dictionary_cast_dyn::<$T>(array, to_type, options)
425
}),
426
(_, Dictionary(index_type, value_type, _)) => match_integer_type!(index_type, |$T| {
427
cast_to_dictionary::<$T>(array, value_type, options)
428
}),
429
// not supported by polars
430
// (List(_), FixedSizeList(inner, size)) => cast_list_to_fixed_size_list::<i32>(
431
// array.as_any().downcast_ref().unwrap(),
432
// inner.as_ref(),
433
// *size,
434
// options,
435
// )
436
// .map(|x| x.boxed()),
437
(LargeList(_), FixedSizeList(inner, size)) => cast_list_to_fixed_size_list::<i64>(
438
array.as_any().downcast_ref().unwrap(),
439
inner.as_ref(),
440
*size,
441
options,
442
)
443
.map(|x| x.boxed()),
444
(FixedSizeList(_, _), List(_)) => cast_fixed_size_list_to_list::<i32>(
445
array.as_any().downcast_ref().unwrap(),
446
to_type,
447
options,
448
)
449
.map(|x| x.boxed()),
450
(FixedSizeList(_, _), LargeList(_)) => cast_fixed_size_list_to_list::<i64>(
451
array.as_any().downcast_ref().unwrap(),
452
to_type,
453
options,
454
)
455
.map(|x| x.boxed()),
456
(List(field), BinaryView) if matches!(field.dtype(), UInt8) => {
457
cast_list_uint8_to_binary::<i32>(array.as_any().downcast_ref().unwrap())
458
.map(|arr| arr.boxed())
459
},
460
(LargeList(field), BinaryView) if matches!(field.dtype(), UInt8) => {
461
cast_list_uint8_to_binary::<i64>(array.as_any().downcast_ref().unwrap())
462
.map(|arr| arr.boxed())
463
},
464
(BinaryView, _) => match to_type {
465
Utf8View => array
466
.as_any()
467
.downcast_ref::<BinaryViewArray>()
468
.unwrap()
469
.to_utf8view()
470
.map(|arr| arr.boxed()),
471
LargeBinary => Ok(binview_to::view_to_binary::<i64>(
472
array.as_any().downcast_ref().unwrap(),
473
)
474
.boxed()),
475
LargeList(inner) if matches!(inner.dtype, ArrowDataType::UInt8) => {
476
let bin_array = view_to_binary::<i64>(array.as_any().downcast_ref().unwrap());
477
Ok(binary_to_list(&bin_array, to_type.clone()).boxed())
478
},
479
_ => polars_bail!(InvalidOperation:
480
"casting from {from_type:?} to {to_type:?} not supported",
481
),
482
},
483
(LargeList(_), LargeList(_)) => {
484
cast_list::<i64>(array.as_any().downcast_ref().unwrap(), to_type, options)
485
.map(|x| x.boxed())
486
},
487
(List(lhs), LargeList(rhs)) if lhs == rhs => {
488
Ok(cast_list_to_large_list(array.as_any().downcast_ref().unwrap(), to_type).boxed())
489
},
490
(LargeList(lhs), List(rhs)) if lhs == rhs => {
491
Ok(cast_large_to_list(array.as_any().downcast_ref().unwrap(), to_type).boxed())
492
},
493
494
(_, List(to)) => {
495
// cast primitive to list's primitive
496
let values = cast(array, &to.dtype, options)?;
497
// create offsets, where if array.len() = 2, we have [0,1,2]
498
let offsets = (0..=array.len() as i32).collect::<Vec<_>>();
499
// SAFETY: offsets _are_ monotonically increasing
500
let offsets = unsafe { Offsets::new_unchecked(offsets) };
501
502
let list_array = ListArray::<i32>::new(to_type.clone(), offsets.into(), values, None);
503
504
Ok(Box::new(list_array))
505
},
506
507
(_, LargeList(to)) if from_type != &LargeBinary => {
508
// cast primitive to list's primitive
509
let values = cast(array, &to.dtype, options)?;
510
// create offsets, where if array.len() = 2, we have [0,1,2]
511
let offsets = (0..=array.len() as i64).collect::<Vec<_>>();
512
// SAFETY: offsets _are_ monotonically increasing
513
let offsets = unsafe { Offsets::new_unchecked(offsets) };
514
515
let list_array = ListArray::<i64>::new(
516
to_type.clone(),
517
offsets.into(),
518
values,
519
array.validity().cloned(),
520
);
521
522
Ok(Box::new(list_array))
523
},
524
525
(Utf8View, _) => {
526
let arr = array.as_any().downcast_ref::<Utf8ViewArray>().unwrap();
527
528
match to_type {
529
BinaryView => Ok(arr.to_binview().boxed()),
530
LargeUtf8 => Ok(binview_to::utf8view_to_utf8::<i64>(arr).boxed()),
531
UInt8 => utf8view_to_primitive_dyn::<u8>(arr, to_type, options),
532
UInt16 => utf8view_to_primitive_dyn::<u16>(arr, to_type, options),
533
UInt32 => utf8view_to_primitive_dyn::<u32>(arr, to_type, options),
534
UInt64 => utf8view_to_primitive_dyn::<u64>(arr, to_type, options),
535
#[cfg(feature = "dtype-u128")]
536
UInt128 => utf8view_to_primitive_dyn::<u128>(arr, to_type, options),
537
Int8 => utf8view_to_primitive_dyn::<i8>(arr, to_type, options),
538
Int16 => utf8view_to_primitive_dyn::<i16>(arr, to_type, options),
539
Int32 => utf8view_to_primitive_dyn::<i32>(arr, to_type, options),
540
Int64 => utf8view_to_primitive_dyn::<i64>(arr, to_type, options),
541
#[cfg(feature = "dtype-i128")]
542
Int128 => utf8view_to_primitive_dyn::<i128>(arr, to_type, options),
543
#[cfg(feature = "dtype-f16")]
544
Float16 => utf8view_to_primitive_dyn::<pf16>(arr, to_type, options),
545
Float32 => utf8view_to_primitive_dyn::<f32>(arr, to_type, options),
546
Float64 => utf8view_to_primitive_dyn::<f64>(arr, to_type, options),
547
Timestamp(time_unit, None) => {
548
utf8view_to_naive_timestamp_dyn(array, time_unit.to_owned())
549
},
550
Timestamp(time_unit, Some(time_zone)) => utf8view_to_timestamp(
551
array.as_any().downcast_ref().unwrap(),
552
RFC3339,
553
time_zone.clone(),
554
time_unit.to_owned(),
555
)
556
.map(|arr| arr.boxed()),
557
Date32 => utf8view_to_date32_dyn(array),
558
#[cfg(feature = "dtype-decimal")]
559
Decimal(precision, scale) => {
560
Ok(binview_to_decimal(&arr.to_binview(), *precision, *scale).to_boxed())
561
},
562
_ => polars_bail!(InvalidOperation:
563
"casting from {from_type:?} to {to_type:?} not supported",
564
),
565
}
566
},
567
568
(_, Boolean) => match from_type {
569
UInt8 => primitive_to_boolean_dyn::<u8>(array, to_type.clone()),
570
UInt16 => primitive_to_boolean_dyn::<u16>(array, to_type.clone()),
571
UInt32 => primitive_to_boolean_dyn::<u32>(array, to_type.clone()),
572
UInt64 => primitive_to_boolean_dyn::<u64>(array, to_type.clone()),
573
#[cfg(feature = "dtype-u128")]
574
UInt128 => primitive_to_boolean_dyn::<u128>(array, to_type.clone()),
575
Int8 => primitive_to_boolean_dyn::<i8>(array, to_type.clone()),
576
Int16 => primitive_to_boolean_dyn::<i16>(array, to_type.clone()),
577
Int32 => primitive_to_boolean_dyn::<i32>(array, to_type.clone()),
578
Int64 => primitive_to_boolean_dyn::<i64>(array, to_type.clone()),
579
#[cfg(feature = "dtype-i128")]
580
Int128 => primitive_to_boolean_dyn::<i128>(array, to_type.clone()),
581
#[cfg(feature = "dtype-f16")]
582
Float16 => primitive_to_boolean_dyn::<pf16>(array, to_type.clone()),
583
Float32 => primitive_to_boolean_dyn::<f32>(array, to_type.clone()),
584
Float64 => primitive_to_boolean_dyn::<f64>(array, to_type.clone()),
585
#[cfg(feature = "dtype-decimal")]
586
Decimal(_, _) => primitive_to_boolean_dyn::<i128>(array, to_type.clone()),
587
_ => polars_bail!(InvalidOperation:
588
"casting from {from_type:?} to {to_type:?} not supported",
589
),
590
},
591
(Boolean, _) => match to_type {
592
UInt8 => boolean_to_primitive_dyn::<u8>(array),
593
UInt16 => boolean_to_primitive_dyn::<u16>(array),
594
UInt32 => boolean_to_primitive_dyn::<u32>(array),
595
UInt64 => boolean_to_primitive_dyn::<u64>(array),
596
#[cfg(feature = "dtype-u128")]
597
UInt128 => boolean_to_primitive_dyn::<u128>(array),
598
Int8 => boolean_to_primitive_dyn::<i8>(array),
599
Int16 => boolean_to_primitive_dyn::<i16>(array),
600
Int32 => boolean_to_primitive_dyn::<i32>(array),
601
Int64 => boolean_to_primitive_dyn::<i64>(array),
602
#[cfg(feature = "dtype-i128")]
603
Int128 => boolean_to_primitive_dyn::<i128>(array),
604
#[cfg(feature = "dtype-f16")]
605
Float16 => boolean_to_primitive_dyn::<pf16>(array),
606
Float32 => boolean_to_primitive_dyn::<f32>(array),
607
Float64 => boolean_to_primitive_dyn::<f64>(array),
608
Utf8View => boolean_to_utf8view_dyn(array),
609
BinaryView => boolean_to_binaryview_dyn(array),
610
_ => polars_bail!(InvalidOperation:
611
"casting from {from_type:?} to {to_type:?} not supported",
612
),
613
},
614
(_, BinaryView) => from_to_binview(array, from_type, to_type).map(|arr| arr.boxed()),
615
(_, Utf8View) => match from_type {
616
LargeUtf8 => Ok(utf8_to_utf8view(
617
array.as_any().downcast_ref::<Utf8Array<i64>>().unwrap(),
618
)
619
.boxed()),
620
Utf8 => Ok(
621
utf8_to_utf8view(array.as_any().downcast_ref::<Utf8Array<i32>>().unwrap()).boxed(),
622
),
623
#[cfg(feature = "dtype-decimal")]
624
Decimal(_, _) => Ok(decimal_to_utf8view_dyn(array).boxed()),
625
_ => from_to_binview(array, from_type, to_type)
626
.map(|arr| unsafe { arr.to_utf8view_unchecked() }.boxed()),
627
},
628
(Utf8, _) => match to_type {
629
LargeUtf8 => Ok(Box::new(utf8_to_large_utf8(
630
array.as_any().downcast_ref().unwrap(),
631
))),
632
_ => polars_bail!(InvalidOperation:
633
"casting from {from_type:?} to {to_type:?} not supported",
634
),
635
},
636
(LargeUtf8, _) => match to_type {
637
LargeBinary => Ok(utf8_to_binary::<i64>(
638
array.as_any().downcast_ref().unwrap(),
639
to_type.clone(),
640
)
641
.boxed()),
642
_ => polars_bail!(InvalidOperation:
643
"casting from {from_type:?} to {to_type:?} not supported",
644
),
645
},
646
(_, LargeUtf8) => match from_type {
647
UInt8 => primitive_to_utf8_dyn::<u8, i64>(array),
648
LargeBinary => {
649
binary_to_utf8::<i64>(array.as_any().downcast_ref().unwrap(), to_type.clone())
650
.map(|x| x.boxed())
651
},
652
_ => polars_bail!(InvalidOperation:
653
"casting from {from_type:?} to {to_type:?} not supported",
654
),
655
},
656
657
(Binary, _) => match to_type {
658
LargeBinary => Ok(Box::new(binary_to_large_binary(
659
array.as_any().downcast_ref().unwrap(),
660
to_type.clone(),
661
))),
662
_ => polars_bail!(InvalidOperation:
663
"casting from {from_type:?} to {to_type:?} not supported",
664
),
665
},
666
667
(LargeBinary, _) => match to_type {
668
UInt8 => binary_to_primitive_dyn::<i64, u8>(array, to_type, options),
669
UInt16 => binary_to_primitive_dyn::<i64, u16>(array, to_type, options),
670
UInt32 => binary_to_primitive_dyn::<i64, u32>(array, to_type, options),
671
UInt64 => binary_to_primitive_dyn::<i64, u64>(array, to_type, options),
672
#[cfg(feature = "dtype-u128")]
673
UInt128 => binary_to_primitive_dyn::<i64, u128>(array, to_type, options),
674
Int8 => binary_to_primitive_dyn::<i64, i8>(array, to_type, options),
675
Int16 => binary_to_primitive_dyn::<i64, i16>(array, to_type, options),
676
Int32 => binary_to_primitive_dyn::<i64, i32>(array, to_type, options),
677
Int64 => binary_to_primitive_dyn::<i64, i64>(array, to_type, options),
678
#[cfg(feature = "dtype-i128")]
679
Int128 => binary_to_primitive_dyn::<i64, i128>(array, to_type, options),
680
#[cfg(feature = "dtype-f16")]
681
Float16 => binary_to_primitive_dyn::<i64, pf16>(array, to_type, options),
682
Float32 => binary_to_primitive_dyn::<i64, f32>(array, to_type, options),
683
Float64 => binary_to_primitive_dyn::<i64, f64>(array, to_type, options),
684
Binary => {
685
binary_large_to_binary(array.as_any().downcast_ref().unwrap(), to_type.clone())
686
.map(|x| x.boxed())
687
},
688
LargeUtf8 => {
689
binary_to_utf8::<i64>(array.as_any().downcast_ref().unwrap(), to_type.clone())
690
.map(|x| x.boxed())
691
},
692
_ => polars_bail!(InvalidOperation:
693
"casting from {from_type:?} to {to_type:?} not supported",
694
),
695
},
696
(FixedSizeBinary(_), _) => match to_type {
697
Binary => Ok(fixed_size_binary_binary::<i32>(
698
array.as_any().downcast_ref().unwrap(),
699
to_type.clone(),
700
)
701
.boxed()),
702
LargeBinary => Ok(fixed_size_binary_binary::<i64>(
703
array.as_any().downcast_ref().unwrap(),
704
to_type.clone(),
705
)
706
.boxed()),
707
_ => polars_bail!(InvalidOperation:
708
"casting from {from_type:?} to {to_type:?} not supported",
709
),
710
},
711
// start numeric casts
712
(UInt8, UInt16) => primitive_to_primitive_dyn::<u8, u16>(array, to_type, as_options),
713
(UInt8, UInt32) => primitive_to_primitive_dyn::<u8, u32>(array, to_type, as_options),
714
(UInt8, UInt64) => primitive_to_primitive_dyn::<u8, u64>(array, to_type, as_options),
715
#[cfg(feature = "dtype-u128")]
716
(UInt8, UInt128) => primitive_to_primitive_dyn::<u8, u128>(array, to_type, options),
717
(UInt8, Int8) => primitive_to_primitive_dyn::<u8, i8>(array, to_type, options),
718
(UInt8, Int16) => primitive_to_primitive_dyn::<u8, i16>(array, to_type, options),
719
(UInt8, Int32) => primitive_to_primitive_dyn::<u8, i32>(array, to_type, options),
720
(UInt8, Int64) => primitive_to_primitive_dyn::<u8, i64>(array, to_type, options),
721
#[cfg(feature = "dtype-i128")]
722
(UInt8, Int128) => primitive_to_primitive_dyn::<u8, i128>(array, to_type, options),
723
#[cfg(feature = "dtype-f16")]
724
(UInt8, Float16) => primitive_to_primitive_dyn::<u8, pf16>(array, to_type, as_options),
725
(UInt8, Float32) => primitive_to_primitive_dyn::<u8, f32>(array, to_type, as_options),
726
(UInt8, Float64) => primitive_to_primitive_dyn::<u8, f64>(array, to_type, as_options),
727
#[cfg(feature = "dtype-decimal")]
728
(UInt8, Decimal(p, s)) => integer_to_decimal_dyn::<u8>(array, *p, *s),
729
730
(UInt16, UInt8) => primitive_to_primitive_dyn::<u16, u8>(array, to_type, options),
731
(UInt16, UInt32) => primitive_to_primitive_dyn::<u16, u32>(array, to_type, as_options),
732
(UInt16, UInt64) => primitive_to_primitive_dyn::<u16, u64>(array, to_type, as_options),
733
#[cfg(feature = "dtype-u128")]
734
(UInt16, UInt128) => primitive_to_primitive_dyn::<u16, u128>(array, to_type, options),
735
(UInt16, Int8) => primitive_to_primitive_dyn::<u16, i8>(array, to_type, options),
736
(UInt16, Int16) => primitive_to_primitive_dyn::<u16, i16>(array, to_type, options),
737
(UInt16, Int32) => primitive_to_primitive_dyn::<u16, i32>(array, to_type, options),
738
(UInt16, Int64) => primitive_to_primitive_dyn::<u16, i64>(array, to_type, options),
739
#[cfg(feature = "dtype-i128")]
740
(UInt16, Int128) => primitive_to_primitive_dyn::<u16, i128>(array, to_type, options),
741
#[cfg(feature = "dtype-f16")]
742
(UInt16, Float16) => primitive_to_primitive_dyn::<u16, pf16>(array, to_type, as_options),
743
(UInt16, Float32) => primitive_to_primitive_dyn::<u16, f32>(array, to_type, as_options),
744
(UInt16, Float64) => primitive_to_primitive_dyn::<u16, f64>(array, to_type, as_options),
745
#[cfg(feature = "dtype-decimal")]
746
(UInt16, Decimal(p, s)) => integer_to_decimal_dyn::<u16>(array, *p, *s),
747
748
(UInt32, UInt8) => primitive_to_primitive_dyn::<u32, u8>(array, to_type, options),
749
(UInt32, UInt16) => primitive_to_primitive_dyn::<u32, u16>(array, to_type, options),
750
(UInt32, UInt64) => primitive_to_primitive_dyn::<u32, u64>(array, to_type, as_options),
751
#[cfg(feature = "dtype-u128")]
752
(UInt32, UInt128) => primitive_to_primitive_dyn::<u32, u128>(array, to_type, options),
753
(UInt32, Int8) => primitive_to_primitive_dyn::<u32, i8>(array, to_type, options),
754
(UInt32, Int16) => primitive_to_primitive_dyn::<u32, i16>(array, to_type, options),
755
(UInt32, Int32) => primitive_to_primitive_dyn::<u32, i32>(array, to_type, options),
756
(UInt32, Int64) => primitive_to_primitive_dyn::<u32, i64>(array, to_type, options),
757
#[cfg(feature = "dtype-i128")]
758
(UInt32, Int128) => primitive_to_primitive_dyn::<u32, i128>(array, to_type, options),
759
#[cfg(feature = "dtype-f16")]
760
(UInt32, Float16) => primitive_to_primitive_dyn::<u32, pf16>(array, to_type, as_options),
761
(UInt32, Float32) => primitive_to_primitive_dyn::<u32, f32>(array, to_type, as_options),
762
(UInt32, Float64) => primitive_to_primitive_dyn::<u32, f64>(array, to_type, as_options),
763
#[cfg(feature = "dtype-decimal")]
764
(UInt32, Decimal(p, s)) => integer_to_decimal_dyn::<u32>(array, *p, *s),
765
766
(UInt64, UInt8) => primitive_to_primitive_dyn::<u64, u8>(array, to_type, options),
767
(UInt64, UInt16) => primitive_to_primitive_dyn::<u64, u16>(array, to_type, options),
768
(UInt64, UInt32) => primitive_to_primitive_dyn::<u64, u32>(array, to_type, options),
769
#[cfg(feature = "dtype-u128")]
770
(UInt64, UInt128) => primitive_to_primitive_dyn::<u64, u128>(array, to_type, options),
771
(UInt64, Int8) => primitive_to_primitive_dyn::<u64, i8>(array, to_type, options),
772
(UInt64, Int16) => primitive_to_primitive_dyn::<u64, i16>(array, to_type, options),
773
(UInt64, Int32) => primitive_to_primitive_dyn::<u64, i32>(array, to_type, options),
774
(UInt64, Int64) => primitive_to_primitive_dyn::<u64, i64>(array, to_type, options),
775
#[cfg(feature = "dtype-i128")]
776
(UInt64, Int128) => primitive_to_primitive_dyn::<u64, i128>(array, to_type, options),
777
#[cfg(feature = "dtype-f16")]
778
(UInt64, Float16) => primitive_to_primitive_dyn::<u64, pf16>(array, to_type, as_options),
779
(UInt64, Float32) => primitive_to_primitive_dyn::<u64, f32>(array, to_type, as_options),
780
(UInt64, Float64) => primitive_to_primitive_dyn::<u64, f64>(array, to_type, as_options),
781
#[cfg(feature = "dtype-decimal")]
782
(UInt64, Decimal(p, s)) => integer_to_decimal_dyn::<u64>(array, *p, *s),
783
784
#[cfg(feature = "dtype-u128")]
785
(UInt128, UInt8) => primitive_to_primitive_dyn::<u128, u8>(array, to_type, options),
786
#[cfg(feature = "dtype-u128")]
787
(UInt128, UInt16) => primitive_to_primitive_dyn::<u128, u16>(array, to_type, options),
788
#[cfg(feature = "dtype-u128")]
789
(UInt128, UInt32) => primitive_to_primitive_dyn::<u128, u32>(array, to_type, options),
790
#[cfg(feature = "dtype-u128")]
791
(UInt128, UInt64) => primitive_to_primitive_dyn::<u128, u64>(array, to_type, options),
792
#[cfg(feature = "dtype-u128")]
793
(UInt128, Int8) => primitive_to_primitive_dyn::<u128, i8>(array, to_type, options),
794
#[cfg(feature = "dtype-u128")]
795
(UInt128, Int16) => primitive_to_primitive_dyn::<u128, i16>(array, to_type, options),
796
#[cfg(feature = "dtype-u128")]
797
(UInt128, Int32) => primitive_to_primitive_dyn::<u128, i32>(array, to_type, options),
798
#[cfg(feature = "dtype-u128")]
799
(UInt128, Int64) => primitive_to_primitive_dyn::<u128, i64>(array, to_type, options),
800
#[cfg(all(feature = "dtype-u128", feature = "dtype-i128"))]
801
(UInt128, Int128) => primitive_to_primitive_dyn::<u128, i128>(array, to_type, options),
802
#[cfg(all(feature = "dtype-u128", feature = "dtype-f16"))]
803
(UInt128, Float16) => primitive_to_primitive_dyn::<u128, pf16>(array, to_type, as_options),
804
#[cfg(feature = "dtype-u128")]
805
(UInt128, Float32) => primitive_to_primitive_dyn::<u128, f32>(array, to_type, as_options),
806
#[cfg(feature = "dtype-u128")]
807
(UInt128, Float64) => primitive_to_primitive_dyn::<u128, f64>(array, to_type, as_options),
808
#[cfg(all(feature = "dtype-u128", feature = "dtype-decimal"))]
809
(UInt128, Decimal(p, s)) => integer_to_decimal_dyn::<u128>(array, *p, *s),
810
811
(Int8, UInt8) => primitive_to_primitive_dyn::<i8, u8>(array, to_type, options),
812
(Int8, UInt16) => primitive_to_primitive_dyn::<i8, u16>(array, to_type, options),
813
(Int8, UInt32) => primitive_to_primitive_dyn::<i8, u32>(array, to_type, options),
814
(Int8, UInt64) => primitive_to_primitive_dyn::<i8, u64>(array, to_type, options),
815
#[cfg(feature = "dtype-u128")]
816
(Int8, UInt128) => primitive_to_primitive_dyn::<i8, u128>(array, to_type, options),
817
(Int8, Int16) => primitive_to_primitive_dyn::<i8, i16>(array, to_type, as_options),
818
(Int8, Int32) => primitive_to_primitive_dyn::<i8, i32>(array, to_type, as_options),
819
(Int8, Int64) => primitive_to_primitive_dyn::<i8, i64>(array, to_type, as_options),
820
#[cfg(feature = "dtype-i128")]
821
(Int8, Int128) => primitive_to_primitive_dyn::<i8, i128>(array, to_type, as_options),
822
#[cfg(feature = "dtype-f16")]
823
(Int8, Float16) => primitive_to_primitive_dyn::<i8, pf16>(array, to_type, as_options),
824
(Int8, Float32) => primitive_to_primitive_dyn::<i8, f32>(array, to_type, as_options),
825
(Int8, Float64) => primitive_to_primitive_dyn::<i8, f64>(array, to_type, as_options),
826
#[cfg(feature = "dtype-decimal")]
827
(Int8, Decimal(p, s)) => integer_to_decimal_dyn::<i8>(array, *p, *s),
828
829
(Int16, UInt8) => primitive_to_primitive_dyn::<i16, u8>(array, to_type, options),
830
(Int16, UInt16) => primitive_to_primitive_dyn::<i16, u16>(array, to_type, options),
831
(Int16, UInt32) => primitive_to_primitive_dyn::<i16, u32>(array, to_type, options),
832
(Int16, UInt64) => primitive_to_primitive_dyn::<i16, u64>(array, to_type, options),
833
#[cfg(feature = "dtype-u128")]
834
(Int16, UInt128) => primitive_to_primitive_dyn::<i16, u128>(array, to_type, options),
835
(Int16, Int8) => primitive_to_primitive_dyn::<i16, i8>(array, to_type, options),
836
(Int16, Int32) => primitive_to_primitive_dyn::<i16, i32>(array, to_type, as_options),
837
(Int16, Int64) => primitive_to_primitive_dyn::<i16, i64>(array, to_type, as_options),
838
#[cfg(feature = "dtype-i128")]
839
(Int16, Int128) => primitive_to_primitive_dyn::<i16, i128>(array, to_type, as_options),
840
#[cfg(feature = "dtype-f16")]
841
(Int16, Float16) => primitive_to_primitive_dyn::<i16, pf16>(array, to_type, as_options),
842
(Int16, Float32) => primitive_to_primitive_dyn::<i16, f32>(array, to_type, as_options),
843
(Int16, Float64) => primitive_to_primitive_dyn::<i16, f64>(array, to_type, as_options),
844
#[cfg(feature = "dtype-decimal")]
845
(Int16, Decimal(p, s)) => integer_to_decimal_dyn::<i16>(array, *p, *s),
846
847
(Int32, UInt8) => primitive_to_primitive_dyn::<i32, u8>(array, to_type, options),
848
(Int32, UInt16) => primitive_to_primitive_dyn::<i32, u16>(array, to_type, options),
849
(Int32, UInt32) => primitive_to_primitive_dyn::<i32, u32>(array, to_type, options),
850
(Int32, UInt64) => primitive_to_primitive_dyn::<i32, u64>(array, to_type, options),
851
#[cfg(feature = "dtype-u128")]
852
(Int32, UInt128) => primitive_to_primitive_dyn::<i32, u128>(array, to_type, options),
853
(Int32, Int8) => primitive_to_primitive_dyn::<i32, i8>(array, to_type, options),
854
(Int32, Int16) => primitive_to_primitive_dyn::<i32, i16>(array, to_type, options),
855
(Int32, Int64) => primitive_to_primitive_dyn::<i32, i64>(array, to_type, as_options),
856
#[cfg(feature = "dtype-i128")]
857
(Int32, Int128) => primitive_to_primitive_dyn::<i32, i128>(array, to_type, as_options),
858
#[cfg(feature = "dtype-f16")]
859
(Int32, Float16) => primitive_to_primitive_dyn::<i32, pf16>(array, to_type, as_options),
860
(Int32, Float32) => primitive_to_primitive_dyn::<i32, f32>(array, to_type, as_options),
861
(Int32, Float64) => primitive_to_primitive_dyn::<i32, f64>(array, to_type, as_options),
862
#[cfg(feature = "dtype-decimal")]
863
(Int32, Decimal(p, s)) => integer_to_decimal_dyn::<i32>(array, *p, *s),
864
865
(Int64, UInt8) => primitive_to_primitive_dyn::<i64, u8>(array, to_type, options),
866
(Int64, UInt16) => primitive_to_primitive_dyn::<i64, u16>(array, to_type, options),
867
(Int64, UInt32) => primitive_to_primitive_dyn::<i64, u32>(array, to_type, options),
868
(Int64, UInt64) => primitive_to_primitive_dyn::<i64, u64>(array, to_type, options),
869
#[cfg(feature = "dtype-u128")]
870
(Int64, UInt128) => primitive_to_primitive_dyn::<i64, u128>(array, to_type, options),
871
(Int64, Int8) => primitive_to_primitive_dyn::<i64, i8>(array, to_type, options),
872
(Int64, Int16) => primitive_to_primitive_dyn::<i64, i16>(array, to_type, options),
873
(Int64, Int32) => primitive_to_primitive_dyn::<i64, i32>(array, to_type, options),
874
#[cfg(feature = "dtype-i128")]
875
(Int64, Int128) => primitive_to_primitive_dyn::<i64, i128>(array, to_type, options),
876
#[cfg(feature = "dtype-f16")]
877
(Int64, Float16) => primitive_to_primitive_dyn::<i64, pf16>(array, to_type, as_options),
878
(Int64, Float32) => primitive_to_primitive_dyn::<i64, f32>(array, to_type, options),
879
(Int64, Float64) => primitive_to_primitive_dyn::<i64, f64>(array, to_type, as_options),
880
#[cfg(feature = "dtype-decimal")]
881
(Int64, Decimal(p, s)) => integer_to_decimal_dyn::<i64>(array, *p, *s),
882
883
#[cfg(feature = "dtype-i128")]
884
(Int128, UInt8) => primitive_to_primitive_dyn::<i128, u8>(array, to_type, options),
885
#[cfg(feature = "dtype-i128")]
886
(Int128, UInt16) => primitive_to_primitive_dyn::<i128, u16>(array, to_type, options),
887
#[cfg(feature = "dtype-i128")]
888
(Int128, UInt32) => primitive_to_primitive_dyn::<i128, u32>(array, to_type, options),
889
#[cfg(feature = "dtype-i128")]
890
(Int128, UInt64) => primitive_to_primitive_dyn::<i128, u64>(array, to_type, options),
891
#[cfg(all(feature = "dtype-u128", feature = "dtype-i128"))]
892
(Int128, UInt128) => primitive_to_primitive_dyn::<i128, u128>(array, to_type, options),
893
#[cfg(feature = "dtype-i128")]
894
(Int128, Int8) => primitive_to_primitive_dyn::<i128, i8>(array, to_type, options),
895
#[cfg(feature = "dtype-i128")]
896
(Int128, Int16) => primitive_to_primitive_dyn::<i128, i16>(array, to_type, options),
897
#[cfg(feature = "dtype-i128")]
898
(Int128, Int32) => primitive_to_primitive_dyn::<i128, i32>(array, to_type, options),
899
#[cfg(feature = "dtype-i128")]
900
(Int128, Int64) => primitive_to_primitive_dyn::<i128, i64>(array, to_type, options),
901
#[cfg(all(feature = "dtype-i128", feature = "dtype-f16"))]
902
(Int128, Float16) => primitive_to_primitive_dyn::<i128, pf16>(array, to_type, as_options),
903
#[cfg(feature = "dtype-i128")]
904
(Int128, Float32) => primitive_to_primitive_dyn::<i128, f32>(array, to_type, options),
905
#[cfg(feature = "dtype-i128")]
906
(Int128, Float64) => primitive_to_primitive_dyn::<i128, f64>(array, to_type, as_options),
907
#[cfg(all(feature = "dtype-i128", feature = "dtype-decimal"))]
908
(Int128, Decimal(p, s)) => integer_to_decimal_dyn::<i128>(array, *p, *s),
909
910
#[cfg(feature = "dtype-f16")]
911
(Float16, UInt8) => primitive_to_primitive_dyn::<pf16, u8>(array, to_type, options),
912
#[cfg(feature = "dtype-f16")]
913
(Float16, UInt16) => primitive_to_primitive_dyn::<pf16, u16>(array, to_type, options),
914
#[cfg(feature = "dtype-f16")]
915
(Float16, UInt32) => primitive_to_primitive_dyn::<pf16, u32>(array, to_type, options),
916
#[cfg(feature = "dtype-f16")]
917
(Float16, UInt64) => primitive_to_primitive_dyn::<pf16, u64>(array, to_type, options),
918
#[cfg(all(feature = "dtype-f16", feature = "dtype-u128"))]
919
(Float16, UInt128) => primitive_to_primitive_dyn::<pf16, u128>(array, to_type, options),
920
#[cfg(feature = "dtype-f16")]
921
(Float16, Int8) => primitive_to_primitive_dyn::<pf16, i8>(array, to_type, options),
922
#[cfg(feature = "dtype-f16")]
923
(Float16, Int16) => primitive_to_primitive_dyn::<pf16, i16>(array, to_type, options),
924
#[cfg(feature = "dtype-f16")]
925
(Float16, Int32) => primitive_to_primitive_dyn::<pf16, i32>(array, to_type, options),
926
#[cfg(feature = "dtype-f16")]
927
(Float16, Int64) => primitive_to_primitive_dyn::<pf16, i64>(array, to_type, options),
928
#[cfg(all(feature = "dtype-f16", feature = "dtype-i128"))]
929
(Float16, Int128) => primitive_to_primitive_dyn::<pf16, i128>(array, to_type, options),
930
#[cfg(feature = "dtype-f16")]
931
(Float16, Float32) => primitive_to_primitive_dyn::<pf16, f32>(array, to_type, as_options),
932
#[cfg(feature = "dtype-f16")]
933
(Float16, Float64) => primitive_to_primitive_dyn::<pf16, f64>(array, to_type, as_options),
934
#[cfg(all(feature = "dtype-f16", feature = "dtype-decimal"))]
935
(Float16, Decimal(p, s)) => float_to_decimal_dyn::<pf16>(array, *p, *s),
936
937
(Float32, UInt8) => primitive_to_primitive_dyn::<f32, u8>(array, to_type, options),
938
(Float32, UInt16) => primitive_to_primitive_dyn::<f32, u16>(array, to_type, options),
939
(Float32, UInt32) => primitive_to_primitive_dyn::<f32, u32>(array, to_type, options),
940
(Float32, UInt64) => primitive_to_primitive_dyn::<f32, u64>(array, to_type, options),
941
#[cfg(feature = "dtype-u128")]
942
(Float32, UInt128) => primitive_to_primitive_dyn::<f32, u128>(array, to_type, options),
943
(Float32, Int8) => primitive_to_primitive_dyn::<f32, i8>(array, to_type, options),
944
(Float32, Int16) => primitive_to_primitive_dyn::<f32, i16>(array, to_type, options),
945
(Float32, Int32) => primitive_to_primitive_dyn::<f32, i32>(array, to_type, options),
946
(Float32, Int64) => primitive_to_primitive_dyn::<f32, i64>(array, to_type, options),
947
#[cfg(feature = "dtype-i128")]
948
(Float32, Int128) => primitive_to_primitive_dyn::<f32, i128>(array, to_type, options),
949
#[cfg(feature = "dtype-f16")]
950
(Float32, Float16) => primitive_to_primitive_dyn::<f32, pf16>(array, to_type, as_options),
951
(Float32, Float64) => primitive_to_primitive_dyn::<f32, f64>(array, to_type, as_options),
952
#[cfg(feature = "dtype-decimal")]
953
(Float32, Decimal(p, s)) => float_to_decimal_dyn::<f32>(array, *p, *s),
954
955
(Float64, UInt8) => primitive_to_primitive_dyn::<f64, u8>(array, to_type, options),
956
(Float64, UInt16) => primitive_to_primitive_dyn::<f64, u16>(array, to_type, options),
957
(Float64, UInt32) => primitive_to_primitive_dyn::<f64, u32>(array, to_type, options),
958
(Float64, UInt64) => primitive_to_primitive_dyn::<f64, u64>(array, to_type, options),
959
#[cfg(feature = "dtype-u128")]
960
(Float64, UInt128) => primitive_to_primitive_dyn::<f64, u128>(array, to_type, options),
961
(Float64, Int8) => primitive_to_primitive_dyn::<f64, i8>(array, to_type, options),
962
(Float64, Int16) => primitive_to_primitive_dyn::<f64, i16>(array, to_type, options),
963
(Float64, Int32) => primitive_to_primitive_dyn::<f64, i32>(array, to_type, options),
964
(Float64, Int64) => primitive_to_primitive_dyn::<f64, i64>(array, to_type, options),
965
#[cfg(feature = "dtype-i128")]
966
(Float64, Int128) => primitive_to_primitive_dyn::<f64, i128>(array, to_type, options),
967
#[cfg(feature = "dtype-f16")]
968
(Float64, Float16) => primitive_to_primitive_dyn::<f64, pf16>(array, to_type, as_options),
969
(Float64, Float32) => primitive_to_primitive_dyn::<f64, f32>(array, to_type, options),
970
#[cfg(feature = "dtype-decimal")]
971
(Float64, Decimal(p, s)) => float_to_decimal_dyn::<f64>(array, *p, *s),
972
973
#[cfg(feature = "dtype-decimal")]
974
(Decimal(_, _), UInt8) => decimal_to_integer_dyn::<u8>(array),
975
#[cfg(feature = "dtype-decimal")]
976
(Decimal(_, _), UInt16) => decimal_to_integer_dyn::<u16>(array),
977
#[cfg(feature = "dtype-decimal")]
978
(Decimal(_, _), UInt32) => decimal_to_integer_dyn::<u32>(array),
979
#[cfg(feature = "dtype-decimal")]
980
(Decimal(_, _), UInt64) => decimal_to_integer_dyn::<u64>(array),
981
#[cfg(all(feature = "dtype-decimal", feature = "dtype-u128"))]
982
(Decimal(_, _), UInt128) => decimal_to_integer_dyn::<u128>(array),
983
#[cfg(feature = "dtype-decimal")]
984
(Decimal(_, _), Int8) => decimal_to_integer_dyn::<i8>(array),
985
#[cfg(feature = "dtype-decimal")]
986
(Decimal(_, _), Int16) => decimal_to_integer_dyn::<i16>(array),
987
#[cfg(feature = "dtype-decimal")]
988
(Decimal(_, _), Int32) => decimal_to_integer_dyn::<i32>(array),
989
#[cfg(feature = "dtype-decimal")]
990
(Decimal(_, _), Int64) => decimal_to_integer_dyn::<i64>(array),
991
#[cfg(all(feature = "dtype-decimal", feature = "dtype-i128"))]
992
(Decimal(_, _), Int128) => decimal_to_integer_dyn::<i128>(array),
993
#[cfg(all(feature = "dtype-decimal", feature = "dtype-f16"))]
994
(Decimal(_, _), Float16) => decimal_to_float_dyn::<pf16>(array),
995
#[cfg(feature = "dtype-decimal")]
996
(Decimal(_, _), Float32) => decimal_to_float_dyn::<f32>(array),
997
#[cfg(feature = "dtype-decimal")]
998
(Decimal(_, _), Float64) => decimal_to_float_dyn::<f64>(array),
999
#[cfg(feature = "dtype-decimal")]
1000
(Decimal(_, _), Decimal(to_p, to_s)) => decimal_to_decimal_dyn(array, *to_p, *to_s),
1001
// end numeric casts
1002
1003
// temporal casts
1004
(Int32, Date32) => primitive_to_same_primitive_dyn::<i32>(array, to_type),
1005
(Int32, Time32(TimeUnit::Second)) => primitive_dyn!(array, int32_to_time32s),
1006
(Int32, Time32(TimeUnit::Millisecond)) => primitive_dyn!(array, int32_to_time32ms),
1007
// No support for microsecond/nanosecond with i32
1008
(Date32, Int32) => primitive_to_same_primitive_dyn::<i32>(array, to_type),
1009
(Date32, Int64) => primitive_to_primitive_dyn::<i32, i64>(array, to_type, options),
1010
(Time32(_), Int32) => primitive_to_same_primitive_dyn::<i32>(array, to_type),
1011
(Int64, Date64) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1012
// No support for second/milliseconds with i64
1013
(Int64, Time64(TimeUnit::Microsecond)) => primitive_dyn!(array, int64_to_time64us),
1014
(Int64, Time64(TimeUnit::Nanosecond)) => primitive_dyn!(array, int64_to_time64ns),
1015
1016
(Date64, Int32) => primitive_to_primitive_dyn::<i64, i32>(array, to_type, options),
1017
(Date64, Int64) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1018
(Time64(_), Int64) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1019
(Date32, Date64) => primitive_dyn!(array, date32_to_date64),
1020
(Date64, Date32) => primitive_dyn!(array, date64_to_date32),
1021
(Time32(TimeUnit::Second), Time32(TimeUnit::Millisecond)) => {
1022
primitive_dyn!(array, time32s_to_time32ms)
1023
},
1024
(Time32(TimeUnit::Millisecond), Time32(TimeUnit::Second)) => {
1025
primitive_dyn!(array, time32ms_to_time32s)
1026
},
1027
(Time32(from_unit), Time64(to_unit)) => {
1028
primitive_dyn!(array, time32_to_time64, *from_unit, *to_unit)
1029
},
1030
(Time64(TimeUnit::Microsecond), Time64(TimeUnit::Nanosecond)) => {
1031
primitive_dyn!(array, time64us_to_time64ns)
1032
},
1033
(Time64(TimeUnit::Nanosecond), Time64(TimeUnit::Microsecond)) => {
1034
primitive_dyn!(array, time64ns_to_time64us)
1035
},
1036
(Time64(from_unit), Time32(to_unit)) => {
1037
primitive_dyn!(array, time64_to_time32, *from_unit, *to_unit)
1038
},
1039
(Timestamp(_, _), Int64) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1040
(Int64, Timestamp(_, _)) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1041
(Timestamp(from_unit, _), Timestamp(to_unit, tz)) => {
1042
primitive_dyn!(array, timestamp_to_timestamp, *from_unit, *to_unit, tz)
1043
},
1044
(Timestamp(from_unit, _), Date32) => primitive_dyn!(array, timestamp_to_date32, *from_unit),
1045
(Timestamp(from_unit, _), Date64) => primitive_dyn!(array, timestamp_to_date64, *from_unit),
1046
1047
(Int64, Duration(_)) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1048
(Duration(_), Int64) => primitive_to_same_primitive_dyn::<i64>(array, to_type),
1049
1050
// Not supported by Polars.
1051
// (Interval(IntervalUnit::DayTime), Interval(IntervalUnit::MonthDayNano)) => {
1052
// primitive_dyn!(array, days_ms_to_months_days_ns)
1053
// },
1054
// (Interval(IntervalUnit::YearMonth), Interval(IntervalUnit::MonthDayNano)) => {
1055
// primitive_dyn!(array, months_to_months_days_ns)
1056
// },
1057
_ => polars_bail!(InvalidOperation:
1058
"casting from {from_type:?} to {to_type:?} not supported",
1059
),
1060
}
1061
}
1062
1063
/// Attempts to encode an array into an `ArrayDictionary` with index
1064
/// type K and value (dictionary) type value_type
1065
///
1066
/// K is the key type
1067
fn cast_to_dictionary<K: DictionaryKey>(
1068
array: &dyn Array,
1069
dict_value_type: &ArrowDataType,
1070
options: CastOptionsImpl,
1071
) -> PolarsResult<Box<dyn Array>> {
1072
let array = cast(array, dict_value_type, options)?;
1073
let array = array.as_ref();
1074
match dict_value_type.to_storage() {
1075
ArrowDataType::Int8 => primitive_to_dictionary_dyn::<i8, K>(array),
1076
ArrowDataType::Int16 => primitive_to_dictionary_dyn::<i16, K>(array),
1077
ArrowDataType::Int32 => primitive_to_dictionary_dyn::<i32, K>(array),
1078
ArrowDataType::Int64 => primitive_to_dictionary_dyn::<i64, K>(array),
1079
ArrowDataType::UInt8 => primitive_to_dictionary_dyn::<u8, K>(array),
1080
ArrowDataType::UInt16 => primitive_to_dictionary_dyn::<u16, K>(array),
1081
ArrowDataType::UInt32 => primitive_to_dictionary_dyn::<u32, K>(array),
1082
ArrowDataType::UInt64 => primitive_to_dictionary_dyn::<u64, K>(array),
1083
ArrowDataType::BinaryView => {
1084
binview_to_dictionary::<K>(array.as_any().downcast_ref().unwrap())
1085
.map(|arr| arr.boxed())
1086
},
1087
ArrowDataType::Utf8View => {
1088
utf8view_to_dictionary::<K>(array.as_any().downcast_ref().unwrap())
1089
.map(|arr| arr.boxed())
1090
},
1091
ArrowDataType::LargeUtf8 => utf8_to_dictionary_dyn::<i64, K>(array),
1092
ArrowDataType::LargeBinary => binary_to_dictionary_dyn::<i64, K>(array),
1093
ArrowDataType::Time64(_) => primitive_to_dictionary_dyn::<i64, K>(array),
1094
ArrowDataType::Timestamp(_, _) => primitive_to_dictionary_dyn::<i64, K>(array),
1095
ArrowDataType::Date32 => primitive_to_dictionary_dyn::<i32, K>(array),
1096
_ => polars_bail!(ComputeError:
1097
"unsupported output type for dictionary packing: {dict_value_type:?}"
1098
),
1099
}
1100
}
1101
1102
fn from_to_binview(
1103
array: &dyn Array,
1104
from_type: &ArrowDataType,
1105
to_type: &ArrowDataType,
1106
) -> PolarsResult<BinaryViewArray> {
1107
use ArrowDataType::*;
1108
let binview = match from_type {
1109
UInt8 => primitive_to_binview_dyn::<u8>(array),
1110
UInt16 => primitive_to_binview_dyn::<u16>(array),
1111
UInt32 => primitive_to_binview_dyn::<u32>(array),
1112
UInt64 => primitive_to_binview_dyn::<u64>(array),
1113
UInt128 => primitive_to_binview_dyn::<u128>(array),
1114
Int8 => primitive_to_binview_dyn::<i8>(array),
1115
Int16 => primitive_to_binview_dyn::<i16>(array),
1116
Int32 => primitive_to_binview_dyn::<i32>(array),
1117
Int64 => primitive_to_binview_dyn::<i64>(array),
1118
Int128 => primitive_to_binview_dyn::<i128>(array),
1119
Float16 => primitive_to_binview_dyn::<pf16>(array),
1120
Float32 => primitive_to_binview_dyn::<f32>(array),
1121
Float64 => primitive_to_binview_dyn::<f64>(array),
1122
Binary => binary_to_binview::<i32>(array.as_any().downcast_ref().unwrap()),
1123
FixedSizeBinary(_) => fixed_size_binary_to_binview(array.as_any().downcast_ref().unwrap()),
1124
LargeBinary => binary_to_binview::<i64>(array.as_any().downcast_ref().unwrap()),
1125
_ => polars_bail!(InvalidOperation:
1126
"casting from {from_type:?} to {to_type:?} not supported",
1127
),
1128
};
1129
Ok(binview)
1130
}
1131
1132
#[cfg(test)]
1133
mod tests {
1134
use arrow::offset::OffsetsBuffer;
1135
use polars_error::PolarsError;
1136
1137
use super::*;
1138
1139
/// When cfg(test), offsets for ``View``s generated by
1140
/// cast_list_uint8_to_binary() are limited to max value of 3, so buffers
1141
/// need to be split aggressively.
1142
#[test]
1143
fn cast_list_uint8_to_binary_across_buffer_max_size() {
1144
let dtype =
1145
ArrowDataType::List(Box::new(Field::new("".into(), ArrowDataType::UInt8, true)));
1146
let values = PrimitiveArray::from_slice((0u8..20).collect::<Vec<_>>()).boxed();
1147
let list_u8 = ListArray::try_new(
1148
dtype,
1149
unsafe { OffsetsBuffer::new_unchecked(vec![0, 13, 18, 20].into()) },
1150
values,
1151
None,
1152
)
1153
.unwrap();
1154
1155
let binary = cast(
1156
&list_u8,
1157
&ArrowDataType::BinaryView,
1158
CastOptionsImpl::default(),
1159
)
1160
.unwrap();
1161
let binary_array: &BinaryViewArray = binary.as_ref().as_any().downcast_ref().unwrap();
1162
assert_eq!(
1163
binary_array
1164
.values_iter()
1165
.map(|s| s.to_vec())
1166
.collect::<Vec<Vec<u8>>>(),
1167
vec![
1168
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
1169
vec![13, 14, 15, 16, 17],
1170
vec![18, 19]
1171
]
1172
);
1173
// max offset of 15 so we need to split:
1174
assert_eq!(
1175
binary_array
1176
.data_buffers()
1177
.iter()
1178
.map(|buf| buf.len())
1179
.collect::<Vec<_>>(),
1180
vec![13, 7]
1181
);
1182
}
1183
1184
/// Arrow spec requires views to fit in a single buffer. When cfg(test),
1185
/// buffers generated by cast_list_uint8_to_binary are of size 15 or
1186
/// smaller, so a list of size 16 should cause an error.
1187
#[test]
1188
fn cast_list_uint8_to_binary_errors_too_large_list() {
1189
let values = PrimitiveArray::from_slice(vec![0u8; 16]);
1190
let dtype =
1191
ArrowDataType::List(Box::new(Field::new("".into(), ArrowDataType::UInt8, true)));
1192
let list_u8 = ListArray::new(
1193
dtype,
1194
OffsetsBuffer::one_with_length(16),
1195
values.boxed(),
1196
None,
1197
);
1198
1199
let err = cast(
1200
&list_u8,
1201
&ArrowDataType::BinaryView,
1202
CastOptionsImpl::default(),
1203
)
1204
.unwrap_err();
1205
assert!(matches!(
1206
err,
1207
PolarsError::InvalidOperation(msg)
1208
if msg.as_ref() == "when casting to BinaryView, list lengths must be <= 15"
1209
));
1210
}
1211
1212
/// When all views are <=12, cast_list_uint8_to_binary drops buffers in the
1213
/// result because all views are inline.
1214
#[test]
1215
fn cast_list_uint8_to_binary_drops_small_buffers() {
1216
let values = PrimitiveArray::from_slice(vec![10u8; 12]);
1217
let dtype =
1218
ArrowDataType::List(Box::new(Field::new("".into(), ArrowDataType::UInt8, true)));
1219
let list_u8 = ListArray::new(
1220
dtype,
1221
OffsetsBuffer::one_with_length(12),
1222
values.boxed(),
1223
None,
1224
);
1225
let binary = cast(
1226
&list_u8,
1227
&ArrowDataType::BinaryView,
1228
CastOptionsImpl::default(),
1229
)
1230
.unwrap();
1231
let binary_array: &BinaryViewArray = binary.as_ref().as_any().downcast_ref().unwrap();
1232
assert!(binary_array.data_buffers().is_empty());
1233
assert_eq!(
1234
binary_array
1235
.values_iter()
1236
.map(|s| s.to_vec())
1237
.collect::<Vec<Vec<u8>>>(),
1238
vec![vec![10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],]
1239
);
1240
}
1241
}
1242
1243