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