1#[macro_use]
7mod macros;
8
9#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
16pub enum ScalarKind {
17 Account,
18 Blob,
19 Bool,
20 Date,
21 Decimal,
22 Duration,
23 Enum,
24 Float32,
25 Float64,
26 Int,
27 Int128,
28 IntBig,
29 Principal,
30 Subaccount,
31 Text,
32 Timestamp,
33 Nat,
34 Nat128,
35 NatBig,
36 Ulid,
37 Unit,
38}
39
40impl ScalarKind {
41 #[must_use]
43 pub const fn metadata(self) -> ScalarMetadata {
44 scalar_kind_registry!(metadata_from_registry, self)
45 }
46
47 #[must_use]
49 pub const fn coercion_family(self) -> ScalarCoercionFamily {
50 self.metadata().family
51 }
52
53 #[must_use]
55 pub const fn is_numeric_value(self) -> bool {
56 self.metadata().is_numeric_value
57 }
58
59 #[must_use]
61 pub const fn supports_numeric_coercion(self) -> bool {
62 self.metadata().supports_numeric_coercion
63 }
64
65 #[must_use]
67 pub const fn supports_arithmetic(self) -> bool {
68 self.metadata().supports_arithmetic
69 }
70
71 #[must_use]
73 pub const fn supports_equality(self) -> bool {
74 self.metadata().supports_equality
75 }
76
77 #[must_use]
79 pub const fn supports_ordering(self) -> bool {
80 self.metadata().supports_ordering
81 }
82
83 #[must_use]
85 pub const fn is_keyable(self) -> bool {
86 self.metadata().is_keyable
87 }
88
89 #[must_use]
91 pub const fn is_primary_key_component_encodable(self) -> bool {
92 self.metadata().is_primary_key_component_encodable
93 }
94}
95
96#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103#[expect(clippy::struct_excessive_bools)]
104pub struct ScalarMetadata {
105 family: ScalarCoercionFamily,
106 is_numeric_value: bool,
107 supports_numeric_coercion: bool,
108 supports_arithmetic: bool,
109 supports_equality: bool,
110 supports_ordering: bool,
111 is_keyable: bool,
112 is_primary_key_component_encodable: bool,
113}
114
115impl ScalarMetadata {
116 #[must_use]
118 pub const fn family(self) -> ScalarCoercionFamily {
119 self.family
120 }
121
122 #[must_use]
124 pub const fn is_numeric_value(self) -> bool {
125 self.is_numeric_value
126 }
127
128 #[must_use]
130 pub const fn supports_numeric_coercion(self) -> bool {
131 self.supports_numeric_coercion
132 }
133
134 #[must_use]
136 pub const fn supports_arithmetic(self) -> bool {
137 self.supports_arithmetic
138 }
139
140 #[must_use]
142 pub const fn supports_equality(self) -> bool {
143 self.supports_equality
144 }
145
146 #[must_use]
148 pub const fn supports_ordering(self) -> bool {
149 self.supports_ordering
150 }
151
152 #[must_use]
154 pub const fn is_keyable(self) -> bool {
155 self.is_keyable
156 }
157
158 #[must_use]
160 pub const fn is_primary_key_component_encodable(self) -> bool {
161 self.is_primary_key_component_encodable
162 }
163}
164
165#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
172pub enum ScalarCoercionFamily {
173 Numeric,
174 Textual,
175 Identifier,
176 Enum,
177 Blob,
178 Bool,
179 Unit,
180}
181
182pub const ALL_SCALAR_KINDS: [ScalarKind; 21] = scalar_kind_registry!(all_kinds_from_registry);
184
185#[cfg(test)]
186mod tests {
187 use super::{ALL_SCALAR_KINDS, ScalarKind};
188 use std::collections::HashSet;
189
190 const EXPECTED_SCALAR_KINDS: [ScalarKind; 21] = [
191 ScalarKind::Account,
192 ScalarKind::Blob,
193 ScalarKind::Bool,
194 ScalarKind::Date,
195 ScalarKind::Decimal,
196 ScalarKind::Duration,
197 ScalarKind::Enum,
198 ScalarKind::Float32,
199 ScalarKind::Float64,
200 ScalarKind::Int,
201 ScalarKind::Int128,
202 ScalarKind::IntBig,
203 ScalarKind::Principal,
204 ScalarKind::Subaccount,
205 ScalarKind::Text,
206 ScalarKind::Timestamp,
207 ScalarKind::Nat,
208 ScalarKind::Nat128,
209 ScalarKind::NatBig,
210 ScalarKind::Ulid,
211 ScalarKind::Unit,
212 ];
213
214 #[test]
215 fn all_scalar_kinds_has_expected_length_and_order() {
216 assert_eq!(ALL_SCALAR_KINDS, EXPECTED_SCALAR_KINDS);
217 }
218
219 #[test]
220 fn all_scalar_kinds_is_unique() {
221 let unique = ALL_SCALAR_KINDS.into_iter().collect::<HashSet<_>>();
222
223 assert_eq!(unique.len(), ALL_SCALAR_KINDS.len());
224 }
225
226 #[test]
227 fn all_scalar_kind_variants_are_audited() {
228 for kind in EXPECTED_SCALAR_KINDS {
229 assert_variant_is_known(kind);
230 }
231 }
232
233 #[test]
234 fn all_scalar_kinds_metadata_is_available() {
235 for kind in ALL_SCALAR_KINDS {
236 let metadata = kind.metadata();
237
238 assert_eq!(kind.coercion_family(), metadata.family());
239 assert_eq!(kind.is_numeric_value(), metadata.is_numeric_value());
240 assert_eq!(
241 kind.supports_numeric_coercion(),
242 metadata.supports_numeric_coercion(),
243 );
244 assert_eq!(kind.supports_arithmetic(), metadata.supports_arithmetic());
245 assert_eq!(kind.supports_equality(), metadata.supports_equality());
246 assert_eq!(kind.supports_ordering(), metadata.supports_ordering());
247 assert_eq!(kind.is_keyable(), metadata.is_keyable());
248 assert_eq!(
249 kind.is_primary_key_component_encodable(),
250 metadata.is_primary_key_component_encodable(),
251 );
252 }
253 }
254
255 fn assert_variant_is_known(kind: ScalarKind) {
256 match kind {
257 ScalarKind::Account
258 | ScalarKind::Blob
259 | ScalarKind::Bool
260 | ScalarKind::Date
261 | ScalarKind::Decimal
262 | ScalarKind::Duration
263 | ScalarKind::Enum
264 | ScalarKind::Float32
265 | ScalarKind::Float64
266 | ScalarKind::Int
267 | ScalarKind::Int128
268 | ScalarKind::IntBig
269 | ScalarKind::Principal
270 | ScalarKind::Subaccount
271 | ScalarKind::Text
272 | ScalarKind::Timestamp
273 | ScalarKind::Nat
274 | ScalarKind::Nat128
275 | ScalarKind::NatBig
276 | ScalarKind::Ulid
277 | ScalarKind::Unit => {}
278 }
279 }
280}