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
896impl<T> FieldTypeMeta for Option<T>
897where
898    T: FieldTypeMeta,
899{
900    const KIND: FieldKind = T::KIND;
901    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
902    const NESTED_FIELDS: &'static [FieldModel] = T::NESTED_FIELDS;
903}
904
905impl<T> FieldTypeMeta for Box<T>
906where
907    T: FieldTypeMeta,
908{
909    const KIND: FieldKind = T::KIND;
910    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
911    const NESTED_FIELDS: &'static [FieldModel] = T::NESTED_FIELDS;
912}
913
914// Standard containers mirror the generated collection-wrapper contract: their
915// semantic kind remains structural, but persisted decode routes through the
916// shared structural `Value` storage seam instead of leaf-by-leaf scalar decode.
917impl<T> FieldTypeMeta for Vec<T>
918where
919    T: FieldTypeMeta,
920{
921    const KIND: FieldKind = FieldKind::List(&T::KIND);
922    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
923}
924
925impl<T> FieldTypeMeta for BTreeSet<T>
926where
927    T: FieldTypeMeta,
928{
929    const KIND: FieldKind = FieldKind::Set(&T::KIND);
930    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
931}
932
933impl<K, V> FieldTypeMeta for BTreeMap<K, V>
934where
935    K: FieldTypeMeta,
936    V: FieldTypeMeta,
937{
938    const KIND: FieldKind = FieldKind::Map {
939        key: &K::KIND,
940        value: &V::KIND,
941    };
942    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
943}
944
945/// ============================================================================
946/// QUERY VALUE BOUNDARIES
947/// ============================================================================
948
949///
950/// Collection
951///
952/// Explicit iteration contract for list/set wrapper types.
953/// Keeps generic collection code on one stable boundary even when concrete
954/// wrapper types opt into direct container ergonomics.
955///
956
957pub trait Collection {
958    type Item;
959
960    /// Iterator over the collection's items, tied to the borrow of `self`.
961    type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
962    where
963        Self: 'a;
964
965    /// Returns an iterator over the collection's items.
966    fn iter(&self) -> Self::Iter<'_>;
967
968    /// Returns the number of items in the collection.
969    fn len(&self) -> usize;
970
971    /// Returns true if the collection contains no items.
972    fn is_empty(&self) -> bool {
973        self.len() == 0
974    }
975}
976
977///
978/// MapCollection
979///
980/// Explicit iteration contract for map wrapper types.
981/// Keeps generic map code on one stable boundary even when concrete wrapper
982/// types opt into direct container ergonomics.
983///
984
985pub trait MapCollection {
986    type Key;
987    type Value;
988
989    /// Iterator over the map's key/value pairs, tied to the borrow of `self`.
990    type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
991    where
992        Self: 'a;
993
994    /// Returns an iterator over the map's key/value pairs.
995    fn iter(&self) -> Self::Iter<'_>;
996
997    /// Returns the number of entries in the map.
998    fn len(&self) -> usize;
999
1000    /// Returns true if the map contains no entries.
1001    fn is_empty(&self) -> bool {
1002        self.len() == 0
1003    }
1004}
1005
1006impl<T> Collection for Vec<T> {
1007    type Item = T;
1008    type Iter<'a>
1009        = std::slice::Iter<'a, T>
1010    where
1011        Self: 'a;
1012
1013    fn iter(&self) -> Self::Iter<'_> {
1014        self.as_slice().iter()
1015    }
1016
1017    fn len(&self) -> usize {
1018        self.as_slice().len()
1019    }
1020}
1021
1022impl<T> Collection for BTreeSet<T> {
1023    type Item = T;
1024    type Iter<'a>
1025        = std::collections::btree_set::Iter<'a, T>
1026    where
1027        Self: 'a;
1028
1029    fn iter(&self) -> Self::Iter<'_> {
1030        self.iter()
1031    }
1032
1033    fn len(&self) -> usize {
1034        self.len()
1035    }
1036}
1037
1038impl<K, V> MapCollection for BTreeMap<K, V> {
1039    type Key = K;
1040    type Value = V;
1041    type Iter<'a>
1042        = std::collections::btree_map::Iter<'a, K, V>
1043    where
1044        Self: 'a;
1045
1046    fn iter(&self) -> Self::Iter<'_> {
1047        self.iter()
1048    }
1049
1050    fn len(&self) -> usize {
1051        self.len()
1052    }
1053}
1054
1055/// Name-based field input projection used before accepted-catalog admission.
1056pub trait AuthoredFieldProjection {
1057    /// Resolve one authored field value by stable field slot index.
1058    fn get_input_value_by_index(&self, index: usize) -> Option<InputValue>;
1059}
1060
1061pub trait FieldProjection {
1062    /// Resolve one field value by stable field slot index.
1063    fn get_value_by_index(&self, index: usize) -> Option<Value>;
1064}
1065
1066///
1067/// RuntimeValueKind
1068///
1069/// Schema affordance classification for query planning and validation.
1070/// Describes whether a field is planner-addressable and predicate-queryable.
1071///
1072
1073#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1074pub enum RuntimeValueKind {
1075    /// Planner-addressable atomic value.
1076    Atomic,
1077
1078    /// Structured value with known internal fields that the planner
1079    /// does not reason about as an addressable query target.
1080    Structured {
1081        /// Whether predicates may be expressed against this field.
1082        queryable: bool,
1083    },
1084}
1085
1086impl RuntimeValueKind {
1087    #[must_use]
1088    pub const fn is_queryable(self) -> bool {
1089        match self {
1090            Self::Atomic => true,
1091            Self::Structured { queryable } => queryable,
1092        }
1093    }
1094}
1095
1096///
1097/// RuntimeValueMeta
1098///
1099/// Schema/queryability metadata for one typed field value surface.
1100/// This stays separate from encode/decode conversion so metadata-only callers do not need
1101/// to depend on runtime `Value` conversion.
1102///
1103
1104pub trait RuntimeValueMeta {
1105    fn kind() -> RuntimeValueKind
1106    where
1107        Self: Sized;
1108}
1109
1110///
1111/// runtime_value_collection_to_value
1112///
1113/// Shared collection-to-`Value::List` lowering for generated wrapper types.
1114/// This keeps list and set value-surface impls from re-emitting the same item
1115/// iteration body for every generated schema type.
1116///
1117
1118pub fn runtime_value_collection_to_value<C>(collection: &C) -> Value
1119where
1120    C: Collection,
1121    C::Item: RuntimeValueEncode,
1122{
1123    Value::List(
1124        collection
1125            .iter()
1126            .map(RuntimeValueEncode::to_value)
1127            .collect(),
1128    )
1129}
1130
1131///
1132/// runtime_value_vec_from_value
1133///
1134/// Shared `Value::List` decode for generated list wrapper types.
1135/// This preserves typed value-surface decoding while avoiding one repeated loop
1136/// body per generated list schema type.
1137///
1138
1139#[must_use]
1140pub fn runtime_value_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
1141where
1142    T: RuntimeValueDecode,
1143{
1144    let Value::List(values) = value else {
1145        return None;
1146    };
1147
1148    let mut out = Vec::with_capacity(values.len());
1149    for value in values {
1150        out.push(T::from_value(value)?);
1151    }
1152
1153    Some(out)
1154}
1155
1156///
1157/// runtime_value_btree_set_from_value
1158///
1159/// Shared `Value::List` decode for generated set wrapper types.
1160/// This preserves duplicate rejection while avoiding one repeated loop body
1161/// per generated set schema type.
1162///
1163
1164#[must_use]
1165pub fn runtime_value_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
1166where
1167    T: Ord + RuntimeValueDecode,
1168{
1169    let Value::List(values) = value else {
1170        return None;
1171    };
1172
1173    let mut out = BTreeSet::new();
1174    for value in values {
1175        let item = T::from_value(value)?;
1176        if !out.insert(item) {
1177            return None;
1178        }
1179    }
1180
1181    Some(out)
1182}
1183
1184///
1185/// runtime_value_map_collection_to_value
1186///
1187/// Shared map-to-`Value::Map` lowering for generated map wrapper types.
1188/// This keeps canonicalization and duplicate-key checks in one runtime helper
1189/// instead of re-emitting the same map conversion body per generated schema
1190/// type.
1191///
1192
1193pub fn runtime_value_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
1194where
1195    M: MapCollection,
1196    M::Key: RuntimeValueEncode,
1197    M::Value: RuntimeValueEncode,
1198{
1199    let mut entries: Vec<(Value, Value)> = map
1200        .iter()
1201        .map(|(key, value)| {
1202            (
1203                RuntimeValueEncode::to_value(key),
1204                RuntimeValueEncode::to_value(value),
1205            )
1206        })
1207        .collect();
1208
1209    if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
1210        debug_assert!(false, "invalid map field value for {path}: {err}");
1211        return Value::Map(entries);
1212    }
1213
1214    Value::sort_map_entries_in_place(entries.as_mut_slice());
1215
1216    for i in 1..entries.len() {
1217        let (left_key, _) = &entries[i - 1];
1218        let (right_key, _) = &entries[i];
1219        if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
1220            debug_assert!(
1221                false,
1222                "duplicate map key in {path} after value-surface canonicalization",
1223            );
1224            break;
1225        }
1226    }
1227
1228    Value::Map(entries)
1229}
1230
1231///
1232/// runtime_value_btree_map_from_value
1233///
1234/// Shared `Value::Map` decode for generated map wrapper types.
1235/// This keeps canonical-entry normalization in one runtime helper instead of
1236/// re-emitting the same decode body per generated schema type.
1237///
1238
1239#[must_use]
1240pub fn runtime_value_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
1241where
1242    K: Ord + RuntimeValueDecode,
1243    V: RuntimeValueDecode,
1244{
1245    let Value::Map(entries) = value else {
1246        return None;
1247    };
1248
1249    let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
1250    if normalized.as_slice() != entries.as_slice() {
1251        return None;
1252    }
1253
1254    let mut map = BTreeMap::new();
1255    for (entry_key, entry_value) in normalized {
1256        let key = K::from_value(&entry_key)?;
1257        let value = V::from_value(&entry_value)?;
1258        map.insert(key, value);
1259    }
1260
1261    Some(map)
1262}
1263
1264///
1265/// runtime_value_from_vec_into
1266///
1267/// Shared `Vec<I> -> Vec<T>` conversion for generated wrapper `From<Vec<I>>`
1268/// impls. This keeps list wrappers from re-emitting the same `into_iter` /
1269/// `map(Into::into)` collection body for every generated schema type.
1270///
1271
1272#[must_use]
1273pub fn runtime_value_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
1274where
1275    I: Into<T>,
1276{
1277    entries.into_iter().map(Into::into).collect()
1278}
1279
1280///
1281/// runtime_value_from_vec_into_btree_set
1282///
1283/// Shared `Vec<I> -> BTreeSet<T>` conversion for generated set wrapper
1284/// `From<Vec<I>>` impls. This keeps set wrappers from re-emitting the same
1285/// collection conversion body for every generated schema type.
1286///
1287
1288#[must_use]
1289pub fn runtime_value_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
1290where
1291    I: Into<T>,
1292    T: Ord,
1293{
1294    entries.into_iter().map(Into::into).collect()
1295}
1296
1297///
1298/// runtime_value_from_vec_into_btree_map
1299///
1300/// Shared `Vec<(IK, IV)> -> BTreeMap<K, V>` conversion for generated map
1301/// wrapper `From<Vec<(IK, IV)>>` impls. This keeps map wrappers from
1302/// re-emitting the same pair-conversion body for every generated schema type.
1303///
1304
1305#[must_use]
1306pub fn runtime_value_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
1307where
1308    IK: Into<K>,
1309    IV: Into<V>,
1310    K: Ord,
1311{
1312    entries
1313        .into_iter()
1314        .map(|(key, value)| (key.into(), value.into()))
1315        .collect()
1316}
1317
1318///
1319/// runtime_value_into
1320///
1321/// Shared `Into<T>` lowering for generated newtype `From<U>` impls.
1322/// This keeps newtype wrappers from re-emitting the same single-field
1323/// conversion body for every generated schema type.
1324///
1325
1326#[must_use]
1327pub fn runtime_value_into<T, U>(value: U) -> T
1328where
1329    U: Into<T>,
1330{
1331    value.into()
1332}
1333
1334impl RuntimeValueMeta for &str {
1335    fn kind() -> RuntimeValueKind {
1336        RuntimeValueKind::Atomic
1337    }
1338}
1339
1340impl RuntimeValueEncode for &str {
1341    fn to_value(&self) -> Value {
1342        Value::Text((*self).to_string())
1343    }
1344}
1345
1346impl RuntimeValueDecode for &str {
1347    fn from_value(_value: &Value) -> Option<Self> {
1348        None
1349    }
1350}
1351
1352impl RuntimeValueMeta for String {
1353    fn kind() -> RuntimeValueKind {
1354        RuntimeValueKind::Atomic
1355    }
1356}
1357
1358impl RuntimeValueEncode for String {
1359    fn to_value(&self) -> Value {
1360        Value::Text(self.clone())
1361    }
1362}
1363
1364impl RuntimeValueDecode for String {
1365    fn from_value(value: &Value) -> Option<Self> {
1366        match value {
1367            Value::Text(v) => Some(v.clone()),
1368            _ => None,
1369        }
1370    }
1371}
1372
1373impl<T: RuntimeValueMeta> RuntimeValueMeta for Option<T> {
1374    fn kind() -> RuntimeValueKind {
1375        T::kind()
1376    }
1377}
1378
1379impl<T: RuntimeValueEncode> RuntimeValueEncode for Option<T> {
1380    fn to_value(&self) -> Value {
1381        match self {
1382            Some(v) => v.to_value(),
1383            None => Value::Null,
1384        }
1385    }
1386}
1387
1388impl<T: RuntimeValueDecode> RuntimeValueDecode for Option<T> {
1389    fn from_value(value: &Value) -> Option<Self> {
1390        if matches!(value, Value::Null) {
1391            return Some(None);
1392        }
1393
1394        T::from_value(value).map(Some)
1395    }
1396
1397    fn from_value_with_enum_context(
1398        value: &Value,
1399        context: &dyn RuntimeEnumContext,
1400    ) -> Option<Self> {
1401        if matches!(value, Value::Null) {
1402            return Some(None);
1403        }
1404
1405        T::from_value_with_enum_context(value, context).map(Some)
1406    }
1407}
1408
1409impl<T: RuntimeValueMeta> RuntimeValueMeta for Box<T> {
1410    fn kind() -> RuntimeValueKind {
1411        T::kind()
1412    }
1413}
1414
1415impl<T: RuntimeValueEncode> RuntimeValueEncode for Box<T> {
1416    fn to_value(&self) -> Value {
1417        (**self).to_value()
1418    }
1419}
1420
1421impl<T: RuntimeValueDecode> RuntimeValueDecode for Box<T> {
1422    fn from_value(value: &Value) -> Option<Self> {
1423        T::from_value(value).map(Self::new)
1424    }
1425
1426    fn from_value_with_enum_context(
1427        value: &Value,
1428        context: &dyn RuntimeEnumContext,
1429    ) -> Option<Self> {
1430        T::from_value_with_enum_context(value, context).map(Self::new)
1431    }
1432}
1433
1434impl<T> RuntimeValueMeta for Vec<T> {
1435    fn kind() -> RuntimeValueKind {
1436        RuntimeValueKind::Structured { queryable: true }
1437    }
1438}
1439
1440impl<T: RuntimeValueEncode> RuntimeValueEncode for Vec<T> {
1441    fn to_value(&self) -> Value {
1442        runtime_value_collection_to_value(self)
1443    }
1444}
1445
1446impl<T: RuntimeValueDecode> RuntimeValueDecode for Vec<T> {
1447    fn from_value(value: &Value) -> Option<Self> {
1448        runtime_value_vec_from_value(value)
1449    }
1450
1451    fn from_value_with_enum_context(
1452        value: &Value,
1453        context: &dyn RuntimeEnumContext,
1454    ) -> Option<Self> {
1455        let Value::List(values) = value else {
1456            return None;
1457        };
1458        values
1459            .iter()
1460            .map(|value| T::from_value_with_enum_context(value, context))
1461            .collect()
1462    }
1463}
1464
1465impl<T> RuntimeValueMeta for BTreeSet<T>
1466where
1467    T: Ord,
1468{
1469    fn kind() -> RuntimeValueKind {
1470        RuntimeValueKind::Structured { queryable: true }
1471    }
1472}
1473
1474impl<T> RuntimeValueEncode for BTreeSet<T>
1475where
1476    T: Ord + RuntimeValueEncode,
1477{
1478    fn to_value(&self) -> Value {
1479        runtime_value_collection_to_value(self)
1480    }
1481}
1482
1483impl<T> RuntimeValueDecode for BTreeSet<T>
1484where
1485    T: Ord + RuntimeValueDecode,
1486{
1487    fn from_value(value: &Value) -> Option<Self> {
1488        runtime_value_btree_set_from_value(value)
1489    }
1490
1491    fn from_value_with_enum_context(
1492        value: &Value,
1493        context: &dyn RuntimeEnumContext,
1494    ) -> Option<Self> {
1495        let Value::List(values) = value else {
1496            return None;
1497        };
1498        values
1499            .iter()
1500            .map(|value| T::from_value_with_enum_context(value, context))
1501            .collect()
1502    }
1503}
1504
1505impl<K, V> RuntimeValueMeta for BTreeMap<K, V>
1506where
1507    K: Ord,
1508{
1509    fn kind() -> RuntimeValueKind {
1510        RuntimeValueKind::Structured { queryable: true }
1511    }
1512}
1513
1514impl<K, V> RuntimeValueEncode for BTreeMap<K, V>
1515where
1516    K: Ord + RuntimeValueEncode,
1517    V: RuntimeValueEncode,
1518{
1519    fn to_value(&self) -> Value {
1520        runtime_value_map_collection_to_value(self, std::any::type_name::<Self>())
1521    }
1522}
1523
1524impl<K, V> RuntimeValueDecode for BTreeMap<K, V>
1525where
1526    K: Ord + RuntimeValueDecode,
1527    V: RuntimeValueDecode,
1528{
1529    fn from_value(value: &Value) -> Option<Self> {
1530        runtime_value_btree_map_from_value(value)
1531    }
1532
1533    fn from_value_with_enum_context(
1534        value: &Value,
1535        context: &dyn RuntimeEnumContext,
1536    ) -> Option<Self> {
1537        let Value::Map(entries) = value else {
1538            return None;
1539        };
1540        entries
1541            .iter()
1542            .map(|(key, value)| {
1543                Some((
1544                    K::from_value_with_enum_context(key, context)?,
1545                    V::from_value_with_enum_context(value, context)?,
1546                ))
1547            })
1548            .collect()
1549    }
1550}
1551
1552// impl_runtime_value
1553#[macro_export]
1554macro_rules! impl_runtime_value {
1555    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
1556        $(
1557            impl RuntimeValueMeta for $type {
1558                fn kind() -> RuntimeValueKind {
1559                    RuntimeValueKind::Atomic
1560                }
1561            }
1562
1563            impl RuntimeValueEncode for $type {
1564                fn to_value(&self) -> Value {
1565                    Value::$variant((*self).into())
1566                }
1567            }
1568
1569            impl RuntimeValueDecode for $type {
1570                fn from_value(value: &Value) -> Option<Self> {
1571                    match value {
1572                        Value::$variant(v) => (*v).try_into().ok(),
1573                        _ => None,
1574                    }
1575                }
1576            }
1577        )*
1578    };
1579}
1580
1581impl_runtime_value!(
1582    i8 => Int64,
1583    i16 => Int64,
1584    i32 => Int64,
1585    i64 => Int64,
1586    i128 => Int128,
1587    u8 => Nat64,
1588    u16 => Nat64,
1589    u32 => Nat64,
1590    u64 => Nat64,
1591    u128 => Nat128,
1592    bool => Bool,
1593);
1594
1595/// ============================================================================
1596/// MISC HELPERS
1597/// ============================================================================
1598
1599///
1600/// Inner
1601///
1602/// For newtypes to expose their innermost value.
1603///
1604
1605pub trait Inner<T> {
1606    fn inner(&self) -> &T;
1607    fn into_inner(self) -> T;
1608}
1609
1610///
1611/// Repr
1612///
1613/// Internal representation boundary for scalar wrapper types.
1614///
1615
1616pub trait Repr {
1617    type Inner;
1618
1619    fn repr(&self) -> Self::Inner;
1620    fn from_repr(inner: Self::Inner) -> Self;
1621}
1622
1623/// ============================================================================
1624/// SANITIZATION / VALIDATION
1625/// ============================================================================
1626
1627///
1628/// Sanitizer
1629///
1630/// Transforms a value into a sanitized version.
1631///
1632
1633pub trait Sanitizer<T> {
1634    fn sanitize(&self, value: &mut T) -> Result<(), String>;
1635
1636    fn sanitize_with_context(
1637        &self,
1638        value: &mut T,
1639        ctx: &mut dyn VisitorContext,
1640    ) -> Result<(), String> {
1641        let _ = ctx;
1642
1643        self.sanitize(value)
1644    }
1645}
1646
1647///
1648/// Validator
1649///
1650/// Allows a node to validate values.
1651///
1652
1653pub trait Validator<T: ?Sized> {
1654    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
1655}