Skip to main content

icydb_core/traits/
mod.rs

1#[macro_use]
2mod macros;
3mod view;
4mod visitor;
5
6pub use view::*;
7pub use visitor::*;
8
9// -----------------------------------------------------------------------------
10// Standard re-exports for `traits::X` ergonomics
11// -----------------------------------------------------------------------------
12
13pub use canic_cdk::structures::storable::Storable;
14pub use num_traits::{FromPrimitive as NumFromPrimitive, NumCast, ToPrimitive as NumToPrimitive};
15pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
16pub use std::{
17    cmp::{Eq, Ordering, PartialEq},
18    convert::From,
19    default::Default,
20    fmt::Debug,
21    hash::Hash,
22    ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign},
23};
24
25use crate::{prelude::*, types::Id, value::ValueEnum, visitor::VisitorContext};
26
27// ============================================================================
28// FOUNDATIONAL KINDS
29// ============================================================================
30//
31// These traits define *where* something lives in the system,
32// not what data it contains.
33//
34
35///
36/// Path
37/// Fully-qualified schema path.
38///
39
40pub trait Path {
41    const PATH: &'static str;
42}
43
44/// Marker for all schema/runtime nodes.
45pub trait Kind: Path + 'static {}
46impl<T> Kind for T where T: Path + 'static {}
47
48/// Marker for canister namespaces.
49pub trait CanisterKind: Kind {}
50
51/// Marker for data stores bound to a canister.
52pub trait DataStoreKind: Kind {
53    type Canister: CanisterKind;
54}
55
56/// Marker for index stores bound to a canister.
57pub trait IndexStoreKind: Kind {
58    type Canister: CanisterKind;
59}
60
61// ============================================================================
62// ENTITY IDENTITY & SCHEMA
63// ============================================================================
64//
65// These traits describe *what an entity is*, not how it is stored
66// or manipulated at runtime.
67//
68
69///
70/// EntityKey
71///
72/// Marker trait for raw entity key material used at storage boundaries.
73///
74
75pub trait EntityKey: Copy + Debug + Eq + Ord + FieldValue + 'static {}
76impl<T> EntityKey for T where T: Copy + Debug + Eq + Ord + FieldValue + 'static {}
77
78///
79/// EntityStorageKey
80///
81/// Raw storage-key facts about an entity.
82///
83
84pub trait EntityStorageKey {
85    type Key: EntityKey;
86}
87
88///
89/// EntityIdentity
90///
91/// Semantic identity facts about an entity.
92///
93
94pub trait EntityIdentity: EntityStorageKey {
95    const ENTITY_NAME: &'static str;
96    const PRIMARY_KEY: &'static str;
97}
98
99///
100/// EntitySchema
101///
102/// Declared schema facts for an entity.
103///
104
105pub trait EntitySchema: EntityIdentity {
106    const MODEL: &'static EntityModel;
107    const FIELDS: &'static [&'static str];
108    const INDEXES: &'static [&'static IndexModel];
109}
110
111// ============================================================================
112// ENTITY RUNTIME COMPOSITION
113// ============================================================================
114//
115// These traits bind schema-defined entities into runtime placement.
116//
117
118///
119/// EntityPlacement
120///
121/// Runtime placement of an entity
122///
123
124pub trait EntityPlacement {
125    type DataStore: DataStoreKind;
126    type Canister: CanisterKind;
127}
128
129///
130/// EntityKind
131///
132/// Fully runtime-bound entity.
133///
134/// This is the *maximum* entity contract and should only be
135/// required by code that actually touches storage or execution.
136///
137
138pub trait EntityKind: EntitySchema + EntityPlacement + Kind + TypeKind {}
139
140// ============================================================================
141// ENTITY VALUES
142// ============================================================================
143//
144// These traits describe *instances* of entities.
145//
146
147///
148/// EntityValue
149///
150/// A concrete entity value.
151///
152/// This trait is intentionally lighter than `EntityKind`.
153/// It does NOT imply storage placement.
154///
155
156pub trait EntityValue: EntityIdentity + FieldValues + Sized {
157    fn id(&self) -> Id<Self>;
158}
159
160/// Marker for entities with exactly one logical row.
161pub trait SingletonEntity: EntityValue {}
162
163///
164// ============================================================================
165// TYPE SYSTEM CONTRACTS
166// ============================================================================
167//
168// These traits define behavioral expectations for schema-defined types.
169//
170
171///
172/// TypeKind
173///
174/// Any schema-defined data type.
175///
176/// This is a *strong* contract and should only be required
177/// where full lifecycle semantics are needed.
178///
179
180pub trait TypeKind:
181    Kind
182    + View
183    + Clone
184    + Default
185    + Serialize
186    + DeserializeOwned
187    + Sanitize
188    + Validate
189    + Visitable
190    + PartialEq
191{
192}
193
194impl<T> TypeKind for T where
195    T: Kind
196        + View
197        + Clone
198        + Default
199        + DeserializeOwned
200        + PartialEq
201        + Serialize
202        + Sanitize
203        + Validate
204        + Visitable
205{
206}
207
208/// ============================================================================
209/// QUERY VALUE BOUNDARIES
210/// ============================================================================
211
212///
213/// Collection
214///
215/// Explicit iteration contract for list/set wrapper types.
216/// Avoids implicit deref-based access to inner collections.
217///
218
219pub trait Collection {
220    type Item;
221
222    /// Iterator over the collection's items, tied to the borrow of `self`.
223    type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
224    where
225        Self: 'a;
226
227    /// Returns an iterator over the collection's items.
228    fn iter(&self) -> Self::Iter<'_>;
229
230    /// Returns the number of items in the collection.
231    fn len(&self) -> usize;
232
233    /// Returns true if the collection contains no items.
234    fn is_empty(&self) -> bool {
235        self.len() == 0
236    }
237}
238
239///
240/// MapCollection
241///
242/// Explicit iteration contract for map wrapper types.
243/// Avoids implicit deref-based access to inner collections.
244///
245
246pub trait MapCollection {
247    type Key;
248    type Value;
249
250    /// Iterator over the map's key/value pairs, tied to the borrow of `self`.
251    type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
252    where
253        Self: 'a;
254
255    /// Returns an iterator over the map's key/value pairs.
256    fn iter(&self) -> Self::Iter<'_>;
257
258    /// Returns the number of entries in the map.
259    fn len(&self) -> usize;
260
261    /// Returns true if the map contains no entries.
262    fn is_empty(&self) -> bool {
263        self.len() == 0
264    }
265}
266
267pub trait EnumValue {
268    fn to_value_enum(&self) -> ValueEnum;
269}
270
271pub trait FieldValues {
272    fn get_value(&self, field: &str) -> Option<Value>;
273}
274
275///
276/// FieldValue
277///
278/// Conversion boundary for values used in query predicates.
279///
280/// Represents values that can appear on the *right-hand side* of predicates.
281///
282
283pub trait FieldValue {
284    fn to_value(&self) -> Value {
285        Value::Unsupported
286    }
287
288    #[must_use]
289    fn from_value(_value: &Value) -> Option<Self>
290    where
291        Self: Sized,
292    {
293        None
294    }
295}
296
297impl FieldValue for &str {
298    fn to_value(&self) -> Value {
299        Value::Text((*self).to_string())
300    }
301}
302
303impl FieldValue for String {
304    fn to_value(&self) -> Value {
305        Value::Text(self.clone())
306    }
307}
308
309impl<T: FieldValue> FieldValue for Option<T> {
310    fn to_value(&self) -> Value {
311        match self {
312            Some(v) => v.to_value(),
313            None => Value::None,
314        }
315    }
316}
317
318impl<T: FieldValue> FieldValue for Box<T> {
319    fn to_value(&self) -> Value {
320        (**self).to_value()
321    }
322}
323
324impl<T: FieldValue> FieldValue for Vec<Box<T>> {
325    fn to_value(&self) -> Value {
326        Value::List(self.iter().map(FieldValue::to_value).collect())
327    }
328}
329
330// impl_field_value
331#[macro_export]
332macro_rules! impl_field_value {
333    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
334        $(
335            impl FieldValue for $type {
336                fn to_value(&self) -> Value {
337                    Value::$variant((*self).into())
338                }
339
340                fn from_value(value: &Value) -> Option<Self> {
341                    match value {
342                        Value::$variant(v) => (*v).try_into().ok(),
343                        _ => None,
344                    }
345                }
346            }
347        )*
348    };
349}
350
351impl_field_value!(
352    i8 => Int,
353    i16 => Int,
354    i32 => Int,
355    i64 => Int,
356    u8 => Uint,
357    u16 => Uint,
358    u32 => Uint,
359    u64 => Uint,
360    bool => Bool,
361);
362
363/// ============================================================================
364/// MISC HELPERS
365/// ============================================================================
366
367///
368/// Inner
369///
370/// For newtypes to expose their innermost value.
371///
372pub trait Inner<T> {
373    fn inner(&self) -> &T;
374    fn into_inner(self) -> T;
375}
376
377// impl_inner
378#[macro_export]
379macro_rules! impl_inner {
380    ($($type:ty),*) => {
381        $(
382            impl Inner<$type> for $type {
383                fn inner(&self) -> &$type {
384                    &self
385                }
386                fn into_inner(self) -> $type {
387                    self
388                }
389            }
390        )*
391    };
392}
393
394impl_inner!(
395    bool, f32, f64, i8, i16, i32, i64, i128, String, u8, u16, u32, u64, u128
396);
397
398/// ============================================================================
399/// SANITIZATION / VALIDATION
400/// ============================================================================
401
402///
403/// Sanitizer
404///
405/// Transforms a value into a sanitized version.
406///
407pub trait Sanitizer<T> {
408    fn sanitize(&self, value: &mut T) -> Result<(), String>;
409}
410
411///
412/// Validator
413///
414/// Allows a node to validate values.
415///
416pub trait Validator<T: ?Sized> {
417    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
418}