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