Skip to main content

icydb_core/traits/
mod.rs

1//! Module: traits
2//!
3//! Responsibility: core trait surface shared across values, entities, and visitors.
4//! Does not own: executor/runtime policy or public facade DTO behavior.
5//! Boundary: reusable domain contracts consumed throughout `icydb-core`.
6
7#[macro_use]
8mod macros;
9mod numeric_value;
10mod visitor;
11
12use crate::{
13    error::InternalError,
14    model::field::{FieldKind, FieldModel, FieldStorageDecode},
15    prelude::*,
16    types::{EntityTag, Id},
17    value::{StorageKey, StorageKeyEncodeError, Value, ValueEnum},
18    visitor::VisitorContext,
19};
20use std::collections::{BTreeMap, BTreeSet};
21
22pub use numeric_value::*;
23pub use visitor::*;
24
25// -----------------------------------------------------------------------------
26// Standard re-exports for `traits::X` ergonomics
27// -----------------------------------------------------------------------------
28
29pub use canic_cdk::structures::storable::Storable;
30pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
31pub use std::{
32    cmp::{Eq, Ordering, PartialEq},
33    convert::From,
34    default::Default,
35    fmt::Debug,
36    hash::Hash,
37    ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign},
38};
39
40// ============================================================================
41// FOUNDATIONAL KINDS
42// ============================================================================
43//
44// These traits define *where* something lives in the system,
45// not what data it contains.
46//
47
48///
49/// Path
50/// Fully-qualified schema path.
51///
52
53pub trait Path {
54    const PATH: &'static str;
55}
56
57///
58/// Kind
59/// Marker for all schema/runtime nodes.
60///
61
62pub trait Kind: Path + 'static {}
63impl<T> Kind for T where T: Path + 'static {}
64
65///
66/// CanisterKind
67/// Marker for canister namespaces
68///
69
70pub trait CanisterKind: Kind {
71    /// Stable memory slot used for commit marker storage.
72    const COMMIT_MEMORY_ID: u8;
73
74    /// Durable stable-memory allocation key for commit marker storage.
75    const COMMIT_STABLE_KEY: &'static str;
76}
77
78///
79/// StoreKind
80/// Marker for data stores bound to a canister
81///
82
83pub trait StoreKind: Kind {
84    type Canister: CanisterKind;
85}
86
87// ============================================================================
88// ENTITY IDENTITY & SCHEMA
89// ============================================================================
90//
91// These traits describe *what an entity is*, not how it is stored
92// or manipulated at runtime.
93//
94
95///
96/// EntityKey
97///
98/// Associates an entity with the primitive type used as its primary key.
99///
100/// ## Semantics
101/// - Implemented for entity types
102/// - `Self::Key` is the *storage representation* of the primary key
103/// - Keys are plain values (Ulid, u64, Principal, …)
104/// - Typed identity is provided by `Id<Self>`, not by the key itself
105/// - Keys are public identifiers and are never authority-bearing capabilities
106///
107
108pub trait EntityKey {
109    type Key: Copy
110        + Debug
111        + Eq
112        + Ord
113        + KeyValueCodec
114        + StorageKeyCodec
115        + StorageKeyDecode
116        + EntityKeyBytes
117        + 'static;
118}
119
120///
121/// EntityKeyBytes
122///
123
124pub trait EntityKeyBytes {
125    /// Exact number of bytes produced.
126    const BYTE_LEN: usize;
127
128    /// Write bytes into the provided buffer.
129    fn write_bytes(&self, out: &mut [u8]);
130}
131
132macro_rules! impl_entity_key_bytes_numeric {
133    ($($ty:ty),* $(,)?) => {
134        $(
135            impl EntityKeyBytes for $ty {
136                const BYTE_LEN: usize = ::core::mem::size_of::<Self>();
137
138                fn write_bytes(&self, out: &mut [u8]) {
139                    assert_eq!(out.len(), Self::BYTE_LEN);
140                    out.copy_from_slice(&self.to_be_bytes());
141                }
142            }
143        )*
144    };
145}
146
147impl_entity_key_bytes_numeric!(i8, i16, i32, i64, u8, u16, u32, u64);
148
149impl EntityKeyBytes for () {
150    const BYTE_LEN: usize = 0;
151
152    fn write_bytes(&self, out: &mut [u8]) {
153        assert_eq!(out.len(), Self::BYTE_LEN);
154    }
155}
156
157///
158/// KeyValueCodec
159///
160/// Narrow runtime `Value` codec for typed primary keys and key-only access
161/// surfaces. This exists to keep cursor, access, and key-routing contracts off
162/// the wider structured-value conversion surface used by persisted-field
163/// codecs and planner queryability metadata.
164///
165
166pub trait KeyValueCodec {
167    fn to_key_value(&self) -> Value;
168
169    #[must_use]
170    fn from_key_value(value: &Value) -> Option<Self>
171    where
172        Self: Sized;
173}
174
175///
176/// StorageKeyCodec
177///
178/// Narrow typed storage-key codec for persistence and indexing admission.
179/// This keeps typed key ownership off the runtime `Value -> StorageKey` bridge
180/// so persisted identity boundaries can encode directly into `StorageKey`.
181///
182pub trait StorageKeyCodec {
183    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError>;
184}
185
186///
187/// StorageKeyDecode
188///
189/// Narrow typed storage-key decode contract for persistence and indexing
190/// boundaries.
191/// This keeps typed key recovery off the runtime `StorageKey -> Value` bridge
192/// so persisted identity boundaries can decode directly from `StorageKey`.
193///
194pub trait StorageKeyDecode: Sized {
195    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError>;
196}
197
198fn storage_key_variant_decode_failed(
199    type_name: &'static str,
200    key: StorageKey,
201    expected: &'static str,
202) -> InternalError {
203    InternalError::store_corruption(format!(
204        "storage key decode failed for `{type_name}`: expected {expected}, found {key:?}",
205    ))
206}
207
208fn storage_key_range_decode_failed(type_name: &'static str, key: StorageKey) -> InternalError {
209    InternalError::store_corruption(format!(
210        "storage key decode failed for `{type_name}`: value out of range for {key:?}",
211    ))
212}
213
214macro_rules! impl_storage_key_codec_signed {
215    ($($ty:ty),* $(,)?) => {
216        $(
217            impl StorageKeyCodec for $ty {
218                fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
219                    Ok(StorageKey::Int(i64::from(*self)))
220                }
221            }
222        )*
223    };
224}
225
226macro_rules! impl_storage_key_codec_unsigned {
227    ($($ty:ty),* $(,)?) => {
228        $(
229            impl StorageKeyCodec for $ty {
230                fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
231                    Ok(StorageKey::Nat(u64::from(*self)))
232                }
233            }
234        )*
235    };
236}
237
238impl<T> KeyValueCodec for T
239where
240    T: RuntimeValueDecode + RuntimeValueEncode,
241{
242    fn to_key_value(&self) -> Value {
243        self.to_value()
244    }
245
246    fn from_key_value(value: &Value) -> Option<Self> {
247        Self::from_value(value)
248    }
249}
250
251impl_storage_key_codec_signed!(i8, i16, i32, i64);
252impl_storage_key_codec_unsigned!(u8, u16, u32, u64);
253
254macro_rules! impl_storage_key_decode_signed {
255    ($($ty:ty),* $(,)?) => {
256        $(
257            impl StorageKeyDecode for $ty {
258                fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
259                    let StorageKey::Int(value) = key else {
260                        return Err(storage_key_variant_decode_failed(
261                            ::std::any::type_name::<Self>(),
262                            key,
263                            "StorageKey::Int",
264                        ));
265                    };
266
267                    Self::try_from(value).map_err(|_| {
268                        storage_key_range_decode_failed(::std::any::type_name::<Self>(), key)
269                    })
270                }
271            }
272        )*
273    };
274}
275
276macro_rules! impl_storage_key_decode_unsigned {
277    ($($ty:ty),* $(,)?) => {
278        $(
279            impl StorageKeyDecode for $ty {
280                fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
281                    let StorageKey::Nat(value) = key else {
282                        return Err(storage_key_variant_decode_failed(
283                            ::std::any::type_name::<Self>(),
284                            key,
285                            "StorageKey::Nat",
286                        ));
287                    };
288
289                    Self::try_from(value).map_err(|_| {
290                        storage_key_range_decode_failed(::std::any::type_name::<Self>(), key)
291                    })
292                }
293            }
294        )*
295    };
296}
297
298impl_storage_key_decode_signed!(i8, i16, i32, i64);
299impl_storage_key_decode_unsigned!(u8, u16, u32, u64);
300
301impl StorageKeyCodec for crate::types::Principal {
302    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
303        Ok(StorageKey::Principal(*self))
304    }
305}
306
307impl StorageKeyDecode for crate::types::Principal {
308    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
309        match key {
310            StorageKey::Principal(value) => Ok(value),
311            other => Err(storage_key_variant_decode_failed(
312                ::std::any::type_name::<Self>(),
313                other,
314                "StorageKey::Principal",
315            )),
316        }
317    }
318}
319
320impl StorageKeyCodec for crate::types::Subaccount {
321    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
322        Ok(StorageKey::Subaccount(*self))
323    }
324}
325
326impl StorageKeyDecode for crate::types::Subaccount {
327    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
328        match key {
329            StorageKey::Subaccount(value) => Ok(value),
330            other => Err(storage_key_variant_decode_failed(
331                ::std::any::type_name::<Self>(),
332                other,
333                "StorageKey::Subaccount",
334            )),
335        }
336    }
337}
338
339impl StorageKeyCodec for crate::types::Account {
340    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
341        Ok(StorageKey::Account(*self))
342    }
343}
344
345impl StorageKeyDecode for crate::types::Account {
346    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
347        match key {
348            StorageKey::Account(value) => Ok(value),
349            other => Err(storage_key_variant_decode_failed(
350                ::std::any::type_name::<Self>(),
351                other,
352                "StorageKey::Account",
353            )),
354        }
355    }
356}
357
358impl StorageKeyCodec for crate::types::Timestamp {
359    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
360        Ok(StorageKey::Timestamp(*self))
361    }
362}
363
364impl StorageKeyDecode for crate::types::Timestamp {
365    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
366        match key {
367            StorageKey::Timestamp(value) => Ok(value),
368            other => Err(storage_key_variant_decode_failed(
369                ::std::any::type_name::<Self>(),
370                other,
371                "StorageKey::Timestamp",
372            )),
373        }
374    }
375}
376
377impl StorageKeyCodec for crate::types::Ulid {
378    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
379        Ok(StorageKey::Ulid(*self))
380    }
381}
382
383impl StorageKeyDecode for crate::types::Ulid {
384    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
385        match key {
386            StorageKey::Ulid(value) => Ok(value),
387            other => Err(storage_key_variant_decode_failed(
388                ::std::any::type_name::<Self>(),
389                other,
390                "StorageKey::Ulid",
391            )),
392        }
393    }
394}
395
396impl StorageKeyCodec for () {
397    fn to_storage_key(&self) -> Result<StorageKey, StorageKeyEncodeError> {
398        Ok(StorageKey::Unit)
399    }
400}
401
402impl StorageKeyDecode for () {
403    fn from_storage_key(key: StorageKey) -> Result<Self, InternalError> {
404        match key {
405            StorageKey::Unit => Ok(()),
406            other => Err(storage_key_variant_decode_failed(
407                ::std::any::type_name::<Self>(),
408                other,
409                "StorageKey::Unit",
410            )),
411        }
412    }
413}
414
415///
416///
417/// RuntimeValueEncode
418///
419/// Narrow runtime lowering boundary for typed value surfaces that can be
420/// projected into the internal `Value` union.
421/// This is the encode-side owner used by generated wrappers and shared helper
422/// paths that only need one-way lowering.
423/// It is runtime-only and MUST NOT be used for persisted-row codecs,
424/// storage-key encoding, or any other persistence/storage encoding path.
425///
426pub trait RuntimeValueEncode {
427    fn to_value(&self) -> Value;
428}
429
430///
431/// RuntimeValueDecode
432///
433/// Narrow runtime reconstruction boundary for typed value surfaces that can be
434/// rebuilt from the internal `Value` union.
435/// This is the decode-side owner used by generated wrappers and shared helper
436/// paths that only need one-way typed reconstruction.
437/// It is runtime-only and MUST NOT be used for persisted-row codecs,
438/// storage-key decoding, or any other persistence/storage encoding path.
439///
440pub trait RuntimeValueDecode {
441    #[must_use]
442    fn from_value(value: &Value) -> Option<Self>
443    where
444        Self: Sized;
445}
446
447///
448/// runtime_value_to_value
449///
450/// Hidden runtime lowering helper for generated code and other encode-only
451/// call sites that should not spell the encode trait directly.
452/// This helper is runtime-only and MUST NOT be used from persistence or
453/// storage encoding code.
454///
455pub fn runtime_value_to_value<T>(value: &T) -> Value
456where
457    T: ?Sized + RuntimeValueEncode,
458{
459    value.to_value()
460}
461
462///
463/// runtime_value_from_value
464///
465/// Hidden runtime reconstruction helper for generated code and other decode
466/// call sites that should not spell the decode trait directly.
467/// This helper is runtime-only and MUST NOT be used from persistence or
468/// storage decoding code.
469///
470#[must_use]
471pub fn runtime_value_from_value<T>(value: &Value) -> Option<T>
472where
473    T: RuntimeValueDecode,
474{
475    T::from_value(value)
476}
477
478///
479/// PersistedByKindCodec
480///
481/// PersistedByKindCodec lets one field type own the stricter schema-selected
482/// `ByKind` persisted-row storage contract.
483/// This contract is persistence-only and MUST NOT depend on runtime `Value`
484/// conversion, generic fallback bridges, or the runtime value-surface traits.
485///
486
487pub trait PersistedByKindCodec: Sized {
488    /// Encode one field payload through the explicit `ByKind` storage lane.
489    fn encode_persisted_slot_payload_by_kind(
490        &self,
491        kind: FieldKind,
492        field_name: &'static str,
493    ) -> Result<Vec<u8>, InternalError>;
494
495    /// Decode one optional field payload through the explicit `ByKind`
496    /// storage lane, preserving the null sentinel for wrapper-owned optional
497    /// handling.
498    fn decode_persisted_option_slot_payload_by_kind(
499        bytes: &[u8],
500        kind: FieldKind,
501        field_name: &'static str,
502    ) -> Result<Option<Self>, InternalError>;
503}
504
505///
506/// PersistedStructuredFieldCodec
507///
508/// Direct persisted payload codec for structured field values.
509/// This trait owns only the typed field <-> persisted structured payload bytes
510/// boundary used by persisted-row storage helpers.
511/// It is persistence-only and MUST NOT mention runtime `Value`, rely on
512/// generic fallback bridges, or widen into a general structural storage
513/// authority.
514///
515
516pub trait PersistedStructuredFieldCodec {
517    /// Encode this typed structured field into persisted structured payload bytes.
518    fn encode_persisted_structured_payload(&self) -> Result<Vec<u8>, InternalError>;
519
520    /// Decode this typed structured field from persisted structured payload bytes.
521    fn decode_persisted_structured_payload(bytes: &[u8]) -> Result<Self, InternalError>
522    where
523        Self: Sized;
524}
525
526///
527/// EntitySchema
528///
529/// Declared runtime schema facts for an entity.
530///
531/// `NAME` seeds self-referential model construction for relation metadata.
532/// `MODEL` remains the authoritative runtime authority for field, primary-key,
533/// and index metadata consumed by planning and execution.
534///
535
536pub trait EntitySchema: EntityKey {
537    const NAME: &'static str;
538    const MODEL: &'static EntityModel;
539}
540
541// ============================================================================
542// ENTITY RUNTIME COMPOSITION
543// ============================================================================
544//
545// These traits bind schema-defined entities into runtime placement.
546//
547
548///
549/// EntityPlacement
550///
551/// Runtime placement of an entity
552///
553
554pub trait EntityPlacement {
555    type Store: StoreKind;
556    type Canister: CanisterKind;
557}
558
559///
560/// EntityKind
561///
562/// Fully runtime-bound entity.
563///
564/// This is the *maximum* entity contract and should only be
565/// required by code that actually touches storage or execution.
566///
567
568pub trait EntityKind: EntitySchema + EntityPlacement + Kind + TypeKind {
569    const ENTITY_TAG: EntityTag;
570}
571
572// ============================================================================
573// ENTITY VALUES
574// ============================================================================
575//
576// These traits describe *instances* of entities.
577//
578
579///
580/// EntityValue
581///
582/// A concrete entity value that can present a typed identity at boundaries.
583///
584/// Implementors store primitive key material internally.
585/// `id()` constructs a typed `Id<Self>` view on demand.
586/// The returned `Id<Self>` is a public identifier, not proof of authority.
587///
588
589pub trait EntityValue: EntityKey + FieldProjection + Sized {
590    fn id(&self) -> Id<Self>;
591}
592
593///
594/// EntityCreateMaterialization
595///
596/// Materialized authored create payload produced by one generated create input.
597/// Carries both the fully-typed entity after-image and the authored field-slot
598/// list so save preflight can still distinguish omission from authorship.
599///
600
601pub struct EntityCreateMaterialization<E> {
602    entity: E,
603    authored_slots: Vec<usize>,
604}
605
606impl<E> EntityCreateMaterialization<E> {
607    /// Build one materialized typed create payload.
608    #[must_use]
609    pub const fn new(entity: E, authored_slots: Vec<usize>) -> Self {
610        Self {
611            entity,
612            authored_slots,
613        }
614    }
615
616    /// Consume and return the typed entity after-image.
617    #[must_use]
618    pub fn into_entity(self) -> E {
619        self.entity
620    }
621
622    /// Borrow the authored field slots carried by this insert payload.
623    #[must_use]
624    pub const fn authored_slots(&self) -> &[usize] {
625        self.authored_slots.as_slice()
626    }
627}
628
629///
630/// EntityCreateInput
631///
632/// Create-authored typed input for one entity.
633/// This is intentionally distinct from the readable entity shape so generated
634/// and managed fields can stay structurally un-authorable on typed creates.
635///
636
637pub trait EntityCreateInput: Sized {
638    type Entity: EntityValue;
639
640    /// Materialize one typed create payload plus authored-slot provenance.
641    fn materialize_create(self)
642    -> Result<EntityCreateMaterialization<Self::Entity>, InternalError>;
643}
644
645///
646/// EntityCreateType
647///
648/// Entity-owned association from one entity type to its generated create
649/// input shape.
650/// This keeps the public create-input surface generic at the facade boundary
651/// while generated code remains free to pick any concrete backing type name.
652///
653
654pub trait EntityCreateType: EntityValue {
655    type Create: EntityCreateInput<Entity = Self>;
656}
657
658/// Marker for entities with exactly one logical row.
659pub trait SingletonEntity: EntityValue {}
660
661///
662// ============================================================================
663// TYPE SYSTEM CONTRACTS
664// ============================================================================
665//
666// These traits define behavioral expectations for schema-defined types.
667//
668
669///
670/// TypeKind
671///
672/// Any schema-defined data type.
673///
674/// This is a *strong* contract and should only be required
675/// where full lifecycle semantics are needed.
676///
677
678pub trait TypeKind:
679    Kind + Clone + DeserializeOwned + Sanitize + Validate + Visitable + PartialEq
680{
681}
682
683impl<T> TypeKind for T where
684    T: Kind + Clone + DeserializeOwned + PartialEq + Sanitize + Validate + Visitable
685{
686}
687
688///
689/// FieldTypeMeta
690///
691/// Static runtime field metadata for one schema-facing value type.
692/// This is the single authority for generated field kind and storage-decode
693/// metadata, so callers do not need per-type inherent constants.
694///
695
696pub trait FieldTypeMeta {
697    /// Semantic field kind used for runtime planning and validation.
698    const KIND: FieldKind;
699
700    /// Persisted decode contract used by row and payload decoding.
701    const STORAGE_DECODE: FieldStorageDecode;
702
703    /// Known nested fields for generated structured records.
704    const NESTED_FIELDS: &'static [FieldModel] = &[];
705}
706
707///
708/// PersistedFieldMetaCodec
709///
710/// PersistedFieldMetaCodec lets one field type own the persisted-row
711/// encode/decode contract selected by its `FieldTypeMeta`.
712/// This keeps the meta-hinted persisted-row path on the field-type owner
713/// instead of forcing row helpers to require both the by-kind and direct
714/// structured codec traits at once.
715///
716
717pub trait PersistedFieldMetaCodec: FieldTypeMeta + Sized {
718    /// Encode one non-optional field payload through the type's own
719    /// `FieldTypeMeta` storage contract.
720    fn encode_persisted_slot_payload_by_meta(
721        &self,
722        field_name: &'static str,
723    ) -> Result<Vec<u8>, InternalError>;
724
725    /// Decode one non-optional field payload through the type's own
726    /// `FieldTypeMeta` storage contract.
727    fn decode_persisted_slot_payload_by_meta(
728        bytes: &[u8],
729        field_name: &'static str,
730    ) -> Result<Self, InternalError>;
731
732    /// Encode one optional field payload through the inner type's own
733    /// `FieldTypeMeta` storage contract.
734    fn encode_persisted_option_slot_payload_by_meta(
735        value: &Option<Self>,
736        field_name: &'static str,
737    ) -> Result<Vec<u8>, InternalError>;
738
739    /// Decode one optional field payload through the inner type's own
740    /// `FieldTypeMeta` storage contract.
741    fn decode_persisted_option_slot_payload_by_meta(
742        bytes: &[u8],
743        field_name: &'static str,
744    ) -> Result<Option<Self>, InternalError>;
745}
746
747///
748/// PersistedFieldSlotCodec
749///
750/// PersistedFieldSlotCodec is the single persisted-row field boundary used by
751/// derive-generated row bridges.
752/// Implementations own every storage decision for their type, including
753/// primitive fast paths, optional null handling, and schema/type metadata.
754///
755
756pub trait PersistedFieldSlotCodec: Sized {
757    /// Encode one required field slot payload through this type's storage
758    /// contract.
759    fn encode_persisted_slot(&self, field_name: &'static str) -> Result<Vec<u8>, InternalError>;
760
761    /// Decode one required field slot payload through this type's storage
762    /// contract.
763    fn decode_persisted_slot(bytes: &[u8], field_name: &'static str)
764    -> Result<Self, InternalError>;
765
766    /// Encode one optional field slot payload through this type's storage
767    /// contract while preserving explicit null.
768    fn encode_persisted_option_slot(
769        value: &Option<Self>,
770        field_name: &'static str,
771    ) -> Result<Vec<u8>, InternalError>;
772
773    /// Decode one optional field slot payload through this type's storage
774    /// contract while preserving explicit null.
775    fn decode_persisted_option_slot(
776        bytes: &[u8],
777        field_name: &'static str,
778    ) -> Result<Option<Self>, InternalError>;
779}
780
781impl<T> FieldTypeMeta for Option<T>
782where
783    T: FieldTypeMeta,
784{
785    const KIND: FieldKind = T::KIND;
786    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
787    const NESTED_FIELDS: &'static [FieldModel] = T::NESTED_FIELDS;
788}
789
790impl<T> FieldTypeMeta for Box<T>
791where
792    T: FieldTypeMeta,
793{
794    const KIND: FieldKind = T::KIND;
795    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
796    const NESTED_FIELDS: &'static [FieldModel] = T::NESTED_FIELDS;
797}
798
799// Standard containers mirror the generated collection-wrapper contract: their
800// semantic kind remains structural, but persisted decode routes through the
801// shared structural `Value` storage seam instead of leaf-by-leaf scalar decode.
802impl<T> FieldTypeMeta for Vec<T>
803where
804    T: FieldTypeMeta,
805{
806    const KIND: FieldKind = FieldKind::List(&T::KIND);
807    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
808}
809
810impl<T> FieldTypeMeta for BTreeSet<T>
811where
812    T: FieldTypeMeta,
813{
814    const KIND: FieldKind = FieldKind::Set(&T::KIND);
815    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
816}
817
818impl<K, V> FieldTypeMeta for BTreeMap<K, V>
819where
820    K: FieldTypeMeta,
821    V: FieldTypeMeta,
822{
823    const KIND: FieldKind = FieldKind::Map {
824        key: &K::KIND,
825        value: &V::KIND,
826    };
827    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
828}
829
830/// ============================================================================
831/// QUERY VALUE BOUNDARIES
832/// ============================================================================
833
834///
835/// Collection
836///
837/// Explicit iteration contract for list/set wrapper types.
838/// Keeps generic collection code on one stable boundary even when concrete
839/// wrapper types opt into direct container ergonomics.
840///
841
842pub trait Collection {
843    type Item;
844
845    /// Iterator over the collection's items, tied to the borrow of `self`.
846    type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
847    where
848        Self: 'a;
849
850    /// Returns an iterator over the collection's items.
851    fn iter(&self) -> Self::Iter<'_>;
852
853    /// Returns the number of items in the collection.
854    fn len(&self) -> usize;
855
856    /// Returns true if the collection contains no items.
857    fn is_empty(&self) -> bool {
858        self.len() == 0
859    }
860}
861
862///
863/// MapCollection
864///
865/// Explicit iteration contract for map wrapper types.
866/// Keeps generic map code on one stable boundary even when concrete wrapper
867/// types opt into direct container ergonomics.
868///
869
870pub trait MapCollection {
871    type Key;
872    type Value;
873
874    /// Iterator over the map's key/value pairs, tied to the borrow of `self`.
875    type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
876    where
877        Self: 'a;
878
879    /// Returns an iterator over the map's key/value pairs.
880    fn iter(&self) -> Self::Iter<'_>;
881
882    /// Returns the number of entries in the map.
883    fn len(&self) -> usize;
884
885    /// Returns true if the map contains no entries.
886    fn is_empty(&self) -> bool {
887        self.len() == 0
888    }
889}
890
891impl<T> Collection for Vec<T> {
892    type Item = T;
893    type Iter<'a>
894        = std::slice::Iter<'a, T>
895    where
896        Self: 'a;
897
898    fn iter(&self) -> Self::Iter<'_> {
899        self.as_slice().iter()
900    }
901
902    fn len(&self) -> usize {
903        self.as_slice().len()
904    }
905}
906
907impl<T> Collection for BTreeSet<T> {
908    type Item = T;
909    type Iter<'a>
910        = std::collections::btree_set::Iter<'a, T>
911    where
912        Self: 'a;
913
914    fn iter(&self) -> Self::Iter<'_> {
915        self.iter()
916    }
917
918    fn len(&self) -> usize {
919        self.len()
920    }
921}
922
923impl<K, V> MapCollection for BTreeMap<K, V> {
924    type Key = K;
925    type Value = V;
926    type Iter<'a>
927        = std::collections::btree_map::Iter<'a, K, V>
928    where
929        Self: 'a;
930
931    fn iter(&self) -> Self::Iter<'_> {
932        self.iter()
933    }
934
935    fn len(&self) -> usize {
936        self.len()
937    }
938}
939
940pub trait EnumValue {
941    fn to_value_enum(&self) -> ValueEnum;
942}
943
944pub trait FieldProjection {
945    /// Resolve one field value by stable field slot index.
946    fn get_value_by_index(&self, index: usize) -> Option<Value>;
947}
948
949///
950/// RuntimeValueKind
951///
952/// Schema affordance classification for query planning and validation.
953/// Describes whether a field is planner-addressable and predicate-queryable.
954///
955
956#[derive(Clone, Copy, Debug, Eq, PartialEq)]
957pub enum RuntimeValueKind {
958    /// Planner-addressable atomic value.
959    Atomic,
960
961    /// Structured value with known internal fields that the planner
962    /// does not reason about as an addressable query target.
963    Structured {
964        /// Whether predicates may be expressed against this field.
965        queryable: bool,
966    },
967}
968
969impl RuntimeValueKind {
970    #[must_use]
971    pub const fn is_queryable(self) -> bool {
972        match self {
973            Self::Atomic => true,
974            Self::Structured { queryable } => queryable,
975        }
976    }
977}
978
979///
980/// RuntimeValueMeta
981///
982/// Schema/queryability metadata for one typed field value surface.
983/// This stays separate from encode/decode conversion so metadata-only callers do not need
984/// to depend on runtime `Value` conversion.
985///
986
987pub trait RuntimeValueMeta {
988    fn kind() -> RuntimeValueKind
989    where
990        Self: Sized;
991}
992
993///
994/// runtime_value_collection_to_value
995///
996/// Shared collection-to-`Value::List` lowering for generated wrapper types.
997/// This keeps list and set value-surface impls from re-emitting the same item
998/// iteration body for every generated schema type.
999///
1000
1001pub fn runtime_value_collection_to_value<C>(collection: &C) -> Value
1002where
1003    C: Collection,
1004    C::Item: RuntimeValueEncode,
1005{
1006    Value::List(
1007        collection
1008            .iter()
1009            .map(RuntimeValueEncode::to_value)
1010            .collect(),
1011    )
1012}
1013
1014///
1015/// runtime_value_vec_from_value
1016///
1017/// Shared `Value::List` decode for generated list wrapper types.
1018/// This preserves typed value-surface decoding while avoiding one repeated loop
1019/// body per generated list schema type.
1020///
1021
1022#[must_use]
1023pub fn runtime_value_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
1024where
1025    T: RuntimeValueDecode,
1026{
1027    let Value::List(values) = value else {
1028        return None;
1029    };
1030
1031    let mut out = Vec::with_capacity(values.len());
1032    for value in values {
1033        out.push(T::from_value(value)?);
1034    }
1035
1036    Some(out)
1037}
1038
1039///
1040/// runtime_value_btree_set_from_value
1041///
1042/// Shared `Value::List` decode for generated set wrapper types.
1043/// This preserves duplicate rejection while avoiding one repeated loop body
1044/// per generated set schema type.
1045///
1046
1047#[must_use]
1048pub fn runtime_value_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
1049where
1050    T: Ord + RuntimeValueDecode,
1051{
1052    let Value::List(values) = value else {
1053        return None;
1054    };
1055
1056    let mut out = BTreeSet::new();
1057    for value in values {
1058        let item = T::from_value(value)?;
1059        if !out.insert(item) {
1060            return None;
1061        }
1062    }
1063
1064    Some(out)
1065}
1066
1067///
1068/// runtime_value_map_collection_to_value
1069///
1070/// Shared map-to-`Value::Map` lowering for generated map wrapper types.
1071/// This keeps canonicalization and duplicate-key checks in one runtime helper
1072/// instead of re-emitting the same map conversion body per generated schema
1073/// type.
1074///
1075
1076pub fn runtime_value_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
1077where
1078    M: MapCollection,
1079    M::Key: RuntimeValueEncode,
1080    M::Value: RuntimeValueEncode,
1081{
1082    let mut entries: Vec<(Value, Value)> = map
1083        .iter()
1084        .map(|(key, value)| {
1085            (
1086                RuntimeValueEncode::to_value(key),
1087                RuntimeValueEncode::to_value(value),
1088            )
1089        })
1090        .collect();
1091
1092    if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
1093        debug_assert!(false, "invalid map field value for {path}: {err}");
1094        return Value::Map(entries);
1095    }
1096
1097    Value::sort_map_entries_in_place(entries.as_mut_slice());
1098
1099    for i in 1..entries.len() {
1100        let (left_key, _) = &entries[i - 1];
1101        let (right_key, _) = &entries[i];
1102        if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
1103            debug_assert!(
1104                false,
1105                "duplicate map key in {path} after value-surface canonicalization",
1106            );
1107            break;
1108        }
1109    }
1110
1111    Value::Map(entries)
1112}
1113
1114///
1115/// runtime_value_btree_map_from_value
1116///
1117/// Shared `Value::Map` decode for generated map wrapper types.
1118/// This keeps canonical-entry normalization in one runtime helper instead of
1119/// re-emitting the same decode body per generated schema type.
1120///
1121
1122#[must_use]
1123pub fn runtime_value_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
1124where
1125    K: Ord + RuntimeValueDecode,
1126    V: RuntimeValueDecode,
1127{
1128    let Value::Map(entries) = value else {
1129        return None;
1130    };
1131
1132    let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
1133    if normalized.as_slice() != entries.as_slice() {
1134        return None;
1135    }
1136
1137    let mut map = BTreeMap::new();
1138    for (entry_key, entry_value) in normalized {
1139        let key = K::from_value(&entry_key)?;
1140        let value = V::from_value(&entry_value)?;
1141        map.insert(key, value);
1142    }
1143
1144    Some(map)
1145}
1146
1147///
1148/// runtime_value_from_vec_into
1149///
1150/// Shared `Vec<I> -> Vec<T>` conversion for generated wrapper `From<Vec<I>>`
1151/// impls. This keeps list wrappers from re-emitting the same `into_iter` /
1152/// `map(Into::into)` collection body for every generated schema type.
1153///
1154
1155#[must_use]
1156pub fn runtime_value_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
1157where
1158    I: Into<T>,
1159{
1160    entries.into_iter().map(Into::into).collect()
1161}
1162
1163///
1164/// runtime_value_from_vec_into_btree_set
1165///
1166/// Shared `Vec<I> -> BTreeSet<T>` conversion for generated set wrapper
1167/// `From<Vec<I>>` impls. This keeps set wrappers from re-emitting the same
1168/// collection conversion body for every generated schema type.
1169///
1170
1171#[must_use]
1172pub fn runtime_value_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
1173where
1174    I: Into<T>,
1175    T: Ord,
1176{
1177    entries.into_iter().map(Into::into).collect()
1178}
1179
1180///
1181/// runtime_value_from_vec_into_btree_map
1182///
1183/// Shared `Vec<(IK, IV)> -> BTreeMap<K, V>` conversion for generated map
1184/// wrapper `From<Vec<(IK, IV)>>` impls. This keeps map wrappers from
1185/// re-emitting the same pair-conversion body for every generated schema type.
1186///
1187
1188#[must_use]
1189pub fn runtime_value_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
1190where
1191    IK: Into<K>,
1192    IV: Into<V>,
1193    K: Ord,
1194{
1195    entries
1196        .into_iter()
1197        .map(|(key, value)| (key.into(), value.into()))
1198        .collect()
1199}
1200
1201///
1202/// runtime_value_into
1203///
1204/// Shared `Into<T>` lowering for generated newtype `From<U>` impls.
1205/// This keeps newtype wrappers from re-emitting the same single-field
1206/// conversion body for every generated schema type.
1207///
1208
1209#[must_use]
1210pub fn runtime_value_into<T, U>(value: U) -> T
1211where
1212    U: Into<T>,
1213{
1214    value.into()
1215}
1216
1217impl RuntimeValueMeta for &str {
1218    fn kind() -> RuntimeValueKind {
1219        RuntimeValueKind::Atomic
1220    }
1221}
1222
1223impl RuntimeValueEncode for &str {
1224    fn to_value(&self) -> Value {
1225        Value::Text((*self).to_string())
1226    }
1227}
1228
1229impl RuntimeValueDecode for &str {
1230    fn from_value(_value: &Value) -> Option<Self> {
1231        None
1232    }
1233}
1234
1235impl RuntimeValueMeta for String {
1236    fn kind() -> RuntimeValueKind {
1237        RuntimeValueKind::Atomic
1238    }
1239}
1240
1241impl RuntimeValueEncode for String {
1242    fn to_value(&self) -> Value {
1243        Value::Text(self.clone())
1244    }
1245}
1246
1247impl RuntimeValueDecode for String {
1248    fn from_value(value: &Value) -> Option<Self> {
1249        match value {
1250            Value::Text(v) => Some(v.clone()),
1251            _ => None,
1252        }
1253    }
1254}
1255
1256impl<T: RuntimeValueMeta> RuntimeValueMeta for Option<T> {
1257    fn kind() -> RuntimeValueKind {
1258        T::kind()
1259    }
1260}
1261
1262impl<T: RuntimeValueEncode> RuntimeValueEncode for Option<T> {
1263    fn to_value(&self) -> Value {
1264        match self {
1265            Some(v) => v.to_value(),
1266            None => Value::Null,
1267        }
1268    }
1269}
1270
1271impl<T: RuntimeValueDecode> RuntimeValueDecode for Option<T> {
1272    fn from_value(value: &Value) -> Option<Self> {
1273        if matches!(value, Value::Null) {
1274            return Some(None);
1275        }
1276
1277        T::from_value(value).map(Some)
1278    }
1279}
1280
1281impl<T: RuntimeValueMeta> RuntimeValueMeta for Box<T> {
1282    fn kind() -> RuntimeValueKind {
1283        T::kind()
1284    }
1285}
1286
1287impl<T: RuntimeValueEncode> RuntimeValueEncode for Box<T> {
1288    fn to_value(&self) -> Value {
1289        (**self).to_value()
1290    }
1291}
1292
1293impl<T: RuntimeValueDecode> RuntimeValueDecode for Box<T> {
1294    fn from_value(value: &Value) -> Option<Self> {
1295        T::from_value(value).map(Self::new)
1296    }
1297}
1298
1299impl<T> RuntimeValueMeta for Vec<T> {
1300    fn kind() -> RuntimeValueKind {
1301        RuntimeValueKind::Structured { queryable: true }
1302    }
1303}
1304
1305impl<T: RuntimeValueEncode> RuntimeValueEncode for Vec<T> {
1306    fn to_value(&self) -> Value {
1307        runtime_value_collection_to_value(self)
1308    }
1309}
1310
1311impl<T: RuntimeValueDecode> RuntimeValueDecode for Vec<T> {
1312    fn from_value(value: &Value) -> Option<Self> {
1313        runtime_value_vec_from_value(value)
1314    }
1315}
1316
1317impl<T> RuntimeValueMeta for BTreeSet<T>
1318where
1319    T: Ord,
1320{
1321    fn kind() -> RuntimeValueKind {
1322        RuntimeValueKind::Structured { queryable: true }
1323    }
1324}
1325
1326impl<T> RuntimeValueEncode for BTreeSet<T>
1327where
1328    T: Ord + RuntimeValueEncode,
1329{
1330    fn to_value(&self) -> Value {
1331        runtime_value_collection_to_value(self)
1332    }
1333}
1334
1335impl<T> RuntimeValueDecode for BTreeSet<T>
1336where
1337    T: Ord + RuntimeValueDecode,
1338{
1339    fn from_value(value: &Value) -> Option<Self> {
1340        runtime_value_btree_set_from_value(value)
1341    }
1342}
1343
1344impl<K, V> RuntimeValueMeta for BTreeMap<K, V>
1345where
1346    K: Ord,
1347{
1348    fn kind() -> RuntimeValueKind {
1349        RuntimeValueKind::Structured { queryable: true }
1350    }
1351}
1352
1353impl<K, V> RuntimeValueEncode for BTreeMap<K, V>
1354where
1355    K: Ord + RuntimeValueEncode,
1356    V: RuntimeValueEncode,
1357{
1358    fn to_value(&self) -> Value {
1359        runtime_value_map_collection_to_value(self, std::any::type_name::<Self>())
1360    }
1361}
1362
1363impl<K, V> RuntimeValueDecode for BTreeMap<K, V>
1364where
1365    K: Ord + RuntimeValueDecode,
1366    V: RuntimeValueDecode,
1367{
1368    fn from_value(value: &Value) -> Option<Self> {
1369        runtime_value_btree_map_from_value(value)
1370    }
1371}
1372
1373// impl_runtime_value
1374#[macro_export]
1375macro_rules! impl_runtime_value {
1376    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
1377        $(
1378            impl RuntimeValueMeta for $type {
1379                fn kind() -> RuntimeValueKind {
1380                    RuntimeValueKind::Atomic
1381                }
1382            }
1383
1384            impl RuntimeValueEncode for $type {
1385                fn to_value(&self) -> Value {
1386                    Value::$variant((*self).into())
1387                }
1388            }
1389
1390            impl RuntimeValueDecode for $type {
1391                fn from_value(value: &Value) -> Option<Self> {
1392                    match value {
1393                        Value::$variant(v) => (*v).try_into().ok(),
1394                        _ => None,
1395                    }
1396                }
1397            }
1398        )*
1399    };
1400}
1401
1402impl_runtime_value!(
1403    i8 => Int,
1404    i16 => Int,
1405    i32 => Int,
1406    i64 => Int,
1407    u8 => Nat,
1408    u16 => Nat,
1409    u32 => Nat,
1410    u64 => Nat,
1411    bool => Bool,
1412);
1413
1414/// ============================================================================
1415/// MISC HELPERS
1416/// ============================================================================
1417
1418///
1419/// Inner
1420///
1421/// For newtypes to expose their innermost value.
1422///
1423
1424pub trait Inner<T> {
1425    fn inner(&self) -> &T;
1426    fn into_inner(self) -> T;
1427}
1428
1429///
1430/// Repr
1431///
1432/// Internal representation boundary for scalar wrapper types.
1433///
1434
1435pub trait Repr {
1436    type Inner;
1437
1438    fn repr(&self) -> Self::Inner;
1439    fn from_repr(inner: Self::Inner) -> Self;
1440}
1441
1442/// ============================================================================
1443/// SANITIZATION / VALIDATION
1444/// ============================================================================
1445
1446///
1447/// Sanitizer
1448///
1449/// Transforms a value into a sanitized version.
1450///
1451
1452pub trait Sanitizer<T> {
1453    fn sanitize(&self, value: &mut T) -> Result<(), String>;
1454
1455    fn sanitize_with_context(
1456        &self,
1457        value: &mut T,
1458        ctx: &mut dyn VisitorContext,
1459    ) -> Result<(), String> {
1460        let _ = ctx;
1461
1462        self.sanitize(value)
1463    }
1464}
1465
1466///
1467/// Validator
1468///
1469/// Allows a node to validate values.
1470///
1471
1472pub trait Validator<T: ?Sized> {
1473    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
1474}