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 + Default;
639
640    /// Materialize one typed create payload plus authored-slot provenance.
641    fn materialize_create(self) -> EntityCreateMaterialization<Self::Entity>;
642}
643
644///
645/// EntityCreateType
646///
647/// Entity-owned association from one entity type to its generated create
648/// input shape.
649/// This keeps the public create-input surface generic at the facade boundary
650/// while generated code remains free to pick any concrete backing type name.
651///
652
653pub trait EntityCreateType: EntityValue {
654    type Create: EntityCreateInput<Entity = Self>;
655}
656
657/// Marker for entities with exactly one logical row.
658pub trait SingletonEntity: EntityValue {}
659
660///
661// ============================================================================
662// TYPE SYSTEM CONTRACTS
663// ============================================================================
664//
665// These traits define behavioral expectations for schema-defined types.
666//
667
668///
669/// TypeKind
670///
671/// Any schema-defined data type.
672///
673/// This is a *strong* contract and should only be required
674/// where full lifecycle semantics are needed.
675///
676
677pub trait TypeKind:
678    Kind + Clone + Default + DeserializeOwned + Sanitize + Validate + Visitable + PartialEq
679{
680}
681
682impl<T> TypeKind for T where
683    T: Kind + Clone + Default + DeserializeOwned + PartialEq + Sanitize + Validate + Visitable
684{
685}
686
687///
688/// FieldTypeMeta
689///
690/// Static runtime field metadata for one schema-facing value type.
691/// This is the single authority for generated field kind and storage-decode
692/// metadata, so callers do not need per-type inherent constants.
693///
694
695pub trait FieldTypeMeta {
696    /// Semantic field kind used for runtime planning and validation.
697    const KIND: FieldKind;
698
699    /// Persisted decode contract used by row and payload decoding.
700    const STORAGE_DECODE: FieldStorageDecode;
701
702    /// Known nested fields for generated structured records.
703    const NESTED_FIELDS: &'static [FieldModel] = &[];
704}
705
706///
707/// PersistedFieldMetaCodec
708///
709/// PersistedFieldMetaCodec lets one field type own the persisted-row
710/// encode/decode contract selected by its `FieldTypeMeta`.
711/// This keeps the meta-hinted persisted-row path on the field-type owner
712/// instead of forcing row helpers to require both the by-kind and direct
713/// structured codec traits at once.
714///
715
716pub trait PersistedFieldMetaCodec: FieldTypeMeta + Sized {
717    /// Encode one non-optional field payload through the type's own
718    /// `FieldTypeMeta` storage contract.
719    fn encode_persisted_slot_payload_by_meta(
720        &self,
721        field_name: &'static str,
722    ) -> Result<Vec<u8>, InternalError>;
723
724    /// Decode one non-optional field payload through the type's own
725    /// `FieldTypeMeta` storage contract.
726    fn decode_persisted_slot_payload_by_meta(
727        bytes: &[u8],
728        field_name: &'static str,
729    ) -> Result<Self, InternalError>;
730
731    /// Encode one optional field payload through the inner type's own
732    /// `FieldTypeMeta` storage contract.
733    fn encode_persisted_option_slot_payload_by_meta(
734        value: &Option<Self>,
735        field_name: &'static str,
736    ) -> Result<Vec<u8>, InternalError>;
737
738    /// Decode one optional field payload through the inner type's own
739    /// `FieldTypeMeta` storage contract.
740    fn decode_persisted_option_slot_payload_by_meta(
741        bytes: &[u8],
742        field_name: &'static str,
743    ) -> Result<Option<Self>, InternalError>;
744}
745
746///
747/// PersistedFieldSlotCodec
748///
749/// PersistedFieldSlotCodec is the single persisted-row field boundary used by
750/// derive-generated row bridges.
751/// Implementations own every storage decision for their type, including
752/// primitive fast paths, optional null handling, and schema/type metadata.
753///
754
755pub trait PersistedFieldSlotCodec: Sized {
756    /// Encode one required field slot payload through this type's storage
757    /// contract.
758    fn encode_persisted_slot(&self, field_name: &'static str) -> Result<Vec<u8>, InternalError>;
759
760    /// Decode one required field slot payload through this type's storage
761    /// contract.
762    fn decode_persisted_slot(bytes: &[u8], field_name: &'static str)
763    -> Result<Self, InternalError>;
764
765    /// Encode one optional field slot payload through this type's storage
766    /// contract while preserving explicit null.
767    fn encode_persisted_option_slot(
768        value: &Option<Self>,
769        field_name: &'static str,
770    ) -> Result<Vec<u8>, InternalError>;
771
772    /// Decode one optional field slot payload through this type's storage
773    /// contract while preserving explicit null.
774    fn decode_persisted_option_slot(
775        bytes: &[u8],
776        field_name: &'static str,
777    ) -> Result<Option<Self>, InternalError>;
778}
779
780impl<T> FieldTypeMeta for Option<T>
781where
782    T: FieldTypeMeta,
783{
784    const KIND: FieldKind = T::KIND;
785    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
786    const NESTED_FIELDS: &'static [FieldModel] = T::NESTED_FIELDS;
787}
788
789impl<T> FieldTypeMeta for Box<T>
790where
791    T: FieldTypeMeta,
792{
793    const KIND: FieldKind = T::KIND;
794    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
795    const NESTED_FIELDS: &'static [FieldModel] = T::NESTED_FIELDS;
796}
797
798// Standard containers mirror the generated collection-wrapper contract: their
799// semantic kind remains structural, but persisted decode routes through the
800// shared structural `Value` storage seam instead of leaf-by-leaf scalar decode.
801impl<T> FieldTypeMeta for Vec<T>
802where
803    T: FieldTypeMeta,
804{
805    const KIND: FieldKind = FieldKind::List(&T::KIND);
806    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
807}
808
809impl<T> FieldTypeMeta for BTreeSet<T>
810where
811    T: FieldTypeMeta,
812{
813    const KIND: FieldKind = FieldKind::Set(&T::KIND);
814    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
815}
816
817impl<K, V> FieldTypeMeta for BTreeMap<K, V>
818where
819    K: FieldTypeMeta,
820    V: FieldTypeMeta,
821{
822    const KIND: FieldKind = FieldKind::Map {
823        key: &K::KIND,
824        value: &V::KIND,
825    };
826    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
827}
828
829/// ============================================================================
830/// QUERY VALUE BOUNDARIES
831/// ============================================================================
832
833///
834/// Collection
835///
836/// Explicit iteration contract for list/set wrapper types.
837/// Keeps generic collection code on one stable boundary even when concrete
838/// wrapper types opt into direct container ergonomics.
839///
840
841pub trait Collection {
842    type Item;
843
844    /// Iterator over the collection's items, tied to the borrow of `self`.
845    type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
846    where
847        Self: 'a;
848
849    /// Returns an iterator over the collection's items.
850    fn iter(&self) -> Self::Iter<'_>;
851
852    /// Returns the number of items in the collection.
853    fn len(&self) -> usize;
854
855    /// Returns true if the collection contains no items.
856    fn is_empty(&self) -> bool {
857        self.len() == 0
858    }
859}
860
861///
862/// MapCollection
863///
864/// Explicit iteration contract for map wrapper types.
865/// Keeps generic map code on one stable boundary even when concrete wrapper
866/// types opt into direct container ergonomics.
867///
868
869pub trait MapCollection {
870    type Key;
871    type Value;
872
873    /// Iterator over the map's key/value pairs, tied to the borrow of `self`.
874    type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
875    where
876        Self: 'a;
877
878    /// Returns an iterator over the map's key/value pairs.
879    fn iter(&self) -> Self::Iter<'_>;
880
881    /// Returns the number of entries in the map.
882    fn len(&self) -> usize;
883
884    /// Returns true if the map contains no entries.
885    fn is_empty(&self) -> bool {
886        self.len() == 0
887    }
888}
889
890impl<T> Collection for Vec<T> {
891    type Item = T;
892    type Iter<'a>
893        = std::slice::Iter<'a, T>
894    where
895        Self: 'a;
896
897    fn iter(&self) -> Self::Iter<'_> {
898        self.as_slice().iter()
899    }
900
901    fn len(&self) -> usize {
902        self.as_slice().len()
903    }
904}
905
906impl<T> Collection for BTreeSet<T> {
907    type Item = T;
908    type Iter<'a>
909        = std::collections::btree_set::Iter<'a, T>
910    where
911        Self: 'a;
912
913    fn iter(&self) -> Self::Iter<'_> {
914        self.iter()
915    }
916
917    fn len(&self) -> usize {
918        self.len()
919    }
920}
921
922impl<K, V> MapCollection for BTreeMap<K, V> {
923    type Key = K;
924    type Value = V;
925    type Iter<'a>
926        = std::collections::btree_map::Iter<'a, K, V>
927    where
928        Self: 'a;
929
930    fn iter(&self) -> Self::Iter<'_> {
931        self.iter()
932    }
933
934    fn len(&self) -> usize {
935        self.len()
936    }
937}
938
939pub trait EnumValue {
940    fn to_value_enum(&self) -> ValueEnum;
941}
942
943pub trait FieldProjection {
944    /// Resolve one field value by stable field slot index.
945    fn get_value_by_index(&self, index: usize) -> Option<Value>;
946}
947
948///
949/// RuntimeValueKind
950///
951/// Schema affordance classification for query planning and validation.
952/// Describes whether a field is planner-addressable and predicate-queryable.
953///
954
955#[derive(Clone, Copy, Debug, Eq, PartialEq)]
956pub enum RuntimeValueKind {
957    /// Planner-addressable atomic value.
958    Atomic,
959
960    /// Structured value with known internal fields that the planner
961    /// does not reason about as an addressable query target.
962    Structured {
963        /// Whether predicates may be expressed against this field.
964        queryable: bool,
965    },
966}
967
968impl RuntimeValueKind {
969    #[must_use]
970    pub const fn is_queryable(self) -> bool {
971        match self {
972            Self::Atomic => true,
973            Self::Structured { queryable } => queryable,
974        }
975    }
976}
977
978///
979/// RuntimeValueMeta
980///
981/// Schema/queryability metadata for one typed field value surface.
982/// This stays separate from encode/decode conversion so metadata-only callers do not need
983/// to depend on runtime `Value` conversion.
984///
985
986pub trait RuntimeValueMeta {
987    fn kind() -> RuntimeValueKind
988    where
989        Self: Sized;
990}
991
992///
993/// runtime_value_collection_to_value
994///
995/// Shared collection-to-`Value::List` lowering for generated wrapper types.
996/// This keeps list and set value-surface impls from re-emitting the same item
997/// iteration body for every generated schema type.
998///
999
1000pub fn runtime_value_collection_to_value<C>(collection: &C) -> Value
1001where
1002    C: Collection,
1003    C::Item: RuntimeValueEncode,
1004{
1005    Value::List(
1006        collection
1007            .iter()
1008            .map(RuntimeValueEncode::to_value)
1009            .collect(),
1010    )
1011}
1012
1013///
1014/// runtime_value_vec_from_value
1015///
1016/// Shared `Value::List` decode for generated list wrapper types.
1017/// This preserves typed value-surface decoding while avoiding one repeated loop
1018/// body per generated list schema type.
1019///
1020
1021#[must_use]
1022pub fn runtime_value_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
1023where
1024    T: RuntimeValueDecode,
1025{
1026    let Value::List(values) = value else {
1027        return None;
1028    };
1029
1030    let mut out = Vec::with_capacity(values.len());
1031    for value in values {
1032        out.push(T::from_value(value)?);
1033    }
1034
1035    Some(out)
1036}
1037
1038///
1039/// runtime_value_btree_set_from_value
1040///
1041/// Shared `Value::List` decode for generated set wrapper types.
1042/// This preserves duplicate rejection while avoiding one repeated loop body
1043/// per generated set schema type.
1044///
1045
1046#[must_use]
1047pub fn runtime_value_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
1048where
1049    T: Ord + RuntimeValueDecode,
1050{
1051    let Value::List(values) = value else {
1052        return None;
1053    };
1054
1055    let mut out = BTreeSet::new();
1056    for value in values {
1057        let item = T::from_value(value)?;
1058        if !out.insert(item) {
1059            return None;
1060        }
1061    }
1062
1063    Some(out)
1064}
1065
1066///
1067/// runtime_value_map_collection_to_value
1068///
1069/// Shared map-to-`Value::Map` lowering for generated map wrapper types.
1070/// This keeps canonicalization and duplicate-key checks in one runtime helper
1071/// instead of re-emitting the same map conversion body per generated schema
1072/// type.
1073///
1074
1075pub fn runtime_value_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
1076where
1077    M: MapCollection,
1078    M::Key: RuntimeValueEncode,
1079    M::Value: RuntimeValueEncode,
1080{
1081    let mut entries: Vec<(Value, Value)> = map
1082        .iter()
1083        .map(|(key, value)| {
1084            (
1085                RuntimeValueEncode::to_value(key),
1086                RuntimeValueEncode::to_value(value),
1087            )
1088        })
1089        .collect();
1090
1091    if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
1092        debug_assert!(false, "invalid map field value for {path}: {err}");
1093        return Value::Map(entries);
1094    }
1095
1096    Value::sort_map_entries_in_place(entries.as_mut_slice());
1097
1098    for i in 1..entries.len() {
1099        let (left_key, _) = &entries[i - 1];
1100        let (right_key, _) = &entries[i];
1101        if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
1102            debug_assert!(
1103                false,
1104                "duplicate map key in {path} after value-surface canonicalization",
1105            );
1106            break;
1107        }
1108    }
1109
1110    Value::Map(entries)
1111}
1112
1113///
1114/// runtime_value_btree_map_from_value
1115///
1116/// Shared `Value::Map` decode for generated map wrapper types.
1117/// This keeps canonical-entry normalization in one runtime helper instead of
1118/// re-emitting the same decode body per generated schema type.
1119///
1120
1121#[must_use]
1122pub fn runtime_value_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
1123where
1124    K: Ord + RuntimeValueDecode,
1125    V: RuntimeValueDecode,
1126{
1127    let Value::Map(entries) = value else {
1128        return None;
1129    };
1130
1131    let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
1132    if normalized.as_slice() != entries.as_slice() {
1133        return None;
1134    }
1135
1136    let mut map = BTreeMap::new();
1137    for (entry_key, entry_value) in normalized {
1138        let key = K::from_value(&entry_key)?;
1139        let value = V::from_value(&entry_value)?;
1140        map.insert(key, value);
1141    }
1142
1143    Some(map)
1144}
1145
1146///
1147/// runtime_value_from_vec_into
1148///
1149/// Shared `Vec<I> -> Vec<T>` conversion for generated wrapper `From<Vec<I>>`
1150/// impls. This keeps list wrappers from re-emitting the same `into_iter` /
1151/// `map(Into::into)` collection body for every generated schema type.
1152///
1153
1154#[must_use]
1155pub fn runtime_value_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
1156where
1157    I: Into<T>,
1158{
1159    entries.into_iter().map(Into::into).collect()
1160}
1161
1162///
1163/// runtime_value_from_vec_into_btree_set
1164///
1165/// Shared `Vec<I> -> BTreeSet<T>` conversion for generated set wrapper
1166/// `From<Vec<I>>` impls. This keeps set wrappers from re-emitting the same
1167/// collection conversion body for every generated schema type.
1168///
1169
1170#[must_use]
1171pub fn runtime_value_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
1172where
1173    I: Into<T>,
1174    T: Ord,
1175{
1176    entries.into_iter().map(Into::into).collect()
1177}
1178
1179///
1180/// runtime_value_from_vec_into_btree_map
1181///
1182/// Shared `Vec<(IK, IV)> -> BTreeMap<K, V>` conversion for generated map
1183/// wrapper `From<Vec<(IK, IV)>>` impls. This keeps map wrappers from
1184/// re-emitting the same pair-conversion body for every generated schema type.
1185///
1186
1187#[must_use]
1188pub fn runtime_value_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
1189where
1190    IK: Into<K>,
1191    IV: Into<V>,
1192    K: Ord,
1193{
1194    entries
1195        .into_iter()
1196        .map(|(key, value)| (key.into(), value.into()))
1197        .collect()
1198}
1199
1200///
1201/// runtime_value_into
1202///
1203/// Shared `Into<T>` lowering for generated newtype `From<U>` impls.
1204/// This keeps newtype wrappers from re-emitting the same single-field
1205/// conversion body for every generated schema type.
1206///
1207
1208#[must_use]
1209pub fn runtime_value_into<T, U>(value: U) -> T
1210where
1211    U: Into<T>,
1212{
1213    value.into()
1214}
1215
1216impl RuntimeValueMeta for &str {
1217    fn kind() -> RuntimeValueKind {
1218        RuntimeValueKind::Atomic
1219    }
1220}
1221
1222impl RuntimeValueEncode for &str {
1223    fn to_value(&self) -> Value {
1224        Value::Text((*self).to_string())
1225    }
1226}
1227
1228impl RuntimeValueDecode for &str {
1229    fn from_value(_value: &Value) -> Option<Self> {
1230        None
1231    }
1232}
1233
1234impl RuntimeValueMeta for String {
1235    fn kind() -> RuntimeValueKind {
1236        RuntimeValueKind::Atomic
1237    }
1238}
1239
1240impl RuntimeValueEncode for String {
1241    fn to_value(&self) -> Value {
1242        Value::Text(self.clone())
1243    }
1244}
1245
1246impl RuntimeValueDecode for String {
1247    fn from_value(value: &Value) -> Option<Self> {
1248        match value {
1249            Value::Text(v) => Some(v.clone()),
1250            _ => None,
1251        }
1252    }
1253}
1254
1255impl<T: RuntimeValueMeta> RuntimeValueMeta for Option<T> {
1256    fn kind() -> RuntimeValueKind {
1257        T::kind()
1258    }
1259}
1260
1261impl<T: RuntimeValueEncode> RuntimeValueEncode for Option<T> {
1262    fn to_value(&self) -> Value {
1263        match self {
1264            Some(v) => v.to_value(),
1265            None => Value::Null,
1266        }
1267    }
1268}
1269
1270impl<T: RuntimeValueDecode> RuntimeValueDecode for Option<T> {
1271    fn from_value(value: &Value) -> Option<Self> {
1272        if matches!(value, Value::Null) {
1273            return Some(None);
1274        }
1275
1276        T::from_value(value).map(Some)
1277    }
1278}
1279
1280impl<T: RuntimeValueMeta> RuntimeValueMeta for Box<T> {
1281    fn kind() -> RuntimeValueKind {
1282        T::kind()
1283    }
1284}
1285
1286impl<T: RuntimeValueEncode> RuntimeValueEncode for Box<T> {
1287    fn to_value(&self) -> Value {
1288        (**self).to_value()
1289    }
1290}
1291
1292impl<T: RuntimeValueDecode> RuntimeValueDecode for Box<T> {
1293    fn from_value(value: &Value) -> Option<Self> {
1294        T::from_value(value).map(Self::new)
1295    }
1296}
1297
1298impl<T> RuntimeValueMeta for Vec<T> {
1299    fn kind() -> RuntimeValueKind {
1300        RuntimeValueKind::Structured { queryable: true }
1301    }
1302}
1303
1304impl<T: RuntimeValueEncode> RuntimeValueEncode for Vec<T> {
1305    fn to_value(&self) -> Value {
1306        runtime_value_collection_to_value(self)
1307    }
1308}
1309
1310impl<T: RuntimeValueDecode> RuntimeValueDecode for Vec<T> {
1311    fn from_value(value: &Value) -> Option<Self> {
1312        runtime_value_vec_from_value(value)
1313    }
1314}
1315
1316impl<T> RuntimeValueMeta for BTreeSet<T>
1317where
1318    T: Ord,
1319{
1320    fn kind() -> RuntimeValueKind {
1321        RuntimeValueKind::Structured { queryable: true }
1322    }
1323}
1324
1325impl<T> RuntimeValueEncode for BTreeSet<T>
1326where
1327    T: Ord + RuntimeValueEncode,
1328{
1329    fn to_value(&self) -> Value {
1330        runtime_value_collection_to_value(self)
1331    }
1332}
1333
1334impl<T> RuntimeValueDecode for BTreeSet<T>
1335where
1336    T: Ord + RuntimeValueDecode,
1337{
1338    fn from_value(value: &Value) -> Option<Self> {
1339        runtime_value_btree_set_from_value(value)
1340    }
1341}
1342
1343impl<K, V> RuntimeValueMeta for BTreeMap<K, V>
1344where
1345    K: Ord,
1346{
1347    fn kind() -> RuntimeValueKind {
1348        RuntimeValueKind::Structured { queryable: true }
1349    }
1350}
1351
1352impl<K, V> RuntimeValueEncode for BTreeMap<K, V>
1353where
1354    K: Ord + RuntimeValueEncode,
1355    V: RuntimeValueEncode,
1356{
1357    fn to_value(&self) -> Value {
1358        runtime_value_map_collection_to_value(self, std::any::type_name::<Self>())
1359    }
1360}
1361
1362impl<K, V> RuntimeValueDecode for BTreeMap<K, V>
1363where
1364    K: Ord + RuntimeValueDecode,
1365    V: RuntimeValueDecode,
1366{
1367    fn from_value(value: &Value) -> Option<Self> {
1368        runtime_value_btree_map_from_value(value)
1369    }
1370}
1371
1372// impl_runtime_value
1373#[macro_export]
1374macro_rules! impl_runtime_value {
1375    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
1376        $(
1377            impl RuntimeValueMeta for $type {
1378                fn kind() -> RuntimeValueKind {
1379                    RuntimeValueKind::Atomic
1380                }
1381            }
1382
1383            impl RuntimeValueEncode for $type {
1384                fn to_value(&self) -> Value {
1385                    Value::$variant((*self).into())
1386                }
1387            }
1388
1389            impl RuntimeValueDecode for $type {
1390                fn from_value(value: &Value) -> Option<Self> {
1391                    match value {
1392                        Value::$variant(v) => (*v).try_into().ok(),
1393                        _ => None,
1394                    }
1395                }
1396            }
1397        )*
1398    };
1399}
1400
1401impl_runtime_value!(
1402    i8 => Int,
1403    i16 => Int,
1404    i32 => Int,
1405    i64 => Int,
1406    u8 => Nat,
1407    u16 => Nat,
1408    u32 => Nat,
1409    u64 => Nat,
1410    bool => Bool,
1411);
1412
1413/// ============================================================================
1414/// MISC HELPERS
1415/// ============================================================================
1416
1417///
1418/// Inner
1419///
1420/// For newtypes to expose their innermost value.
1421///
1422
1423pub trait Inner<T> {
1424    fn inner(&self) -> &T;
1425    fn into_inner(self) -> T;
1426}
1427
1428///
1429/// Repr
1430///
1431/// Internal representation boundary for scalar wrapper types.
1432///
1433
1434pub trait Repr {
1435    type Inner;
1436
1437    fn repr(&self) -> Self::Inner;
1438    fn from_repr(inner: Self::Inner) -> Self;
1439}
1440
1441/// ============================================================================
1442/// SANITIZATION / VALIDATION
1443/// ============================================================================
1444
1445///
1446/// Sanitizer
1447///
1448/// Transforms a value into a sanitized version.
1449///
1450
1451pub trait Sanitizer<T> {
1452    fn sanitize(&self, value: &mut T) -> Result<(), String>;
1453
1454    fn sanitize_with_context(
1455        &self,
1456        value: &mut T,
1457        ctx: &mut dyn VisitorContext,
1458    ) -> Result<(), String> {
1459        let _ = ctx;
1460
1461        self.sanitize(value)
1462    }
1463}
1464
1465///
1466/// Validator
1467///
1468/// Allows a node to validate values.
1469///
1470
1471pub trait Validator<T: ?Sized> {
1472    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
1473}