Skip to main content

icydb_core/traits/
mod.rs

1mod aliases;
2mod create;
3#[macro_use]
4mod macros;
5mod update;
6mod view;
7mod visitor;
8
9pub use aliases::*;
10pub use create::*;
11pub use update::*;
12pub use view::*;
13pub use visitor::*;
14
15// -----------------------------------------------------------------------------
16// Standard re-exports for `traits::X` ergonomics
17// -----------------------------------------------------------------------------
18
19pub use canic_cdk::structures::storable::Storable;
20pub use num_traits::{FromPrimitive as NumFromPrimitive, NumCast, ToPrimitive as NumToPrimitive};
21pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
22pub use std::{
23    cmp::{Eq, Ordering, PartialEq},
24    convert::From,
25    default::Default,
26    fmt::Debug,
27    hash::Hash,
28    ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign},
29};
30
31use crate::{prelude::*, types::Id, value::ValueEnum, visitor::VisitorContext};
32
33// ============================================================================
34// FOUNDATIONAL KINDS
35// ============================================================================
36//
37// These traits define *where* something lives in the system,
38// not what data it contains.
39//
40
41///
42/// Path
43/// Fully-qualified schema path.
44///
45
46pub trait Path {
47    const PATH: &'static str;
48}
49
50/// Marker for all schema/runtime nodes.
51pub trait Kind: Path + 'static {}
52impl<T> Kind for T where T: Path + 'static {}
53
54/// Marker for canister namespaces.
55pub trait CanisterKind: Kind {}
56
57/// Marker for data stores bound to a canister.
58pub trait DataStoreKind: Kind {
59    type Canister: CanisterKind;
60}
61
62/// Marker for index stores bound to a canister.
63pub trait IndexStoreKind: Kind {
64    type Canister: CanisterKind;
65}
66
67// ============================================================================
68// ENTITY IDENTITY & SCHEMA
69// ============================================================================
70//
71// These traits describe *what an entity is*, not how it is stored
72// or manipulated at runtime.
73//
74
75///
76/// EntityKey
77///
78/// Associates an entity with the primitive type used as its primary key.
79///
80/// ## Semantics
81/// - Implemented for entity types
82/// - `Self::Key` is the *storage representation* of the primary key
83/// - Keys are plain values (Ulid, u64, Principal, …)
84/// - Typed identity is provided by `Id<Self>`, not by the key itself
85/// - Keys are public identifiers and are never authority-bearing capabilities
86///
87
88pub trait EntityKey {
89    type Key: Copy + Debug + Eq + Ord + FieldValue + EntityKeyBytes + 'static;
90}
91
92///
93/// EntityKeyBytes
94///
95
96pub trait EntityKeyBytes {
97    /// Exact number of bytes produced.
98    const BYTE_LEN: usize;
99
100    /// Write bytes into the provided buffer.
101    fn write_bytes(&self, out: &mut [u8]);
102}
103
104macro_rules! impl_entity_key_bytes_numeric {
105    ($($ty:ty),* $(,)?) => {
106        $(
107            impl EntityKeyBytes for $ty {
108                const BYTE_LEN: usize = ::core::mem::size_of::<Self>();
109
110                fn write_bytes(&self, out: &mut [u8]) {
111                    assert_eq!(out.len(), Self::BYTE_LEN);
112                    out.copy_from_slice(&self.to_be_bytes());
113                }
114            }
115        )*
116    };
117}
118
119impl_entity_key_bytes_numeric!(i8, i16, i32, i64, u8, u16, u32, u64);
120
121impl EntityKeyBytes for () {
122    const BYTE_LEN: usize = 0;
123
124    fn write_bytes(&self, out: &mut [u8]) {
125        assert_eq!(out.len(), Self::BYTE_LEN);
126    }
127}
128
129///
130/// EntityIdentity
131///
132/// Semantic primary-key metadata about an entity.
133///
134/// These constants name identity metadata only. They do not imply trust, ownership,
135/// authorization, or existence.
136///
137
138pub trait EntityIdentity: EntityKey {
139    const ENTITY_NAME: &'static str;
140    const PRIMARY_KEY: &'static str;
141}
142
143///
144/// EntitySchema
145///
146/// Declared schema facts for an entity.
147///
148
149pub trait EntitySchema: EntityIdentity {
150    const MODEL: &'static EntityModel;
151    const FIELDS: &'static [&'static str];
152    const INDEXES: &'static [&'static IndexModel];
153}
154
155// ============================================================================
156// ENTITY RUNTIME COMPOSITION
157// ============================================================================
158//
159// These traits bind schema-defined entities into runtime placement.
160//
161
162///
163/// EntityPlacement
164///
165/// Runtime placement of an entity
166///
167
168pub trait EntityPlacement {
169    type DataStore: DataStoreKind;
170    type Canister: CanisterKind;
171}
172
173///
174/// EntityKind
175///
176/// Fully runtime-bound entity.
177///
178/// This is the *maximum* entity contract and should only be
179/// required by code that actually touches storage or execution.
180///
181
182pub trait EntityKind: EntitySchema + EntityPlacement + Kind + TypeKind {}
183
184// ============================================================================
185// ENTITY VALUES
186// ============================================================================
187//
188// These traits describe *instances* of entities.
189//
190
191///
192/// EntityValue
193///
194/// A concrete entity value that can present a typed identity at boundaries.
195///
196/// Implementors store primitive key material internally.
197/// `id()` constructs a typed `Id<Self>` view on demand.
198/// The returned `Id<Self>` is a public identifier, not proof of authority.
199///
200
201pub trait EntityValue: EntityIdentity + FieldValues + Sized {
202    fn id(&self) -> Id<Self>;
203}
204
205/// Marker for entities with exactly one logical row.
206pub trait SingletonEntity: EntityValue {}
207
208///
209// ============================================================================
210// TYPE SYSTEM CONTRACTS
211// ============================================================================
212//
213// These traits define behavioral expectations for schema-defined types.
214//
215
216///
217/// TypeKind
218///
219/// Any schema-defined data type.
220///
221/// This is a *strong* contract and should only be required
222/// where full lifecycle semantics are needed.
223///
224
225pub trait TypeKind:
226    Kind
227    + AsView
228    + Clone
229    + Default
230    + Serialize
231    + DeserializeOwned
232    + Sanitize
233    + Validate
234    + Visitable
235    + PartialEq
236{
237}
238
239impl<T> TypeKind for T where
240    T: Kind
241        + AsView
242        + Clone
243        + Default
244        + DeserializeOwned
245        + PartialEq
246        + Serialize
247        + Sanitize
248        + Validate
249        + Visitable
250{
251}
252
253/// ============================================================================
254/// QUERY VALUE BOUNDARIES
255/// ============================================================================
256
257///
258/// Collection
259///
260/// Explicit iteration contract for list/set wrapper types.
261/// Avoids implicit deref-based access to inner collections.
262///
263
264pub trait Collection {
265    type Item;
266
267    /// Iterator over the collection's items, tied to the borrow of `self`.
268    type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
269    where
270        Self: 'a;
271
272    /// Returns an iterator over the collection's items.
273    fn iter(&self) -> Self::Iter<'_>;
274
275    /// Returns the number of items in the collection.
276    fn len(&self) -> usize;
277
278    /// Returns true if the collection contains no items.
279    fn is_empty(&self) -> bool {
280        self.len() == 0
281    }
282}
283
284///
285/// MapCollection
286///
287/// Explicit iteration contract for map wrapper types.
288/// Avoids implicit deref-based access to inner collections.
289///
290
291pub trait MapCollection {
292    type Key;
293    type Value;
294
295    /// Iterator over the map's key/value pairs, tied to the borrow of `self`.
296    type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
297    where
298        Self: 'a;
299
300    /// Returns an iterator over the map's key/value pairs.
301    fn iter(&self) -> Self::Iter<'_>;
302
303    /// Returns the number of entries in the map.
304    fn len(&self) -> usize;
305
306    /// Returns true if the map contains no entries.
307    fn is_empty(&self) -> bool {
308        self.len() == 0
309    }
310}
311
312pub trait EnumValue {
313    fn to_value_enum(&self) -> ValueEnum;
314}
315
316pub trait FieldValues {
317    fn get_value(&self, field: &str) -> Option<Value>;
318}
319
320///
321/// FieldValueKind
322///
323/// Schema affordance classification for query planning and validation.
324/// Describes whether a field is planner-addressable and predicate-queryable.
325///
326#[derive(Clone, Copy, Debug, Eq, PartialEq)]
327pub enum FieldValueKind {
328    /// Planner-addressable atomic value.
329    Atomic,
330
331    /// Structured value with known internal fields that the planner
332    /// does not reason about as an addressable query target.
333    Structured {
334        /// Whether predicates may be expressed against this field.
335        queryable: bool,
336    },
337}
338
339impl FieldValueKind {
340    #[must_use]
341    pub const fn is_queryable(self) -> bool {
342        match self {
343            Self::Atomic => true,
344            Self::Structured { queryable } => queryable,
345        }
346    }
347}
348
349///
350/// FieldValue
351///
352/// Conversion boundary for values used in query predicates.
353///
354/// Represents values that can appear on the *right-hand side* of predicates.
355///
356
357pub trait FieldValue {
358    fn kind() -> FieldValueKind
359    where
360        Self: Sized;
361
362    fn to_value(&self) -> Value;
363
364    #[must_use]
365    fn from_value(value: &Value) -> Option<Self>
366    where
367        Self: Sized;
368}
369
370impl FieldValue for &str {
371    fn kind() -> FieldValueKind {
372        FieldValueKind::Atomic
373    }
374
375    fn to_value(&self) -> Value {
376        Value::Text((*self).to_string())
377    }
378
379    fn from_value(_value: &Value) -> Option<Self> {
380        None
381    }
382}
383
384impl FieldValue for String {
385    fn kind() -> FieldValueKind {
386        FieldValueKind::Atomic
387    }
388
389    fn to_value(&self) -> Value {
390        Value::Text(self.clone())
391    }
392
393    fn from_value(value: &Value) -> Option<Self> {
394        match value {
395            Value::Text(v) => Some(v.clone()),
396            _ => None,
397        }
398    }
399}
400
401impl<T: FieldValue> FieldValue for Option<T> {
402    fn kind() -> FieldValueKind {
403        T::kind()
404    }
405
406    fn to_value(&self) -> Value {
407        match self {
408            Some(v) => v.to_value(),
409            None => Value::Null,
410        }
411    }
412
413    fn from_value(value: &Value) -> Option<Self> {
414        if matches!(value, Value::Null) {
415            return Some(None);
416        }
417
418        T::from_value(value).map(Some)
419    }
420}
421
422impl<T: FieldValue> FieldValue for Box<T> {
423    fn kind() -> FieldValueKind {
424        T::kind()
425    }
426
427    fn to_value(&self) -> Value {
428        (**self).to_value()
429    }
430
431    fn from_value(value: &Value) -> Option<Self> {
432        T::from_value(value).map(Self::new)
433    }
434}
435
436impl<T: FieldValue> FieldValue for Vec<Box<T>> {
437    fn kind() -> FieldValueKind {
438        FieldValueKind::Structured { queryable: true }
439    }
440
441    fn to_value(&self) -> Value {
442        Value::List(self.iter().map(FieldValue::to_value).collect())
443    }
444
445    fn from_value(value: &Value) -> Option<Self> {
446        let Value::List(items) = value else {
447            return None;
448        };
449
450        let mut out = Self::with_capacity(items.len());
451        for item in items {
452            out.push(Box::new(T::from_value(item)?));
453        }
454
455        Some(out)
456    }
457}
458
459// impl_field_value
460#[macro_export]
461macro_rules! impl_field_value {
462    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
463        $(
464            impl FieldValue for $type {
465                fn kind() -> FieldValueKind {
466                    FieldValueKind::Atomic
467                }
468
469                fn to_value(&self) -> Value {
470                    Value::$variant((*self).into())
471                }
472
473                fn from_value(value: &Value) -> Option<Self> {
474                    match value {
475                        Value::$variant(v) => (*v).try_into().ok(),
476                        _ => None,
477                    }
478                }
479            }
480        )*
481    };
482}
483
484impl_field_value!(
485    i8 => Int,
486    i16 => Int,
487    i32 => Int,
488    i64 => Int,
489    u8 => Uint,
490    u16 => Uint,
491    u32 => Uint,
492    u64 => Uint,
493    bool => Bool,
494);
495
496/// ============================================================================
497/// MISC HELPERS
498/// ============================================================================
499
500///
501/// Inner
502///
503/// For newtypes to expose their innermost value.
504///
505pub trait Inner<T> {
506    fn inner(&self) -> &T;
507    fn into_inner(self) -> T;
508}
509
510// impl_inner
511#[macro_export]
512macro_rules! impl_inner {
513    ($($type:ty),*) => {
514        $(
515            impl Inner<$type> for $type {
516                fn inner(&self) -> &$type {
517                    &self
518                }
519                fn into_inner(self) -> $type {
520                    self
521                }
522            }
523        )*
524    };
525}
526
527impl_inner!(
528    bool, f32, f64, i8, i16, i32, i64, i128, String, u8, u16, u32, u64, u128
529);
530
531/// ============================================================================
532/// SANITIZATION / VALIDATION
533/// ============================================================================
534
535///
536/// Sanitizer
537///
538/// Transforms a value into a sanitized version.
539///
540pub trait Sanitizer<T> {
541    fn sanitize(&self, value: &mut T) -> Result<(), String>;
542}
543
544///
545/// Validator
546///
547/// Allows a node to validate values.
548///
549pub trait Validator<T: ?Sized> {
550    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
551}