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