Skip to main content

icydb_primitives/
lib.rs

1#[macro_use]
2mod macros;
3
4///
5/// ScalarKind
6///
7/// Canonical scalar kind used for shared capability metadata.
8///
9
10#[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    /// Return the full metadata descriptor for one scalar kind.
37    #[must_use]
38    pub const fn metadata(self) -> ScalarMetadata {
39        scalar_kind_registry!(metadata_from_registry, self)
40    }
41
42    /// Return coercion routing family for this scalar kind.
43    #[must_use]
44    pub const fn coercion_family(self) -> ScalarCoercionFamily {
45        self.metadata().family
46    }
47
48    /// Return whether this scalar participates in numeric-valued classification.
49    #[must_use]
50    pub const fn is_numeric_value(self) -> bool {
51        self.metadata().is_numeric_value
52    }
53
54    /// Return whether this scalar supports numeric widening coercion.
55    #[must_use]
56    pub const fn supports_numeric_coercion(self) -> bool {
57        self.metadata().supports_numeric_coercion
58    }
59
60    /// Return whether this scalar supports arithmetic trait derivation.
61    #[must_use]
62    pub const fn supports_arithmetic(self) -> bool {
63        self.metadata().supports_arithmetic
64    }
65
66    /// Return whether this scalar supports equality predicates.
67    #[must_use]
68    pub const fn supports_equality(self) -> bool {
69        self.metadata().supports_equality
70    }
71
72    /// Return whether this scalar supports ordering predicates.
73    #[must_use]
74    pub const fn supports_ordering(self) -> bool {
75        self.metadata().supports_ordering
76    }
77
78    /// Return whether this scalar is keyable at query/schema level.
79    #[must_use]
80    pub const fn is_keyable(self) -> bool {
81        self.metadata().is_keyable
82    }
83
84    /// Return whether this scalar can be encoded as a storage key.
85    #[must_use]
86    pub const fn is_storage_key_encodable(self) -> bool {
87        self.metadata().is_storage_key_encodable
88    }
89}
90
91///
92/// ScalarMetadata
93///
94/// Capability metadata shared across schema/core layers.
95///
96
97#[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    /// Return coercion routing family for this scalar metadata entry.
112    #[must_use]
113    pub const fn family(self) -> ScalarCoercionFamily {
114        self.family
115    }
116
117    /// Return whether this scalar participates in numeric-valued classification.
118    #[must_use]
119    pub const fn is_numeric_value(self) -> bool {
120        self.is_numeric_value
121    }
122
123    /// Return whether this scalar supports numeric widening coercion.
124    #[must_use]
125    pub const fn supports_numeric_coercion(self) -> bool {
126        self.supports_numeric_coercion
127    }
128
129    /// Return whether this scalar supports arithmetic trait derivation.
130    #[must_use]
131    pub const fn supports_arithmetic(self) -> bool {
132        self.supports_arithmetic
133    }
134
135    /// Return whether this scalar supports equality predicates.
136    #[must_use]
137    pub const fn supports_equality(self) -> bool {
138        self.supports_equality
139    }
140
141    /// Return whether this scalar supports ordering predicates.
142    #[must_use]
143    pub const fn supports_ordering(self) -> bool {
144        self.supports_ordering
145    }
146
147    /// Return whether this scalar is keyable at query/schema level.
148    #[must_use]
149    pub const fn is_keyable(self) -> bool {
150        self.is_keyable
151    }
152
153    /// Return whether this scalar can be encoded as a storage key.
154    #[must_use]
155    pub const fn is_storage_key_encodable(self) -> bool {
156        self.is_storage_key_encodable
157    }
158}
159
160///
161/// ScalarCoercionFamily
162///
163/// Coarse scalar routing family used by query coercion and validation.
164///
165
166#[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
177/// Ordered list of all scalar kinds in registry order.
178pub 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}