use super::cast::CastRule;
use super::cast::builtin::BUILTIN_CAST_FUNCTION_SETS;
use crate::arrays::datatype::DataTypeId;
pub const NO_CAST_SCORE: u32 = 800;
const TO_ANY_SCORE: u32 = 10;
const NULL_TO_LIST_SCORE: u32 = 10;
pub fn implicit_cast_score(have: DataTypeId, want: DataTypeId) -> Option<u32> {
if want == DataTypeId::Any {
return Some(TO_ANY_SCORE);
}
if have == DataTypeId::Null && matches!(want, DataTypeId::List) {
return Some(NULL_TO_LIST_SCORE);
}
for cast_set in BUILTIN_CAST_FUNCTION_SETS {
if cast_set.target == want {
for cast_fn in cast_set.functions {
if cast_fn.src == have {
if let CastRule::Implicit(score) = cast_fn.rule {
return Some(score);
}
}
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn implicit_cast_from_utf8() {
assert!(implicit_cast_score(DataTypeId::Utf8, DataTypeId::Int32).is_some());
}
#[test]
fn allow_implicit_to_utf8() {
assert!(implicit_cast_score(DataTypeId::Int16, DataTypeId::Utf8).is_some());
assert!(implicit_cast_score(DataTypeId::Float64, DataTypeId::Utf8).is_some());
}
#[test]
fn integer_casts() {
assert!(implicit_cast_score(DataTypeId::Int16, DataTypeId::Int64).is_some());
assert!(implicit_cast_score(DataTypeId::Int16, DataTypeId::Decimal64).is_some());
assert!(implicit_cast_score(DataTypeId::Int16, DataTypeId::Float32).is_some());
assert!(implicit_cast_score(DataTypeId::Int16, DataTypeId::UInt64).is_none());
assert!(implicit_cast_score(DataTypeId::Int64, DataTypeId::Decimal64).is_none());
}
#[test]
fn float_casts() {
assert!(implicit_cast_score(DataTypeId::Float64, DataTypeId::Decimal64).is_some());
assert!(implicit_cast_score(DataTypeId::Float64, DataTypeId::Int64).is_none());
}
#[test]
fn decimal_to_float_scores_higher_than_float_to_decimal() {
let d_to_f_score = implicit_cast_score(DataTypeId::Decimal64, DataTypeId::Float32).unwrap();
let f_to_d_score = implicit_cast_score(DataTypeId::Float32, DataTypeId::Decimal64).unwrap();
assert!(d_to_f_score > f_to_d_score);
let d_to_f_score = implicit_cast_score(DataTypeId::Decimal64, DataTypeId::Float64).unwrap();
let f_to_d_score = implicit_cast_score(DataTypeId::Float64, DataTypeId::Decimal64).unwrap();
assert!(d_to_f_score > f_to_d_score);
}
#[test]
fn prefer_cast_int32_to_int64() {
let to_int64_score = implicit_cast_score(DataTypeId::Int32, DataTypeId::Int64).unwrap();
let to_float32_score = implicit_cast_score(DataTypeId::Int32, DataTypeId::Float32).unwrap();
assert!(
to_int64_score > to_float32_score,
"int64: {to_int64_score}, float32: {to_float32_score}"
);
}
}