icydb_core/db/predicate/
coercion.rs1use crate::value::CoercionFamily;
7use std::collections::BTreeMap;
8
9#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
19pub enum CoercionId {
20 Strict,
21 NumericWiden,
22 TextCasefold,
23 CollectionElement,
24}
25
26impl CoercionId {
27 #[must_use]
29 pub const fn plan_hash_tag(self) -> u8 {
30 match self {
31 Self::Strict => 0x01,
32 Self::NumericWiden => 0x02,
33 Self::TextCasefold => 0x04,
34 Self::CollectionElement => 0x05,
35 }
36 }
37}
38
39#[derive(Clone, Debug, Eq, PartialEq)]
46pub struct CoercionSpec {
47 pub id: CoercionId,
48 pub params: BTreeMap<String, String>,
49}
50
51impl CoercionSpec {
52 #[must_use]
53 pub const fn new(id: CoercionId) -> Self {
54 Self {
55 id,
56 params: BTreeMap::new(),
57 }
58 }
59}
60
61impl Default for CoercionSpec {
62 fn default() -> Self {
63 Self::new(CoercionId::Strict)
64 }
65}
66
67#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74pub(crate) enum CoercionRuleFamily {
75 Any,
76 Family(CoercionFamily),
77}
78
79#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86pub(crate) struct CoercionRule {
87 pub left: CoercionRuleFamily,
88 pub right: CoercionRuleFamily,
89 pub id: CoercionId,
90}
91
92pub(crate) const COERCION_TABLE: &[CoercionRule] = &[
93 CoercionRule {
94 left: CoercionRuleFamily::Any,
95 right: CoercionRuleFamily::Any,
96 id: CoercionId::Strict,
97 },
98 CoercionRule {
99 left: CoercionRuleFamily::Family(CoercionFamily::Numeric),
100 right: CoercionRuleFamily::Family(CoercionFamily::Numeric),
101 id: CoercionId::NumericWiden,
102 },
103 CoercionRule {
104 left: CoercionRuleFamily::Family(CoercionFamily::Textual),
105 right: CoercionRuleFamily::Family(CoercionFamily::Textual),
106 id: CoercionId::TextCasefold,
107 },
108 CoercionRule {
109 left: CoercionRuleFamily::Any,
110 right: CoercionRuleFamily::Any,
111 id: CoercionId::CollectionElement,
112 },
113];
114
115#[must_use]
117pub(in crate::db) fn supports_coercion(
118 left: CoercionFamily,
119 right: CoercionFamily,
120 id: CoercionId,
121) -> bool {
122 COERCION_TABLE.iter().any(|rule| {
123 rule.id == id && family_matches(rule.left, left) && family_matches(rule.right, right)
124 })
125}
126
127fn family_matches(rule: CoercionRuleFamily, value: CoercionFamily) -> bool {
128 match rule {
129 CoercionRuleFamily::Any => true,
130 CoercionRuleFamily::Family(expected) => expected == value,
131 }
132}