use crate::value::CoercionFamily;
use std::fmt;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CoercionId {
Strict,
NumericWiden,
TextCasefold,
CollectionElement,
}
impl CoercionId {
#[must_use]
pub const fn plan_hash_tag(self) -> u8 {
match self {
Self::Strict => 0x01,
Self::NumericWiden => 0x02,
Self::TextCasefold => 0x04,
Self::CollectionElement => 0x05,
}
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct CoercionSpec {
pub(crate) id: CoercionId,
pub(crate) params: Vec<(String, String)>,
}
impl CoercionSpec {
#[must_use]
pub const fn new(id: CoercionId) -> Self {
Self {
id,
params: Vec::new(),
}
}
}
impl fmt::Debug for CoercionSpec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CoercionSpec")
.field("id", &self.id)
.field("params", &CoercionParamsDebug(&self.params))
.finish()
}
}
impl Default for CoercionSpec {
fn default() -> Self {
Self::new(CoercionId::Strict)
}
}
struct CoercionParamsDebug<'a>(&'a [(String, String)]);
impl fmt::Debug for CoercionParamsDebug<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug = f.debug_map();
for (key, value) in self.0 {
debug.entry(key, value);
}
debug.finish()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum CoercionRuleFamily {
Any,
Family(CoercionFamily),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct CoercionRule {
left: CoercionRuleFamily,
right: CoercionRuleFamily,
id: CoercionId,
}
pub(crate) const COERCION_TABLE: &[CoercionRule] = &[
CoercionRule {
left: CoercionRuleFamily::Any,
right: CoercionRuleFamily::Any,
id: CoercionId::Strict,
},
CoercionRule {
left: CoercionRuleFamily::Family(CoercionFamily::Numeric),
right: CoercionRuleFamily::Family(CoercionFamily::Numeric),
id: CoercionId::NumericWiden,
},
CoercionRule {
left: CoercionRuleFamily::Family(CoercionFamily::Textual),
right: CoercionRuleFamily::Family(CoercionFamily::Textual),
id: CoercionId::TextCasefold,
},
CoercionRule {
left: CoercionRuleFamily::Any,
right: CoercionRuleFamily::Any,
id: CoercionId::CollectionElement,
},
];
#[must_use]
pub(in crate::db) fn supports_coercion(
left: CoercionFamily,
right: CoercionFamily,
id: CoercionId,
) -> bool {
COERCION_TABLE.iter().any(|rule| {
rule.id == id && family_matches(rule.left, left) && family_matches(rule.right, right)
})
}
fn family_matches(rule: CoercionRuleFamily, value: CoercionFamily) -> bool {
match rule {
CoercionRuleFamily::Any => true,
CoercionRuleFamily::Family(expected) => expected == value,
}
}