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 atomic;
10mod numeric_value;
11mod visitor;
12
13use crate::{
14    error::InternalError,
15    model::field::{FieldKind, FieldStorageDecode},
16    prelude::*,
17    types::{EntityTag, Id},
18    value::{Value, ValueEnum},
19    visitor::VisitorContext,
20};
21use std::collections::{BTreeMap, BTreeSet};
22
23pub use atomic::*;
24pub use numeric_value::*;
25pub use visitor::*;
26
27// -----------------------------------------------------------------------------
28// Standard re-exports for `traits::X` ergonomics
29// -----------------------------------------------------------------------------
30
31pub use canic_cdk::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
77///
78/// StoreKind
79/// Marker for data stores bound to a canister
80///
81
82pub trait StoreKind: Kind {
83    type Canister: CanisterKind;
84}
85
86// ============================================================================
87// ENTITY IDENTITY & SCHEMA
88// ============================================================================
89//
90// These traits describe *what an entity is*, not how it is stored
91// or manipulated at runtime.
92//
93
94///
95/// EntityKey
96///
97/// Associates an entity with the primitive type used as its primary key.
98///
99/// ## Semantics
100/// - Implemented for entity types
101/// - `Self::Key` is the *storage representation* of the primary key
102/// - Keys are plain values (Ulid, u64, Principal, …)
103/// - Typed identity is provided by `Id<Self>`, not by the key itself
104/// - Keys are public identifiers and are never authority-bearing capabilities
105///
106
107pub trait EntityKey {
108    type Key: Copy + Debug + Eq + Ord + KeyValueCodec + EntityKeyBytes + 'static;
109}
110
111///
112/// EntityKeyBytes
113///
114
115pub trait EntityKeyBytes {
116    /// Exact number of bytes produced.
117    const BYTE_LEN: usize;
118
119    /// Write bytes into the provided buffer.
120    fn write_bytes(&self, out: &mut [u8]);
121}
122
123macro_rules! impl_entity_key_bytes_numeric {
124    ($($ty:ty),* $(,)?) => {
125        $(
126            impl EntityKeyBytes for $ty {
127                const BYTE_LEN: usize = ::core::mem::size_of::<Self>();
128
129                fn write_bytes(&self, out: &mut [u8]) {
130                    assert_eq!(out.len(), Self::BYTE_LEN);
131                    out.copy_from_slice(&self.to_be_bytes());
132                }
133            }
134        )*
135    };
136}
137
138impl_entity_key_bytes_numeric!(i8, i16, i32, i64, u8, u16, u32, u64);
139
140impl EntityKeyBytes for () {
141    const BYTE_LEN: usize = 0;
142
143    fn write_bytes(&self, out: &mut [u8]) {
144        assert_eq!(out.len(), Self::BYTE_LEN);
145    }
146}
147
148///
149/// KeyValueCodec
150///
151/// Narrow runtime `Value` codec for typed primary keys and key-only access
152/// surfaces. This exists to keep cursor, access, and key-routing contracts off
153/// the wider structured-value conversion surface used by persisted-field
154/// codecs and planner queryability metadata.
155///
156
157pub trait KeyValueCodec {
158    fn to_key_value(&self) -> Value;
159
160    #[must_use]
161    fn from_key_value(value: &Value) -> Option<Self>
162    where
163        Self: Sized;
164}
165
166impl<T> KeyValueCodec for T
167where
168    T: ValueSurfaceDecode + ValueSurfaceEncode,
169{
170    fn to_key_value(&self) -> Value {
171        self.to_value()
172    }
173
174    fn from_key_value(value: &Value) -> Option<Self> {
175        Self::from_value(value)
176    }
177}
178
179///
180///
181/// ValueSurfaceEncode
182///
183/// Narrow runtime lowering boundary for typed value surfaces that can be
184/// projected into the internal `Value` union.
185/// This is the encode-side owner used by generated wrappers and shared helper
186/// paths that only need one-way lowering.
187///
188pub trait ValueSurfaceEncode {
189    fn to_value(&self) -> Value;
190}
191
192///
193/// ValueSurfaceDecode
194///
195/// Narrow runtime reconstruction boundary for typed value surfaces that can be
196/// rebuilt from the internal `Value` union.
197/// This is the decode-side owner used by generated wrappers and shared helper
198/// paths that only need one-way typed reconstruction.
199///
200pub trait ValueSurfaceDecode {
201    #[must_use]
202    fn from_value(value: &Value) -> Option<Self>
203    where
204        Self: Sized;
205}
206
207///
208/// value_surface_to_value
209///
210/// Hidden runtime lowering helper for generated code and other encode-only
211/// call sites that should not spell the encode trait directly.
212///
213pub fn value_surface_to_value<T>(value: &T) -> Value
214where
215    T: ?Sized + ValueSurfaceEncode,
216{
217    value.to_value()
218}
219
220///
221/// value_surface_from_value
222///
223/// Hidden runtime reconstruction helper for generated code and other decode
224/// call sites that should not spell the decode trait directly.
225///
226#[must_use]
227pub fn value_surface_from_value<T>(value: &Value) -> Option<T>
228where
229    T: ValueSurfaceDecode,
230{
231    T::from_value(value)
232}
233
234///
235/// PersistedByKindCodec
236///
237/// PersistedByKindCodec lets one field type own the stricter schema-selected
238/// `ByKind` persisted-row storage contract.
239/// This keeps the persisted-row helper boundary off the wider runtime
240/// value-surface conversion seam even when the current implementation still delegates to
241/// runtime `Value` conversion internally.
242///
243
244pub trait PersistedByKindCodec: Sized {
245    /// Encode one field payload through the explicit `ByKind` storage lane.
246    fn encode_persisted_slot_payload_by_kind(
247        &self,
248        kind: FieldKind,
249        field_name: &'static str,
250    ) -> Result<Vec<u8>, InternalError>;
251
252    /// Decode one optional field payload through the explicit `ByKind`
253    /// storage lane, preserving the null sentinel for wrapper-owned optional
254    /// handling.
255    fn decode_persisted_option_slot_payload_by_kind(
256        bytes: &[u8],
257        kind: FieldKind,
258        field_name: &'static str,
259    ) -> Result<Option<Self>, InternalError>;
260}
261
262///
263/// PersistedStructuredFieldCodec
264///
265/// Direct persisted payload codec for custom structured field values.
266/// This trait owns only the typed field <-> persisted custom payload bytes
267/// boundary used by persisted-row storage helpers.
268///
269
270pub trait PersistedStructuredFieldCodec {
271    /// Encode this typed structured field into persisted custom payload bytes.
272    fn encode_persisted_structured_payload(&self) -> Result<Vec<u8>, InternalError>;
273
274    /// Decode this typed structured field from persisted custom payload bytes.
275    fn decode_persisted_structured_payload(bytes: &[u8]) -> Result<Self, InternalError>
276    where
277        Self: Sized;
278}
279
280///
281/// EntitySchema
282///
283/// Declared runtime schema facts for an entity.
284///
285/// `NAME` seeds self-referential model construction for relation metadata.
286/// `MODEL` remains the authoritative runtime authority for field, primary-key,
287/// and index metadata consumed by planning and execution.
288///
289
290pub trait EntitySchema: EntityKey {
291    const NAME: &'static str;
292    const MODEL: &'static EntityModel;
293}
294
295// ============================================================================
296// ENTITY RUNTIME COMPOSITION
297// ============================================================================
298//
299// These traits bind schema-defined entities into runtime placement.
300//
301
302///
303/// EntityPlacement
304///
305/// Runtime placement of an entity
306///
307
308pub trait EntityPlacement {
309    type Store: StoreKind;
310    type Canister: CanisterKind;
311}
312
313///
314/// EntityKind
315///
316/// Fully runtime-bound entity.
317///
318/// This is the *maximum* entity contract and should only be
319/// required by code that actually touches storage or execution.
320///
321
322pub trait EntityKind: EntitySchema + EntityPlacement + Kind + TypeKind {
323    const ENTITY_TAG: EntityTag;
324}
325
326// ============================================================================
327// ENTITY VALUES
328// ============================================================================
329//
330// These traits describe *instances* of entities.
331//
332
333///
334/// EntityValue
335///
336/// A concrete entity value that can present a typed identity at boundaries.
337///
338/// Implementors store primitive key material internally.
339/// `id()` constructs a typed `Id<Self>` view on demand.
340/// The returned `Id<Self>` is a public identifier, not proof of authority.
341///
342
343pub trait EntityValue: EntityKey + FieldProjection + Sized {
344    fn id(&self) -> Id<Self>;
345}
346
347///
348/// EntityCreateMaterialization
349///
350/// Materialized authored create payload produced by one generated create input.
351/// Carries both the fully-typed entity after-image and the authored field-slot
352/// list so save preflight can still distinguish omission from authorship.
353///
354
355pub struct EntityCreateMaterialization<E> {
356    entity: E,
357    authored_slots: Vec<usize>,
358}
359
360impl<E> EntityCreateMaterialization<E> {
361    /// Build one materialized typed create payload.
362    #[must_use]
363    pub const fn new(entity: E, authored_slots: Vec<usize>) -> Self {
364        Self {
365            entity,
366            authored_slots,
367        }
368    }
369
370    /// Consume and return the typed entity after-image.
371    #[must_use]
372    pub fn into_entity(self) -> E {
373        self.entity
374    }
375
376    /// Borrow the authored field slots carried by this insert payload.
377    #[must_use]
378    pub const fn authored_slots(&self) -> &[usize] {
379        self.authored_slots.as_slice()
380    }
381}
382
383///
384/// EntityCreateInput
385///
386/// Create-authored typed input for one entity.
387/// This is intentionally distinct from the readable entity shape so generated
388/// and managed fields can stay structurally un-authorable on typed creates.
389///
390
391pub trait EntityCreateInput: Sized {
392    type Entity: EntityValue + Default;
393
394    /// Materialize one typed create payload plus authored-slot provenance.
395    fn materialize_create(self) -> EntityCreateMaterialization<Self::Entity>;
396}
397
398///
399/// EntityCreateType
400///
401/// Entity-owned association from one entity type to its generated create
402/// input shape.
403/// This keeps the public create-input surface generic at the facade boundary
404/// while generated code remains free to pick any concrete backing type name.
405///
406
407pub trait EntityCreateType: EntityValue {
408    type Create: EntityCreateInput<Entity = Self>;
409}
410
411/// Marker for entities with exactly one logical row.
412pub trait SingletonEntity: EntityValue {}
413
414///
415// ============================================================================
416// TYPE SYSTEM CONTRACTS
417// ============================================================================
418//
419// These traits define behavioral expectations for schema-defined types.
420//
421
422///
423/// TypeKind
424///
425/// Any schema-defined data type.
426///
427/// This is a *strong* contract and should only be required
428/// where full lifecycle semantics are needed.
429///
430
431pub trait TypeKind:
432    Kind + Clone + Default + DeserializeOwned + Sanitize + Validate + Visitable + PartialEq
433{
434}
435
436impl<T> TypeKind for T where
437    T: Kind + Clone + Default + DeserializeOwned + PartialEq + Sanitize + Validate + Visitable
438{
439}
440
441///
442/// FieldTypeMeta
443///
444/// Static runtime field metadata for one schema-facing value type.
445/// This is the single authority for generated field kind and storage-decode
446/// metadata, so callers do not need per-type inherent constants.
447///
448
449pub trait FieldTypeMeta {
450    /// Semantic field kind used for runtime planning and validation.
451    const KIND: FieldKind;
452
453    /// Persisted decode contract used by row and payload decoding.
454    const STORAGE_DECODE: FieldStorageDecode;
455}
456
457///
458/// PersistedFieldMetaCodec
459///
460/// PersistedFieldMetaCodec lets one field type own the persisted-row
461/// encode/decode contract selected by its `FieldTypeMeta`.
462/// This keeps the meta-hinted persisted-row path on the field-type owner
463/// instead of forcing row helpers to require both the by-kind and direct
464/// structured codec traits at once.
465///
466
467pub trait PersistedFieldMetaCodec: FieldTypeMeta + Sized {
468    /// Encode one non-optional field payload through the type's own
469    /// `FieldTypeMeta` storage contract.
470    fn encode_persisted_slot_payload_by_meta(
471        &self,
472        field_name: &'static str,
473    ) -> Result<Vec<u8>, InternalError>;
474
475    /// Decode one non-optional field payload through the type's own
476    /// `FieldTypeMeta` storage contract.
477    fn decode_persisted_slot_payload_by_meta(
478        bytes: &[u8],
479        field_name: &'static str,
480    ) -> Result<Self, InternalError>;
481
482    /// Encode one optional field payload through the inner type's own
483    /// `FieldTypeMeta` storage contract.
484    fn encode_persisted_option_slot_payload_by_meta(
485        value: &Option<Self>,
486        field_name: &'static str,
487    ) -> Result<Vec<u8>, InternalError>;
488
489    /// Decode one optional field payload through the inner type's own
490    /// `FieldTypeMeta` storage contract.
491    fn decode_persisted_option_slot_payload_by_meta(
492        bytes: &[u8],
493        field_name: &'static str,
494    ) -> Result<Option<Self>, InternalError>;
495}
496
497impl<T> FieldTypeMeta for Option<T>
498where
499    T: FieldTypeMeta,
500{
501    const KIND: FieldKind = T::KIND;
502    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
503}
504
505impl<T> FieldTypeMeta for Box<T>
506where
507    T: FieldTypeMeta,
508{
509    const KIND: FieldKind = T::KIND;
510    const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
511}
512
513// Standard containers mirror the generated collection-wrapper contract: their
514// semantic kind remains structural, but persisted decode routes through the
515// shared structural `Value` storage seam instead of leaf-by-leaf scalar decode.
516impl<T> FieldTypeMeta for Vec<T>
517where
518    T: FieldTypeMeta,
519{
520    const KIND: FieldKind = FieldKind::List(&T::KIND);
521    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
522}
523
524impl<T> FieldTypeMeta for BTreeSet<T>
525where
526    T: FieldTypeMeta,
527{
528    const KIND: FieldKind = FieldKind::Set(&T::KIND);
529    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
530}
531
532impl<K, V> FieldTypeMeta for BTreeMap<K, V>
533where
534    K: FieldTypeMeta,
535    V: FieldTypeMeta,
536{
537    const KIND: FieldKind = FieldKind::Map {
538        key: &K::KIND,
539        value: &V::KIND,
540    };
541    const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
542}
543
544/// ============================================================================
545/// QUERY VALUE BOUNDARIES
546/// ============================================================================
547
548///
549/// Collection
550///
551/// Explicit iteration contract for list/set wrapper types.
552/// Keeps generic collection code on one stable boundary even when concrete
553/// wrapper types opt into direct container ergonomics.
554///
555
556pub trait Collection {
557    type Item;
558
559    /// Iterator over the collection's items, tied to the borrow of `self`.
560    type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
561    where
562        Self: 'a;
563
564    /// Returns an iterator over the collection's items.
565    fn iter(&self) -> Self::Iter<'_>;
566
567    /// Returns the number of items in the collection.
568    fn len(&self) -> usize;
569
570    /// Returns true if the collection contains no items.
571    fn is_empty(&self) -> bool {
572        self.len() == 0
573    }
574}
575
576///
577/// MapCollection
578///
579/// Explicit iteration contract for map wrapper types.
580/// Keeps generic map code on one stable boundary even when concrete wrapper
581/// types opt into direct container ergonomics.
582///
583
584pub trait MapCollection {
585    type Key;
586    type Value;
587
588    /// Iterator over the map's key/value pairs, tied to the borrow of `self`.
589    type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
590    where
591        Self: 'a;
592
593    /// Returns an iterator over the map's key/value pairs.
594    fn iter(&self) -> Self::Iter<'_>;
595
596    /// Returns the number of entries in the map.
597    fn len(&self) -> usize;
598
599    /// Returns true if the map contains no entries.
600    fn is_empty(&self) -> bool {
601        self.len() == 0
602    }
603}
604
605impl<T> Collection for Vec<T> {
606    type Item = T;
607    type Iter<'a>
608        = std::slice::Iter<'a, T>
609    where
610        Self: 'a;
611
612    fn iter(&self) -> Self::Iter<'_> {
613        self.as_slice().iter()
614    }
615
616    fn len(&self) -> usize {
617        self.as_slice().len()
618    }
619}
620
621impl<T> Collection for BTreeSet<T> {
622    type Item = T;
623    type Iter<'a>
624        = std::collections::btree_set::Iter<'a, T>
625    where
626        Self: 'a;
627
628    fn iter(&self) -> Self::Iter<'_> {
629        self.iter()
630    }
631
632    fn len(&self) -> usize {
633        self.len()
634    }
635}
636
637impl<K, V> MapCollection for BTreeMap<K, V> {
638    type Key = K;
639    type Value = V;
640    type Iter<'a>
641        = std::collections::btree_map::Iter<'a, K, V>
642    where
643        Self: 'a;
644
645    fn iter(&self) -> Self::Iter<'_> {
646        self.iter()
647    }
648
649    fn len(&self) -> usize {
650        self.len()
651    }
652}
653
654pub trait EnumValue {
655    fn to_value_enum(&self) -> ValueEnum;
656}
657
658pub trait FieldProjection {
659    /// Resolve one field value by stable field slot index.
660    fn get_value_by_index(&self, index: usize) -> Option<Value>;
661}
662
663///
664/// ValueSurfaceKind
665///
666/// Schema affordance classification for query planning and validation.
667/// Describes whether a field is planner-addressable and predicate-queryable.
668///
669
670#[derive(Clone, Copy, Debug, Eq, PartialEq)]
671pub enum ValueSurfaceKind {
672    /// Planner-addressable atomic value.
673    Atomic,
674
675    /// Structured value with known internal fields that the planner
676    /// does not reason about as an addressable query target.
677    Structured {
678        /// Whether predicates may be expressed against this field.
679        queryable: bool,
680    },
681}
682
683impl ValueSurfaceKind {
684    #[must_use]
685    pub const fn is_queryable(self) -> bool {
686        match self {
687            Self::Atomic => true,
688            Self::Structured { queryable } => queryable,
689        }
690    }
691}
692
693///
694/// ValueSurfaceMeta
695///
696/// Schema/queryability metadata for one typed field value surface.
697/// This stays separate from encode/decode conversion so metadata-only callers do not need
698/// to depend on runtime `Value` conversion.
699///
700
701pub trait ValueSurfaceMeta {
702    fn kind() -> ValueSurfaceKind
703    where
704        Self: Sized;
705}
706
707///
708/// value_surface_collection_to_value
709///
710/// Shared collection-to-`Value::List` lowering for generated wrapper types.
711/// This keeps list and set value-surface impls from re-emitting the same item
712/// iteration body for every generated schema type.
713///
714
715pub fn value_surface_collection_to_value<C>(collection: &C) -> Value
716where
717    C: Collection,
718    C::Item: ValueSurfaceEncode,
719{
720    Value::List(
721        collection
722            .iter()
723            .map(ValueSurfaceEncode::to_value)
724            .collect(),
725    )
726}
727
728///
729/// value_surface_vec_from_value
730///
731/// Shared `Value::List` decode for generated list wrapper types.
732/// This preserves typed value-surface decoding while avoiding one repeated loop
733/// body per generated list schema type.
734///
735
736#[must_use]
737pub fn value_surface_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
738where
739    T: ValueSurfaceDecode,
740{
741    let Value::List(values) = value else {
742        return None;
743    };
744
745    let mut out = Vec::with_capacity(values.len());
746    for value in values {
747        out.push(T::from_value(value)?);
748    }
749
750    Some(out)
751}
752
753///
754/// value_surface_btree_set_from_value
755///
756/// Shared `Value::List` decode for generated set wrapper types.
757/// This preserves duplicate rejection while avoiding one repeated loop body
758/// per generated set schema type.
759///
760
761#[must_use]
762pub fn value_surface_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
763where
764    T: Ord + ValueSurfaceDecode,
765{
766    let Value::List(values) = value else {
767        return None;
768    };
769
770    let mut out = BTreeSet::new();
771    for value in values {
772        let item = T::from_value(value)?;
773        if !out.insert(item) {
774            return None;
775        }
776    }
777
778    Some(out)
779}
780
781///
782/// value_surface_map_collection_to_value
783///
784/// Shared map-to-`Value::Map` lowering for generated map wrapper types.
785/// This keeps canonicalization and duplicate-key checks in one runtime helper
786/// instead of re-emitting the same map conversion body per generated schema
787/// type.
788///
789
790pub fn value_surface_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
791where
792    M: MapCollection,
793    M::Key: ValueSurfaceEncode,
794    M::Value: ValueSurfaceEncode,
795{
796    let mut entries: Vec<(Value, Value)> = map
797        .iter()
798        .map(|(key, value)| {
799            (
800                ValueSurfaceEncode::to_value(key),
801                ValueSurfaceEncode::to_value(value),
802            )
803        })
804        .collect();
805
806    if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
807        debug_assert!(false, "invalid map field value for {path}: {err}");
808        return Value::Map(entries);
809    }
810
811    Value::sort_map_entries_in_place(entries.as_mut_slice());
812
813    for i in 1..entries.len() {
814        let (left_key, _) = &entries[i - 1];
815        let (right_key, _) = &entries[i];
816        if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
817            debug_assert!(
818                false,
819                "duplicate map key in {path} after value-surface canonicalization",
820            );
821            break;
822        }
823    }
824
825    Value::Map(entries)
826}
827
828///
829/// value_surface_btree_map_from_value
830///
831/// Shared `Value::Map` decode for generated map wrapper types.
832/// This keeps canonical-entry normalization in one runtime helper instead of
833/// re-emitting the same decode body per generated schema type.
834///
835
836#[must_use]
837pub fn value_surface_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
838where
839    K: Ord + ValueSurfaceDecode,
840    V: ValueSurfaceDecode,
841{
842    let Value::Map(entries) = value else {
843        return None;
844    };
845
846    let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
847    if normalized.as_slice() != entries.as_slice() {
848        return None;
849    }
850
851    let mut map = BTreeMap::new();
852    for (entry_key, entry_value) in normalized {
853        let key = K::from_value(&entry_key)?;
854        let value = V::from_value(&entry_value)?;
855        map.insert(key, value);
856    }
857
858    Some(map)
859}
860
861///
862/// value_surface_from_vec_into
863///
864/// Shared `Vec<I> -> Vec<T>` conversion for generated wrapper `From<Vec<I>>`
865/// impls. This keeps list wrappers from re-emitting the same `into_iter` /
866/// `map(Into::into)` collection body for every generated schema type.
867///
868
869#[must_use]
870pub fn value_surface_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
871where
872    I: Into<T>,
873{
874    entries.into_iter().map(Into::into).collect()
875}
876
877///
878/// value_surface_from_vec_into_btree_set
879///
880/// Shared `Vec<I> -> BTreeSet<T>` conversion for generated set wrapper
881/// `From<Vec<I>>` impls. This keeps set wrappers from re-emitting the same
882/// collection conversion body for every generated schema type.
883///
884
885#[must_use]
886pub fn value_surface_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
887where
888    I: Into<T>,
889    T: Ord,
890{
891    entries.into_iter().map(Into::into).collect()
892}
893
894///
895/// value_surface_from_vec_into_btree_map
896///
897/// Shared `Vec<(IK, IV)> -> BTreeMap<K, V>` conversion for generated map
898/// wrapper `From<Vec<(IK, IV)>>` impls. This keeps map wrappers from
899/// re-emitting the same pair-conversion body for every generated schema type.
900///
901
902#[must_use]
903pub fn value_surface_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
904where
905    IK: Into<K>,
906    IV: Into<V>,
907    K: Ord,
908{
909    entries
910        .into_iter()
911        .map(|(key, value)| (key.into(), value.into()))
912        .collect()
913}
914
915///
916/// value_surface_into
917///
918/// Shared `Into<T>` lowering for generated newtype `From<U>` impls.
919/// This keeps newtype wrappers from re-emitting the same single-field
920/// conversion body for every generated schema type.
921///
922
923#[must_use]
924pub fn value_surface_into<T, U>(value: U) -> T
925where
926    U: Into<T>,
927{
928    value.into()
929}
930
931impl ValueSurfaceMeta for &str {
932    fn kind() -> ValueSurfaceKind {
933        ValueSurfaceKind::Atomic
934    }
935}
936
937impl ValueSurfaceEncode for &str {
938    fn to_value(&self) -> Value {
939        Value::Text((*self).to_string())
940    }
941}
942
943impl ValueSurfaceDecode for &str {
944    fn from_value(_value: &Value) -> Option<Self> {
945        None
946    }
947}
948
949impl ValueSurfaceMeta for String {
950    fn kind() -> ValueSurfaceKind {
951        ValueSurfaceKind::Atomic
952    }
953}
954
955impl ValueSurfaceEncode for String {
956    fn to_value(&self) -> Value {
957        Value::Text(self.clone())
958    }
959}
960
961impl ValueSurfaceDecode for String {
962    fn from_value(value: &Value) -> Option<Self> {
963        match value {
964            Value::Text(v) => Some(v.clone()),
965            _ => None,
966        }
967    }
968}
969
970impl<T: ValueSurfaceMeta> ValueSurfaceMeta for Option<T> {
971    fn kind() -> ValueSurfaceKind {
972        T::kind()
973    }
974}
975
976impl<T: ValueSurfaceEncode> ValueSurfaceEncode for Option<T> {
977    fn to_value(&self) -> Value {
978        match self {
979            Some(v) => v.to_value(),
980            None => Value::Null,
981        }
982    }
983}
984
985impl<T: ValueSurfaceDecode> ValueSurfaceDecode for Option<T> {
986    fn from_value(value: &Value) -> Option<Self> {
987        if matches!(value, Value::Null) {
988            return Some(None);
989        }
990
991        T::from_value(value).map(Some)
992    }
993}
994
995impl<T: ValueSurfaceMeta> ValueSurfaceMeta for Box<T> {
996    fn kind() -> ValueSurfaceKind {
997        T::kind()
998    }
999}
1000
1001impl<T: ValueSurfaceEncode> ValueSurfaceEncode for Box<T> {
1002    fn to_value(&self) -> Value {
1003        (**self).to_value()
1004    }
1005}
1006
1007impl<T: ValueSurfaceDecode> ValueSurfaceDecode for Box<T> {
1008    fn from_value(value: &Value) -> Option<Self> {
1009        T::from_value(value).map(Self::new)
1010    }
1011}
1012
1013impl<T> ValueSurfaceMeta for Vec<T> {
1014    fn kind() -> ValueSurfaceKind {
1015        ValueSurfaceKind::Structured { queryable: true }
1016    }
1017}
1018
1019impl<T: ValueSurfaceEncode> ValueSurfaceEncode for Vec<T> {
1020    fn to_value(&self) -> Value {
1021        value_surface_collection_to_value(self)
1022    }
1023}
1024
1025impl<T: ValueSurfaceDecode> ValueSurfaceDecode for Vec<T> {
1026    fn from_value(value: &Value) -> Option<Self> {
1027        value_surface_vec_from_value(value)
1028    }
1029}
1030
1031impl<T> ValueSurfaceMeta for BTreeSet<T>
1032where
1033    T: Ord,
1034{
1035    fn kind() -> ValueSurfaceKind {
1036        ValueSurfaceKind::Structured { queryable: true }
1037    }
1038}
1039
1040impl<T> ValueSurfaceEncode for BTreeSet<T>
1041where
1042    T: Ord + ValueSurfaceEncode,
1043{
1044    fn to_value(&self) -> Value {
1045        value_surface_collection_to_value(self)
1046    }
1047}
1048
1049impl<T> ValueSurfaceDecode for BTreeSet<T>
1050where
1051    T: Ord + ValueSurfaceDecode,
1052{
1053    fn from_value(value: &Value) -> Option<Self> {
1054        value_surface_btree_set_from_value(value)
1055    }
1056}
1057
1058impl<K, V> ValueSurfaceMeta for BTreeMap<K, V>
1059where
1060    K: Ord,
1061{
1062    fn kind() -> ValueSurfaceKind {
1063        ValueSurfaceKind::Structured { queryable: true }
1064    }
1065}
1066
1067impl<K, V> ValueSurfaceEncode for BTreeMap<K, V>
1068where
1069    K: Ord + ValueSurfaceEncode,
1070    V: ValueSurfaceEncode,
1071{
1072    fn to_value(&self) -> Value {
1073        value_surface_map_collection_to_value(self, std::any::type_name::<Self>())
1074    }
1075}
1076
1077impl<K, V> ValueSurfaceDecode for BTreeMap<K, V>
1078where
1079    K: Ord + ValueSurfaceDecode,
1080    V: ValueSurfaceDecode,
1081{
1082    fn from_value(value: &Value) -> Option<Self> {
1083        value_surface_btree_map_from_value(value)
1084    }
1085}
1086
1087// impl_field_value
1088#[macro_export]
1089macro_rules! impl_field_value {
1090    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
1091        $(
1092            impl ValueSurfaceMeta for $type {
1093                fn kind() -> ValueSurfaceKind {
1094                    ValueSurfaceKind::Atomic
1095                }
1096            }
1097
1098            impl ValueSurfaceEncode for $type {
1099                fn to_value(&self) -> Value {
1100                    Value::$variant((*self).into())
1101                }
1102            }
1103
1104            impl ValueSurfaceDecode for $type {
1105                fn from_value(value: &Value) -> Option<Self> {
1106                    match value {
1107                        Value::$variant(v) => (*v).try_into().ok(),
1108                        _ => None,
1109                    }
1110                }
1111            }
1112        )*
1113    };
1114}
1115
1116impl_field_value!(
1117    i8 => Int,
1118    i16 => Int,
1119    i32 => Int,
1120    i64 => Int,
1121    u8 => Uint,
1122    u16 => Uint,
1123    u32 => Uint,
1124    u64 => Uint,
1125    bool => Bool,
1126);
1127
1128/// ============================================================================
1129/// MISC HELPERS
1130/// ============================================================================
1131
1132///
1133/// Inner
1134///
1135/// For newtypes to expose their innermost value.
1136///
1137
1138pub trait Inner<T> {
1139    fn inner(&self) -> &T;
1140    fn into_inner(self) -> T;
1141}
1142
1143impl<T> Inner<T> for T
1144where
1145    T: Atomic,
1146{
1147    fn inner(&self) -> &T {
1148        self
1149    }
1150
1151    fn into_inner(self) -> T {
1152        self
1153    }
1154}
1155
1156///
1157/// Repr
1158///
1159/// Internal representation boundary for scalar wrapper types.
1160///
1161
1162pub trait Repr {
1163    type Inner;
1164
1165    fn repr(&self) -> Self::Inner;
1166    fn from_repr(inner: Self::Inner) -> Self;
1167}
1168
1169/// ============================================================================
1170/// SANITIZATION / VALIDATION
1171/// ============================================================================
1172
1173///
1174/// Sanitizer
1175///
1176/// Transforms a value into a sanitized version.
1177///
1178
1179pub trait Sanitizer<T> {
1180    fn sanitize(&self, value: &mut T) -> Result<(), String>;
1181
1182    fn sanitize_with_context(
1183        &self,
1184        value: &mut T,
1185        ctx: &mut dyn VisitorContext,
1186    ) -> Result<(), String> {
1187        let _ = ctx;
1188
1189        self.sanitize(value)
1190    }
1191}
1192
1193///
1194/// Validator
1195///
1196/// Allows a node to validate values.
1197///
1198
1199pub trait Validator<T: ?Sized> {
1200    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
1201}