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