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// 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::{prelude::*, types::Unit, value::ValueEnum, visitor::VisitorContext};
26
27/// ------------------------
28/// KIND TRAITS
29/// the Schema uses the term "Node" but when they're built it's "Kind"
30/// ------------------------
31
32///
33/// Kind
34///
35
36pub trait Kind: Path + 'static {}
37
38impl<T> Kind for T where T: Path + 'static {}
39
40///
41/// CanisterKind
42///
43
44pub trait CanisterKind: Kind {}
45
46///
47/// DataStoreKind
48///
49
50pub trait DataStoreKind: Kind {
51    type Canister: CanisterKind;
52}
53
54///
55/// EntityKind
56///
57
58pub trait EntityKind: Kind + TypeKind + FieldValues {
59    type PrimaryKey: Copy + Into<Key>;
60    type DataStore: DataStoreKind;
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    const MODEL: &'static crate::model::entity::EntityModel;
68
69    fn key(&self) -> Key;
70    fn primary_key(&self) -> Self::PrimaryKey;
71    fn set_primary_key(&mut self, key: Self::PrimaryKey);
72}
73
74///
75/// IndexStoreKind
76///
77
78pub trait IndexStoreKind: Kind {
79    type Canister: CanisterKind;
80}
81
82///
83/// UnitKey
84/// Marker trait for unit-valued primary keys used by singleton entities.
85///
86
87pub trait UnitKey: Copy + Into<Key> + unit_key::Sealed {}
88
89impl UnitKey for () {}
90impl UnitKey for Unit {}
91
92mod unit_key {
93    use crate::types::Unit;
94
95    // Seal UnitKey so only unit-equivalent key types can implement it.
96    pub trait Sealed {}
97
98    impl Sealed for () {}
99    impl Sealed for Unit {}
100}
101
102/// ------------------------
103/// TYPE TRAITS
104/// ------------------------
105
106///
107/// TypeKind
108/// any data type
109///
110
111pub trait TypeKind:
112    Kind
113    + View
114    + Clone
115    + Default
116    + Serialize
117    + DeserializeOwned
118    + Sanitize
119    + Validate
120    + Visitable
121    + PartialEq
122{
123}
124
125impl<T> TypeKind for T where
126    T: Kind
127        + View
128        + Clone
129        + Default
130        + DeserializeOwned
131        + PartialEq
132        + Serialize
133        + Sanitize
134        + Validate
135        + Visitable
136{
137}
138
139/// ------------------------
140/// OTHER TRAITS
141/// ------------------------
142
143///
144/// FieldValues
145///
146
147pub trait FieldValues {
148    fn get_value(&self, field: &str) -> Option<Value>;
149}
150
151///
152/// FieldValue
153///
154/// Conversion boundary for values used in query predicates.
155///
156/// `FieldValue` represents any value that can appear on the *right-hand side*
157/// of a predicate (e.g. `field == value`, `field IN values`). Implementations
158/// convert Rust values into owned [`Value`] instances that are stored inside
159/// query plans and executed later.
160///
161
162pub trait FieldValue {
163    fn to_value(&self) -> Value {
164        Value::Unsupported
165    }
166}
167
168///
169/// EnumValue
170/// Explicit conversion boundary for domain enums used in query values.
171///
172
173pub trait EnumValue {
174    /// Convert this enum into a strict [`ValueEnum`] with its canonical path.
175    fn to_value_enum(&self) -> ValueEnum;
176}
177
178impl FieldValue for &str {
179    fn to_value(&self) -> Value {
180        Value::Text((*self).to_string())
181    }
182}
183
184impl FieldValue for String {
185    fn to_value(&self) -> Value {
186        Value::Text(self.clone())
187    }
188}
189
190impl<T> FieldValue for &'_ T
191where
192    T: FieldValue + Copy,
193{
194    fn to_value(&self) -> Value {
195        (*self).to_value()
196    }
197}
198
199impl<T: FieldValue> FieldValue for Option<T> {
200    fn to_value(&self) -> Value {
201        match self {
202            Some(v) => v.to_value(),
203            None => Value::None,
204        }
205    }
206}
207
208impl<T: FieldValue> FieldValue for Vec<T> {
209    fn to_value(&self) -> Value {
210        Value::List(self.iter().map(FieldValue::to_value).collect())
211    }
212}
213
214impl<T: FieldValue> FieldValue for Box<T> {
215    fn to_value(&self) -> Value {
216        (**self).to_value()
217    }
218}
219
220// impl_field_value
221#[macro_export]
222macro_rules! impl_field_value {
223    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
224        $(
225            impl FieldValue for $type {
226                fn to_value(&self) -> Value {
227                    Value::$variant((*self).into())
228                }
229            }
230        )*
231    };
232}
233
234impl_field_value!(
235    i8 => Int,
236    i16 => Int,
237    i32 => Int,
238    i64 => Int,
239    u8 => Uint,
240    u16 => Uint,
241    u32 => Uint,
242    u64 => Uint,
243    bool => Bool,
244);
245
246///
247/// Inner
248/// for Newtypes to get the innermost value
249///
250/// DO NOT REMOVE - its been added and removed twice already, NumCast
251/// is a pain to use and won't work for half our types
252///
253
254pub trait Inner<T> {
255    fn inner(&self) -> &T;
256    fn into_inner(self) -> T;
257}
258
259// impl_inner
260#[macro_export]
261macro_rules! impl_inner {
262    ($($type:ty),*) => {
263        $(
264            impl Inner<$type> for $type {
265                fn inner(&self) -> &$type {
266                    &self
267                }
268                fn into_inner(self) -> $type {
269                    self
270                }
271            }
272        )*
273    };
274}
275
276impl_inner!(
277    bool, f32, f64, i8, i16, i32, i64, i128, String, u8, u16, u32, u64, u128
278);
279
280///
281/// Path
282///
283/// any node created via a macro has a Path
284/// ie. design::game::rarity::Rarity
285///
286
287pub trait Path {
288    const PATH: &'static str;
289}
290
291///
292/// Sanitizer
293/// transforms a value into a sanitized version
294///
295
296pub trait Sanitizer<T> {
297    /// Apply in-place sanitization.
298    ///
299    /// - `Ok(())` means success (possibly with issues recorded by the caller)
300    /// - `Err(String)` means a fatal sanitization failure
301    fn sanitize(&self, value: &mut T) -> Result<(), String>;
302}
303
304///
305/// Validator
306/// allows a node to validate different types of primitives
307/// ?Sized so we can operate on str
308///
309
310pub trait Validator<T: ?Sized> {
311    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
312}