1#[macro_use]
2mod macros;
3
4#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
11pub enum ScalarKind {
12 Account,
13 Blob,
14 Bool,
15 Date,
16 Decimal,
17 Duration,
18 Enum,
19 Float32,
20 Float64,
21 Int,
22 Int128,
23 IntBig,
24 Principal,
25 Subaccount,
26 Text,
27 Timestamp,
28 Nat,
29 Nat128,
30 NatBig,
31 Ulid,
32 Unit,
33}
34
35impl ScalarKind {
36 #[must_use]
38 pub const fn metadata(self) -> ScalarMetadata {
39 scalar_kind_registry!(metadata_from_registry, self)
40 }
41
42 #[must_use]
44 pub const fn coercion_family(self) -> ScalarCoercionFamily {
45 self.metadata().family
46 }
47
48 #[must_use]
50 pub const fn is_numeric_value(self) -> bool {
51 self.metadata().is_numeric_value
52 }
53
54 #[must_use]
56 pub const fn supports_numeric_coercion(self) -> bool {
57 self.metadata().supports_numeric_coercion
58 }
59
60 #[must_use]
62 pub const fn supports_arithmetic(self) -> bool {
63 self.metadata().supports_arithmetic
64 }
65
66 #[must_use]
68 pub const fn supports_equality(self) -> bool {
69 self.metadata().supports_equality
70 }
71
72 #[must_use]
74 pub const fn supports_ordering(self) -> bool {
75 self.metadata().supports_ordering
76 }
77
78 #[must_use]
80 pub const fn is_keyable(self) -> bool {
81 self.metadata().is_keyable
82 }
83
84 #[must_use]
86 pub const fn is_storage_key_encodable(self) -> bool {
87 self.metadata().is_storage_key_encodable
88 }
89}
90
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
98#[expect(clippy::struct_excessive_bools)]
99pub struct ScalarMetadata {
100 family: ScalarCoercionFamily,
101 is_numeric_value: bool,
102 supports_numeric_coercion: bool,
103 supports_arithmetic: bool,
104 supports_equality: bool,
105 supports_ordering: bool,
106 is_keyable: bool,
107 is_storage_key_encodable: bool,
108}
109
110impl ScalarMetadata {
111 #[must_use]
113 pub const fn family(self) -> ScalarCoercionFamily {
114 self.family
115 }
116
117 #[must_use]
119 pub const fn is_numeric_value(self) -> bool {
120 self.is_numeric_value
121 }
122
123 #[must_use]
125 pub const fn supports_numeric_coercion(self) -> bool {
126 self.supports_numeric_coercion
127 }
128
129 #[must_use]
131 pub const fn supports_arithmetic(self) -> bool {
132 self.supports_arithmetic
133 }
134
135 #[must_use]
137 pub const fn supports_equality(self) -> bool {
138 self.supports_equality
139 }
140
141 #[must_use]
143 pub const fn supports_ordering(self) -> bool {
144 self.supports_ordering
145 }
146
147 #[must_use]
149 pub const fn is_keyable(self) -> bool {
150 self.is_keyable
151 }
152
153 #[must_use]
155 pub const fn is_storage_key_encodable(self) -> bool {
156 self.is_storage_key_encodable
157 }
158}
159
160#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
167pub enum ScalarCoercionFamily {
168 Numeric,
169 Textual,
170 Identifier,
171 Enum,
172 Blob,
173 Bool,
174 Unit,
175}
176
177pub const ALL_SCALAR_KINDS: [ScalarKind; 21] = scalar_kind_registry!(all_kinds_from_registry);
179
180#[cfg(test)]
181mod tests {
182 use super::{ALL_SCALAR_KINDS, ScalarKind};
183 use std::collections::HashSet;
184
185 const EXPECTED_SCALAR_KINDS: [ScalarKind; 21] = [
186 ScalarKind::Account,
187 ScalarKind::Blob,
188 ScalarKind::Bool,
189 ScalarKind::Date,
190 ScalarKind::Decimal,
191 ScalarKind::Duration,
192 ScalarKind::Enum,
193 ScalarKind::Float32,
194 ScalarKind::Float64,
195 ScalarKind::Int,
196 ScalarKind::Int128,
197 ScalarKind::IntBig,
198 ScalarKind::Principal,
199 ScalarKind::Subaccount,
200 ScalarKind::Text,
201 ScalarKind::Timestamp,
202 ScalarKind::Nat,
203 ScalarKind::Nat128,
204 ScalarKind::NatBig,
205 ScalarKind::Ulid,
206 ScalarKind::Unit,
207 ];
208
209 #[test]
210 fn all_scalar_kinds_has_expected_length_and_order() {
211 assert_eq!(ALL_SCALAR_KINDS.len(), EXPECTED_SCALAR_KINDS.len());
212 assert_eq!(ALL_SCALAR_KINDS, EXPECTED_SCALAR_KINDS);
213 }
214
215 #[test]
216 fn all_scalar_kinds_is_unique() {
217 let unique = ALL_SCALAR_KINDS.into_iter().collect::<HashSet<_>>();
218
219 assert_eq!(unique.len(), ALL_SCALAR_KINDS.len());
220 }
221
222 #[test]
223 fn all_scalar_kinds_covers_every_variant() {
224 let all = ALL_SCALAR_KINDS.into_iter().collect::<HashSet<_>>();
225
226 for kind in EXPECTED_SCALAR_KINDS {
227 assert!(all.contains(&kind), "ALL_SCALAR_KINDS missing {kind:?}");
228 assert_variant_is_known(kind);
229 }
230 }
231
232 #[test]
233 fn all_scalar_kinds_metadata_is_available() {
234 for kind in ALL_SCALAR_KINDS {
235 let metadata = kind.metadata();
236
237 assert_eq!(kind.coercion_family(), metadata.family());
238 assert_eq!(kind.is_numeric_value(), metadata.is_numeric_value());
239 assert_eq!(
240 kind.supports_numeric_coercion(),
241 metadata.supports_numeric_coercion(),
242 );
243 assert_eq!(kind.supports_arithmetic(), metadata.supports_arithmetic());
244 assert_eq!(kind.supports_equality(), metadata.supports_equality());
245 assert_eq!(kind.supports_ordering(), metadata.supports_ordering());
246 assert_eq!(kind.is_keyable(), metadata.is_keyable());
247 assert_eq!(
248 kind.is_storage_key_encodable(),
249 metadata.is_storage_key_encodable(),
250 );
251 }
252 }
253
254 fn assert_variant_is_known(kind: ScalarKind) {
255 match kind {
256 ScalarKind::Account
257 | ScalarKind::Blob
258 | ScalarKind::Bool
259 | ScalarKind::Date
260 | ScalarKind::Decimal
261 | ScalarKind::Duration
262 | ScalarKind::Enum
263 | ScalarKind::Float32
264 | ScalarKind::Float64
265 | ScalarKind::Int
266 | ScalarKind::Int128
267 | ScalarKind::IntBig
268 | ScalarKind::Principal
269 | ScalarKind::Subaccount
270 | ScalarKind::Text
271 | ScalarKind::Timestamp
272 | ScalarKind::Nat
273 | ScalarKind::Nat128
274 | ScalarKind::NatBig
275 | ScalarKind::Ulid
276 | ScalarKind::Unit => {}
277 }
278 }
279}