icydb_core/db/predicate/
coercion.rs1use crate::value::CoercionFamily;
7use std::fmt;
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, Eq, PartialEq)]
46pub struct CoercionSpec {
47 pub(crate) id: CoercionId,
48 pub(crate) params: Vec<(String, String)>,
49}
50
51impl CoercionSpec {
52 #[must_use]
53 pub const fn new(id: CoercionId) -> Self {
54 Self {
55 id,
56 params: Vec::new(),
57 }
58 }
59
60 #[must_use]
62 pub const fn id(&self) -> CoercionId {
63 self.id
64 }
65
66 #[must_use]
68 pub const fn params(&self) -> &[(String, String)] {
69 self.params.as_slice()
70 }
71}
72
73impl fmt::Debug for CoercionSpec {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.debug_struct("CoercionSpec")
76 .field("id", &self.id)
77 .field("params", &CoercionParamsDebug(&self.params))
78 .finish()
79 }
80}
81
82impl Default for CoercionSpec {
83 fn default() -> Self {
84 Self::new(CoercionId::Strict)
85 }
86}
87
88struct CoercionParamsDebug<'a>(&'a [(String, String)]);
91
92impl fmt::Debug for CoercionParamsDebug<'_> {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 let mut debug = f.debug_map();
95 for (key, value) in self.0 {
96 debug.entry(key, value);
97 }
98
99 debug.finish()
100 }
101}
102
103#[must_use]
105pub(in crate::db) fn supports_coercion(
106 left: CoercionFamily,
107 right: CoercionFamily,
108 id: CoercionId,
109) -> bool {
110 match id {
111 CoercionId::Strict | CoercionId::CollectionElement => true,
112 CoercionId::NumericWiden => {
113 left == CoercionFamily::Numeric && right == CoercionFamily::Numeric
114 }
115 CoercionId::TextCasefold => {
116 left == CoercionFamily::Textual && right == CoercionFamily::Textual
117 }
118 }
119}
120
121#[cfg(test)]
126mod tests {
127 use crate::{
128 db::predicate::{CoercionId, coercion::supports_coercion},
129 value::CoercionFamily,
130 };
131
132 #[test]
133 fn supports_coercion_matches_canonical_family_matrix() {
134 assert!(supports_coercion(
135 CoercionFamily::Numeric,
136 CoercionFamily::Textual,
137 CoercionId::Strict,
138 ));
139 assert!(supports_coercion(
140 CoercionFamily::Textual,
141 CoercionFamily::Numeric,
142 CoercionId::CollectionElement,
143 ));
144
145 assert!(supports_coercion(
146 CoercionFamily::Numeric,
147 CoercionFamily::Numeric,
148 CoercionId::NumericWiden,
149 ));
150 assert!(!supports_coercion(
151 CoercionFamily::Numeric,
152 CoercionFamily::Textual,
153 CoercionId::NumericWiden,
154 ));
155
156 assert!(supports_coercion(
157 CoercionFamily::Textual,
158 CoercionFamily::Textual,
159 CoercionId::TextCasefold,
160 ));
161 assert!(!supports_coercion(
162 CoercionFamily::Textual,
163 CoercionFamily::Numeric,
164 CoercionId::TextCasefold,
165 ));
166 }
167}