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