use super::types::DataType;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CastContext {
Implicit,
Assignment,
Explicit,
}
impl CastContext {
pub fn allows(self, other: CastContext) -> bool {
use CastContext::*;
matches!(
(self, other),
(Explicit, _)
| (Assignment, Assignment)
| (Assignment, Implicit)
| (Implicit, Implicit)
)
}
}
#[derive(Debug, Clone, Copy)]
pub struct CastEntry {
pub src: DataType,
pub target: DataType,
pub context: CastContext,
pub lossy: bool,
}
pub const CAST_CATALOG: &[CastEntry] = &[
entry(
DataType::Integer,
DataType::BigInt,
CastContext::Implicit,
false,
),
entry(
DataType::Integer,
DataType::Float,
CastContext::Implicit,
false,
),
entry(
DataType::Integer,
DataType::Decimal,
CastContext::Implicit,
false,
),
entry(
DataType::UnsignedInteger,
DataType::Integer,
CastContext::Implicit,
false,
),
entry(
DataType::UnsignedInteger,
DataType::Float,
CastContext::Implicit,
false,
),
entry(
DataType::BigInt,
DataType::Float,
CastContext::Implicit,
false,
),
entry(
DataType::Float,
DataType::Integer,
CastContext::Assignment,
true,
),
entry(
DataType::Float,
DataType::BigInt,
CastContext::Assignment,
true,
),
entry(
DataType::Float,
DataType::UnsignedInteger,
CastContext::Assignment,
true,
),
entry(
DataType::Integer,
DataType::UnsignedInteger,
CastContext::Assignment,
true,
),
entry(
DataType::Integer,
DataType::Text,
CastContext::Explicit,
false,
),
entry(
DataType::UnsignedInteger,
DataType::Text,
CastContext::Explicit,
false,
),
entry(
DataType::Float,
DataType::Text,
CastContext::Explicit,
false,
),
entry(
DataType::Boolean,
DataType::Text,
CastContext::Explicit,
false,
),
entry(
DataType::Timestamp,
DataType::Text,
CastContext::Explicit,
false,
),
entry(DataType::Date, DataType::Text, CastContext::Explicit, false),
entry(DataType::Time, DataType::Text, CastContext::Explicit, false),
entry(DataType::Uuid, DataType::Text, CastContext::Explicit, false),
entry(
DataType::IpAddr,
DataType::Text,
CastContext::Explicit,
false,
),
entry(
DataType::Text,
DataType::Integer,
CastContext::Explicit,
true,
),
entry(DataType::Text, DataType::Float, CastContext::Explicit, true),
entry(
DataType::Text,
DataType::Boolean,
CastContext::Explicit,
true,
),
entry(DataType::Text, DataType::Email, CastContext::Explicit, true),
entry(DataType::Text, DataType::Url, CastContext::Explicit, true),
entry(DataType::Text, DataType::Phone, CastContext::Explicit, true),
entry(
DataType::Text,
DataType::Semver,
CastContext::Explicit,
true,
),
entry(DataType::Text, DataType::Cidr, CastContext::Explicit, true),
entry(DataType::Text, DataType::Date, CastContext::Explicit, true),
entry(DataType::Text, DataType::Time, CastContext::Explicit, true),
entry(DataType::Text, DataType::Uuid, CastContext::Explicit, true),
entry(DataType::Text, DataType::Color, CastContext::Explicit, true),
entry(
DataType::Text,
DataType::AssetCode,
CastContext::Explicit,
true,
),
entry(DataType::Text, DataType::Money, CastContext::Explicit, true),
entry(
DataType::Text,
DataType::IpAddr,
CastContext::Explicit,
true,
),
entry(
DataType::Boolean,
DataType::Integer,
CastContext::Explicit,
false,
),
entry(
DataType::Integer,
DataType::Boolean,
CastContext::Explicit,
false,
),
entry(
DataType::Integer,
DataType::Integer,
CastContext::Implicit,
false,
),
entry(
DataType::Float,
DataType::Float,
CastContext::Implicit,
false,
),
entry(DataType::Text, DataType::Text, CastContext::Implicit, false),
entry(
DataType::Boolean,
DataType::Boolean,
CastContext::Implicit,
false,
),
];
const fn entry(src: DataType, target: DataType, context: CastContext, lossy: bool) -> CastEntry {
CastEntry {
src,
target,
context,
lossy,
}
}
pub fn find_cast(src: DataType, target: DataType, ctx: CastContext) -> Option<CastEntry> {
if src == target {
return Some(CastEntry {
src,
target,
context: CastContext::Implicit,
lossy: false,
});
}
CAST_CATALOG
.iter()
.find(|e| e.src == src && e.target == target && e.context.allows(ctx))
.copied()
}
pub fn can_implicit_cast(src: DataType, target: DataType) -> bool {
find_cast(src, target, CastContext::Implicit).is_some()
}
pub fn can_assignment_cast(src: DataType, target: DataType) -> bool {
find_cast(src, target, CastContext::Assignment).is_some()
}
pub fn can_explicit_cast(src: DataType, target: DataType) -> bool {
find_cast(src, target, CastContext::Explicit).is_some()
}