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