Skip to main content

icydb_primitives/
lib.rs

1//! Module: lib
2//! Responsibility: shared primitive capability metadata used across schema and runtime.
3//! Does not own: query coercion policy, storage encoding, or schema validation.
4//! Boundary: exposes compact scalar-kind capability descriptors and registry order.
5
6#[macro_use]
7mod macros;
8
9///
10/// ScalarKind
11///
12/// Canonical scalar kind used for shared capability metadata.
13///
14
15#[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    /// Return the full metadata descriptor for one scalar kind.
42    #[must_use]
43    pub const fn metadata(self) -> ScalarMetadata {
44        scalar_kind_registry!(metadata_from_registry, self)
45    }
46
47    /// Return coercion routing family for this scalar kind.
48    #[must_use]
49    pub const fn coercion_family(self) -> ScalarCoercionFamily {
50        self.metadata().family
51    }
52
53    /// Return whether this scalar participates in numeric-valued classification.
54    #[must_use]
55    pub const fn is_numeric_value(self) -> bool {
56        self.metadata().is_numeric_value
57    }
58
59    /// Return whether this scalar supports numeric widening coercion.
60    #[must_use]
61    pub const fn supports_numeric_coercion(self) -> bool {
62        self.metadata().supports_numeric_coercion
63    }
64
65    /// Return whether this scalar supports arithmetic trait derivation.
66    #[must_use]
67    pub const fn supports_arithmetic(self) -> bool {
68        self.metadata().supports_arithmetic
69    }
70
71    /// Return whether this scalar supports equality predicates.
72    #[must_use]
73    pub const fn supports_equality(self) -> bool {
74        self.metadata().supports_equality
75    }
76
77    /// Return whether this scalar supports ordering predicates.
78    #[must_use]
79    pub const fn supports_ordering(self) -> bool {
80        self.metadata().supports_ordering
81    }
82
83    /// Return whether this scalar is keyable at query/schema level.
84    #[must_use]
85    pub const fn is_keyable(self) -> bool {
86        self.metadata().is_keyable
87    }
88
89    /// Return whether this scalar can be encoded as a storage key.
90    #[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///
97/// ScalarMetadata
98///
99/// Capability metadata shared across schema/core layers.
100///
101
102#[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    /// Return coercion routing family for this scalar metadata entry.
117    #[must_use]
118    pub const fn family(self) -> ScalarCoercionFamily {
119        self.family
120    }
121
122    /// Return whether this scalar participates in numeric-valued classification.
123    #[must_use]
124    pub const fn is_numeric_value(self) -> bool {
125        self.is_numeric_value
126    }
127
128    /// Return whether this scalar supports numeric widening coercion.
129    #[must_use]
130    pub const fn supports_numeric_coercion(self) -> bool {
131        self.supports_numeric_coercion
132    }
133
134    /// Return whether this scalar supports arithmetic trait derivation.
135    #[must_use]
136    pub const fn supports_arithmetic(self) -> bool {
137        self.supports_arithmetic
138    }
139
140    /// Return whether this scalar supports equality predicates.
141    #[must_use]
142    pub const fn supports_equality(self) -> bool {
143        self.supports_equality
144    }
145
146    /// Return whether this scalar supports ordering predicates.
147    #[must_use]
148    pub const fn supports_ordering(self) -> bool {
149        self.supports_ordering
150    }
151
152    /// Return whether this scalar is keyable at query/schema level.
153    #[must_use]
154    pub const fn is_keyable(self) -> bool {
155        self.is_keyable
156    }
157
158    /// Return whether this scalar can be encoded as a storage key.
159    #[must_use]
160    pub const fn is_primary_key_component_encodable(self) -> bool {
161        self.is_primary_key_component_encodable
162    }
163}
164
165///
166/// ScalarCoercionFamily
167///
168/// Coarse scalar routing family used by query coercion and validation.
169///
170
171#[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
182/// Ordered list of all scalar kinds in registry order.
183pub 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}