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