icydb_core/db/predicate/
coercion.rs1use crate::value::CoercionFamily;
2use std::collections::BTreeMap;
3
4#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub enum CoercionId {
15 Strict,
16 NumericWiden,
17 TextCasefold,
18 CollectionElement,
19}
20
21impl CoercionId {
22 #[must_use]
24 pub const fn plan_hash_tag(self) -> u8 {
25 match self {
26 Self::Strict => 0x01,
27 Self::NumericWiden => 0x02,
28 Self::TextCasefold => 0x04,
29 Self::CollectionElement => 0x05,
30 }
31 }
32}
33
34#[derive(Clone, Debug, Eq, PartialEq)]
41pub struct CoercionSpec {
42 pub id: CoercionId,
43 pub params: BTreeMap<String, String>,
44}
45
46impl CoercionSpec {
47 #[must_use]
48 pub const fn new(id: CoercionId) -> Self {
49 Self {
50 id,
51 params: BTreeMap::new(),
52 }
53 }
54}
55
56impl Default for CoercionSpec {
57 fn default() -> Self {
58 Self::new(CoercionId::Strict)
59 }
60}
61
62#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub(crate) enum CoercionRuleFamily {
70 Any,
71 Family(CoercionFamily),
72}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
81pub(crate) struct CoercionRule {
82 pub left: CoercionRuleFamily,
83 pub right: CoercionRuleFamily,
84 pub id: CoercionId,
85}
86
87pub(crate) const COERCION_TABLE: &[CoercionRule] = &[
88 CoercionRule {
89 left: CoercionRuleFamily::Any,
90 right: CoercionRuleFamily::Any,
91 id: CoercionId::Strict,
92 },
93 CoercionRule {
94 left: CoercionRuleFamily::Family(CoercionFamily::Numeric),
95 right: CoercionRuleFamily::Family(CoercionFamily::Numeric),
96 id: CoercionId::NumericWiden,
97 },
98 CoercionRule {
99 left: CoercionRuleFamily::Family(CoercionFamily::Textual),
100 right: CoercionRuleFamily::Family(CoercionFamily::Textual),
101 id: CoercionId::TextCasefold,
102 },
103 CoercionRule {
104 left: CoercionRuleFamily::Any,
105 right: CoercionRuleFamily::Any,
106 id: CoercionId::CollectionElement,
107 },
108];
109
110#[must_use]
112pub(in crate::db) fn supports_coercion(
113 left: CoercionFamily,
114 right: CoercionFamily,
115 id: CoercionId,
116) -> bool {
117 COERCION_TABLE.iter().any(|rule| {
118 rule.id == id && family_matches(rule.left, left) && family_matches(rule.right, right)
119 })
120}
121
122fn family_matches(rule: CoercionRuleFamily, value: CoercionFamily) -> bool {
123 match rule {
124 CoercionRuleFamily::Any => true,
125 CoercionRuleFamily::Family(expected) => expected == value,
126 }
127}