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