use std::sync::Arc;
use super::{cast_out_of_range_error, libcudf_cast, stored_counts};
use crate::{
core::{
column::{Column, ColumnView},
error::Result,
scalar::Scalar,
types::{DataType, TimestampResolution, TypeId},
},
ops::{
binary::{self, BinaryOperator},
reduction,
},
runtime::execution_domain::ExecutionDomain,
};
pub(super) fn resolutions(from: TypeId, to: TypeId) -> Option<(TimestampResolution, TimestampResolution)> {
from.timestamp_resolution()
.zip(to.timestamp_resolution())
.or_else(|| from.duration_resolution().zip(to.duration_resolution()))
}
pub(super) fn cast(
input: &ColumnView<'_>,
input_type: &DataType,
output_type: &DataType,
(from, to): (TimestampResolution, TimestampResolution),
output_domain: &Arc<ExecutionDomain>,
exec_options: &cudf_sys::cudf_exec_options_t,
operation: &'static str,
) -> Result<Column> {
let (from_ticks, to_ticks) = (from.nanoseconds_per_tick(), to.nanoseconds_per_tick());
if from_ticks > to_ticks {
let factor = from_ticks / to_ticks;
validate_product_fits(input, input_type, output_type, factor, output_domain, exec_options, operation)?;
return libcudf_cast(input, input_type, output_type, output_domain, exec_options, operation);
}
if to == TimestampResolution::Days {
return libcudf_cast(input, input_type, output_type, output_domain, exec_options, operation);
}
let int64 = DataType::new(TypeId::Int64);
let counts = stored_counts(input, input_type, output_domain, exec_options, operation)?;
let divisor = Scalar::from_value_in_domain(to_ticks / from_ticks, output_domain)?;
let quotients = binary::binary_operation_vs_impl(
&counts.view()?,
&divisor,
BinaryOperator::Div,
&int64,
output_domain,
exec_options,
operation,
)?;
let duration_type = DataType::new(to.duration_type_id());
let durations = libcudf_cast("ients.view()?, &int64, &duration_type, output_domain, exec_options, operation)?;
if output_type.id().is_duration() {
return Ok(durations);
}
libcudf_cast(&durations.view()?, &duration_type, output_type, output_domain, exec_options, operation)
}
fn validate_product_fits(
input: &ColumnView<'_>,
input_type: &DataType,
output_type: &DataType,
factor: i64,
output_domain: &Arc<ExecutionDomain>,
exec_options: &cudf_sys::cudf_exec_options_t,
operation: &'static str,
) -> Result<()> {
let counts = stored_counts(input, input_type, output_domain, exec_options, operation)?;
let (min, max) = reduction::minmax_impl(&counts.view()?, output_domain, exec_options, operation)?;
if !min.is_valid()? {
return Ok(());
}
let out_of_range = |reason: &'static str| {
cast_out_of_range_error(
operation,
input_type,
output_type,
reason,
"cast to a finer resolution overflows Int64 in a valid row",
)
};
if min.value::<i64>()? < i64::MIN / factor {
return Err(out_of_range("below_target_range"));
}
if max.value::<i64>()? > i64::MAX / factor {
return Err(out_of_range("above_target_range"));
}
Ok(())
}