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