use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use vortex_error::vortex_bail;
use vortex_error::vortex_ensure;
use crate::dtype::DType;
use crate::scalar::Scalar;
impl Scalar {
pub fn cast(&self, target_dtype: &DType) -> VortexResult<Scalar> {
if self.dtype() == target_dtype {
return Ok(self.clone());
}
if self.dtype().eq_ignore_nullability(target_dtype) {
return Scalar::try_new(target_dtype.clone(), self.value().cloned());
}
if self.value().is_none() || matches!(self.dtype(), DType::Null) {
vortex_ensure!(
target_dtype.is_nullable(),
"Cannot cast null to {target_dtype}: target type is non-nullable"
);
return Scalar::try_new(target_dtype.clone(), self.value().cloned());
}
if let Some(ext_dtype) = target_dtype.as_extension_opt() {
let cast_storage_scalar_value = self.cast(ext_dtype.storage_dtype())?.into_value();
return Scalar::try_new(target_dtype.clone(), cast_storage_scalar_value);
}
match &self.dtype() {
DType::Null => unreachable!("Handled by the if case above"),
DType::Bool(_) => self.as_bool().cast(target_dtype),
DType::Primitive(..) => self.as_primitive().cast(target_dtype),
DType::Decimal(..) => self.as_decimal().cast(target_dtype),
DType::Utf8(_) => self.as_utf8().cast(target_dtype),
DType::Binary(_) => self.as_binary().cast(target_dtype),
DType::Struct(..) => self.as_struct().cast(target_dtype),
DType::List(..) | DType::FixedSizeList(..) => self.as_list().cast(target_dtype),
DType::Extension(..) => self.as_extension().cast(target_dtype),
DType::Variant(_) => vortex_bail!("Variant scalars can't be cast to {target_dtype}"),
}
}
pub fn into_nullable(self) -> Scalar {
let (dtype, value) = self.into_parts();
Self::try_new(dtype.as_nullable(), value)
.vortex_expect("Casting to nullable should always succeed")
}
}