icydb_core/traits/
mod.rs

1#[macro_use]
2mod macros;
3mod view;
4mod visitor;
5
6pub use view::*;
7pub use visitor::*;
8
9// re-exports of other traits
10// for the standard traits::X pattern
11pub use canic_cdk::structures::storable::Storable;
12pub use num_traits::{FromPrimitive as NumFromPrimitive, NumCast, ToPrimitive as NumToPrimitive};
13pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
14pub use std::{
15    cmp::{Eq, Ordering, PartialEq},
16    convert::{AsRef, From, Into},
17    default::Default,
18    fmt::{Debug, Display},
19    hash::Hash,
20    iter::IntoIterator,
21    ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Sub, SubAssign},
22    str::FromStr,
23};
24
25use crate::{
26    db::primitives::{
27        BoolEqualityFilterKind, BoolListFilterKind, FilterKind, Int64RangeFilterKind,
28        IntListFilterKind, Nat64RangeFilterKind, NatListFilterKind, TextFilterKind,
29        TextListFilterKind,
30    },
31    prelude::*,
32    visitor::VisitorContext,
33};
34
35/// ------------------------
36/// KIND TRAITS
37/// the Schema uses the term "Node" but when they're built it's "Kind"
38/// ------------------------
39
40///
41/// Kind
42///
43
44pub trait Kind: Path + 'static {}
45
46impl<T> Kind for T where T: Path + 'static {}
47
48///
49/// CanisterKind
50///
51
52pub trait CanisterKind: Kind {}
53
54///
55/// EntityKind
56///
57
58pub trait EntityKind: Kind + TypeKind + FieldValues {
59    type PrimaryKey: Copy + Into<Key>;
60    type Store: StoreKind;
61    type Canister: CanisterKind; // Self::Store::Canister shortcut
62
63    const ENTITY_NAME: &'static str;
64    const PRIMARY_KEY: &'static str;
65    const FIELDS: &'static [&'static str];
66    const INDEXES: &'static [&'static IndexModel];
67
68    fn key(&self) -> Key;
69    fn primary_key(&self) -> Self::PrimaryKey;
70    fn set_primary_key(&mut self, key: Self::PrimaryKey);
71}
72
73///
74/// StoreKind
75///
76
77pub trait StoreKind: Kind {
78    type Canister: CanisterKind;
79}
80
81/// ------------------------
82/// TYPE TRAITS
83/// ------------------------
84
85///
86/// TypeKind
87/// any data type
88///
89
90pub trait TypeKind:
91    Kind
92    + View
93    + Clone
94    + Default
95    + Serialize
96    + DeserializeOwned
97    + Sanitize
98    + Validate
99    + Visitable
100    + PartialEq
101{
102}
103
104impl<T> TypeKind for T where
105    T: Kind
106        + View
107        + Clone
108        + Default
109        + DeserializeOwned
110        + PartialEq
111        + Serialize
112        + Sanitize
113        + Validate
114        + Visitable
115{
116}
117
118/// ------------------------
119/// OTHER TRAITS
120/// ------------------------
121
122///
123/// FieldValues
124///
125
126pub trait FieldValues {
127    fn get_value(&self, field: &str) -> Option<Value>;
128}
129
130///
131/// FieldValue
132///
133
134pub trait FieldValue {
135    fn to_value(&self) -> Value {
136        Value::Unsupported
137    }
138}
139
140impl FieldValue for &str {
141    fn to_value(&self) -> Value {
142        Value::Text((*self).to_string())
143    }
144}
145
146impl FieldValue for String {
147    fn to_value(&self) -> Value {
148        Value::Text(self.clone())
149    }
150}
151
152impl<T: FieldValue + Clone> FieldValue for &T {
153    fn to_value(&self) -> Value {
154        (*self).clone().to_value()
155    }
156}
157
158impl<T: FieldValue> FieldValue for Option<T> {
159    fn to_value(&self) -> Value {
160        match self {
161            Some(v) => v.to_value(),
162            None => Value::None,
163        }
164    }
165}
166
167impl<T: FieldValue> FieldValue for Vec<T> {
168    fn to_value(&self) -> Value {
169        Value::List(self.iter().map(FieldValue::to_value).collect())
170    }
171}
172
173impl<T: FieldValue> FieldValue for Box<T> {
174    fn to_value(&self) -> Value {
175        (**self).to_value()
176    }
177}
178
179// impl_field_value
180#[macro_export]
181macro_rules! impl_field_value {
182    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
183        $(
184            impl FieldValue for $type {
185                fn to_value(&self) -> Value {
186                    Value::$variant((*self).into())
187                }
188            }
189        )*
190    };
191}
192
193impl_field_value!(
194    i8 => Int,
195    i16 => Int,
196    i32 => Int,
197    i64 => Int,
198    u8 => Uint,
199    u16 => Uint,
200    u32 => Uint,
201    u64 => Uint,
202    bool => Bool,
203);
204
205///
206/// Filterable
207///
208
209pub trait Filterable {
210    type Filter: FilterKind;
211    type ListFilter: FilterKind;
212}
213
214macro_rules! impl_filterable {
215    // Case 1: type => scalar_filter, list_filter
216    ( $( $type:ty => $filter:path, $list_filter:path );* $(;)? ) => {
217        $(
218            impl Filterable for $type {
219                type Filter = $filter;
220                type ListFilter = $list_filter;
221            }
222        )*
223    };
224}
225
226impl_filterable! {
227    bool    => BoolEqualityFilterKind, BoolListFilterKind;
228    i8      => Int64RangeFilterKind, IntListFilterKind;
229    i16     => Int64RangeFilterKind, IntListFilterKind;
230    i32     => Int64RangeFilterKind, IntListFilterKind;
231    i64     => Int64RangeFilterKind, IntListFilterKind;
232
233    u8      => Nat64RangeFilterKind, NatListFilterKind;
234    u16     => Nat64RangeFilterKind, NatListFilterKind;
235    u32     => Nat64RangeFilterKind, NatListFilterKind;
236    u64     => Nat64RangeFilterKind, NatListFilterKind;
237
238    String  => TextFilterKind, TextListFilterKind;
239}
240
241///
242/// FromKey
243/// Convert a stored [`Key`] into a concrete type.
244/// Returns `None` if the key cannot represent this type.
245///
246
247pub trait FromKey: Copy {
248    fn try_from_key(key: Key) -> Option<Self>;
249}
250
251#[macro_export]
252macro_rules! impl_from_key_int {
253    ( $( $ty:ty ),* $(,)? ) => {
254        $(
255            impl FromKey for $ty {
256                fn try_from_key(key: Key) -> Option<Self> {
257                    match key {
258                        Key::Int(v) => Self::try_from(v).ok(),
259                        _ => None,
260                    }
261                }
262            }
263        )*
264    };
265}
266
267#[macro_export]
268macro_rules! impl_from_key_uint {
269    ( $( $ty:ty ),* $(,)? ) => {
270        $(
271            impl FromKey for $ty {
272                fn try_from_key(key: Key) -> Option<Self> {
273                    match key {
274                        Key::Uint(v) => Self::try_from(v).ok(),
275                        _ => None,
276                    }
277                }
278            }
279        )*
280    };
281}
282
283impl_from_key_int!(i8, i16, i32, i64);
284impl_from_key_uint!(u8, u16, u32, u64);
285
286///
287/// Inner
288/// for Newtypes to get the innermost value
289///
290/// DO NOT REMOVE - its been added and removed twice already, NumCast
291/// is a pain to use and won't work for half our types
292///
293
294pub trait Inner<T> {
295    fn inner(&self) -> &T;
296    fn into_inner(self) -> T;
297}
298
299// impl_inner
300#[macro_export]
301macro_rules! impl_inner {
302    ($($type:ty),*) => {
303        $(
304            impl Inner<$type> for $type {
305                fn inner(&self) -> &$type {
306                    &self
307                }
308                fn into_inner(self) -> $type {
309                    self
310                }
311            }
312        )*
313    };
314}
315
316impl_inner!(
317    bool, f32, f64, i8, i16, i32, i64, i128, String, u8, u16, u32, u64, u128
318);
319
320///
321/// Path
322///
323/// any node created via a macro has a Path
324/// ie. design::game::rarity::Rarity
325///
326
327pub trait Path {
328    const PATH: &'static str;
329}
330
331///
332/// Sanitizer
333/// transforms a value into a sanitized version
334///
335
336pub trait Sanitizer<T> {
337    /// Apply in-place sanitization.
338    ///
339    /// - `Ok(())` means success (possibly with issues recorded by the caller)
340    /// - `Err(String)` means a fatal sanitization failure
341    fn sanitize(&self, value: &mut T) -> Result<(), String>;
342}
343
344///
345/// Validator
346/// allows a node to validate different types of primitives
347/// ?Sized so we can operate on str
348///
349
350pub trait Validator<T: ?Sized> {
351    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
352}