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