1#[macro_use]
8mod macros;
9mod atomic;
10mod numeric_value;
11mod visitor;
12
13use crate::{
14 model::field::{FieldKind, FieldStorageDecode},
15 prelude::*,
16 types::{EntityTag, Id},
17 value::{Value, ValueEnum},
18 visitor::VisitorContext,
19};
20use std::collections::{BTreeMap, BTreeSet};
21
22pub use atomic::*;
23pub use numeric_value::*;
24pub use visitor::*;
25
26pub use canic_cdk::structures::storable::Storable;
31pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
32pub use std::{
33 cmp::{Eq, Ordering, PartialEq},
34 convert::From,
35 default::Default,
36 fmt::Debug,
37 hash::Hash,
38 ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign},
39};
40
41pub trait Path {
55 const PATH: &'static str;
56}
57
58pub trait Kind: Path + 'static {}
64impl<T> Kind for T where T: Path + 'static {}
65
66pub trait CanisterKind: Kind {
72 const COMMIT_MEMORY_ID: u8;
74}
75
76pub trait StoreKind: Kind {
82 type Canister: CanisterKind;
83}
84
85pub trait EntityKey {
107 type Key: Copy + Debug + Eq + Ord + FieldValue + EntityKeyBytes + 'static;
108}
109
110pub trait EntityKeyBytes {
115 const BYTE_LEN: usize;
117
118 fn write_bytes(&self, out: &mut [u8]);
120}
121
122macro_rules! impl_entity_key_bytes_numeric {
123 ($($ty:ty),* $(,)?) => {
124 $(
125 impl EntityKeyBytes for $ty {
126 const BYTE_LEN: usize = ::core::mem::size_of::<Self>();
127
128 fn write_bytes(&self, out: &mut [u8]) {
129 assert_eq!(out.len(), Self::BYTE_LEN);
130 out.copy_from_slice(&self.to_be_bytes());
131 }
132 }
133 )*
134 };
135}
136
137impl_entity_key_bytes_numeric!(i8, i16, i32, i64, u8, u16, u32, u64);
138
139impl EntityKeyBytes for () {
140 const BYTE_LEN: usize = 0;
141
142 fn write_bytes(&self, out: &mut [u8]) {
143 assert_eq!(out.len(), Self::BYTE_LEN);
144 }
145}
146
147pub trait EntitySchema: EntityKey {
158 const NAME: &'static str;
159 const MODEL: &'static EntityModel;
160}
161
162pub trait EntityPlacement {
176 type Store: StoreKind;
177 type Canister: CanisterKind;
178}
179
180pub trait EntityKind: EntitySchema + EntityPlacement + Kind + TypeKind {
190 const ENTITY_TAG: EntityTag;
191}
192
193pub trait EntityValue: EntityKey + FieldProjection + Sized {
211 fn id(&self) -> Id<Self>;
212}
213
214pub struct EntityCreateMaterialization<E> {
223 entity: E,
224 authored_slots: Vec<usize>,
225}
226
227impl<E> EntityCreateMaterialization<E> {
228 #[must_use]
230 pub const fn new(entity: E, authored_slots: Vec<usize>) -> Self {
231 Self {
232 entity,
233 authored_slots,
234 }
235 }
236
237 #[must_use]
239 pub fn into_entity(self) -> E {
240 self.entity
241 }
242
243 #[must_use]
245 pub const fn authored_slots(&self) -> &[usize] {
246 self.authored_slots.as_slice()
247 }
248}
249
250pub trait EntityCreateInput: Sized {
259 type Entity: EntityValue + Default;
260
261 fn materialize_create(self) -> EntityCreateMaterialization<Self::Entity>;
263}
264
265pub trait EntityCreateType: EntityValue {
275 type Create: EntityCreateInput<Entity = Self>;
276}
277
278pub trait SingletonEntity: EntityValue {}
280
281pub trait TypeKind:
299 Kind + Clone + Default + DeserializeOwned + Sanitize + Validate + Visitable + PartialEq
300{
301}
302
303impl<T> TypeKind for T where
304 T: Kind + Clone + Default + DeserializeOwned + PartialEq + Sanitize + Validate + Visitable
305{
306}
307
308pub trait FieldTypeMeta {
317 const KIND: FieldKind;
319
320 const STORAGE_DECODE: FieldStorageDecode;
322}
323
324impl<T> FieldTypeMeta for Option<T>
325where
326 T: FieldTypeMeta,
327{
328 const KIND: FieldKind = T::KIND;
329 const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
330}
331
332impl<T> FieldTypeMeta for Box<T>
333where
334 T: FieldTypeMeta,
335{
336 const KIND: FieldKind = T::KIND;
337 const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
338}
339
340impl<T> FieldTypeMeta for Vec<T>
344where
345 T: FieldTypeMeta,
346{
347 const KIND: FieldKind = FieldKind::List(&T::KIND);
348 const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
349}
350
351impl<T> FieldTypeMeta for BTreeSet<T>
352where
353 T: FieldTypeMeta,
354{
355 const KIND: FieldKind = FieldKind::Set(&T::KIND);
356 const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
357}
358
359impl<K, V> FieldTypeMeta for BTreeMap<K, V>
360where
361 K: FieldTypeMeta,
362 V: FieldTypeMeta,
363{
364 const KIND: FieldKind = FieldKind::Map {
365 key: &K::KIND,
366 value: &V::KIND,
367 };
368 const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
369}
370
371pub trait Collection {
384 type Item;
385
386 type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
388 where
389 Self: 'a;
390
391 fn iter(&self) -> Self::Iter<'_>;
393
394 fn len(&self) -> usize;
396
397 fn is_empty(&self) -> bool {
399 self.len() == 0
400 }
401}
402
403pub trait MapCollection {
412 type Key;
413 type Value;
414
415 type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
417 where
418 Self: 'a;
419
420 fn iter(&self) -> Self::Iter<'_>;
422
423 fn len(&self) -> usize;
425
426 fn is_empty(&self) -> bool {
428 self.len() == 0
429 }
430}
431
432pub trait EnumValue {
433 fn to_value_enum(&self) -> ValueEnum;
434}
435
436pub trait FieldProjection {
437 fn get_value_by_index(&self, index: usize) -> Option<Value>;
439}
440
441#[derive(Clone, Copy, Debug, Eq, PartialEq)]
449pub enum FieldValueKind {
450 Atomic,
452
453 Structured {
456 queryable: bool,
458 },
459}
460
461impl FieldValueKind {
462 #[must_use]
463 pub const fn is_queryable(self) -> bool {
464 match self {
465 Self::Atomic => true,
466 Self::Structured { queryable } => queryable,
467 }
468 }
469}
470
471pub trait FieldValue {
479 fn kind() -> FieldValueKind
480 where
481 Self: Sized;
482
483 fn to_value(&self) -> Value;
484
485 #[must_use]
486 fn from_value(value: &Value) -> Option<Self>
487 where
488 Self: Sized;
489}
490
491pub fn field_value_collection_to_value<C>(collection: &C) -> Value
500where
501 C: Collection,
502 C::Item: FieldValue,
503{
504 Value::List(collection.iter().map(FieldValue::to_value).collect())
505}
506
507#[must_use]
516pub fn field_value_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
517where
518 T: FieldValue,
519{
520 let Value::List(values) = value else {
521 return None;
522 };
523
524 let mut out = Vec::with_capacity(values.len());
525 for value in values {
526 out.push(T::from_value(value)?);
527 }
528
529 Some(out)
530}
531
532#[must_use]
541pub fn field_value_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
542where
543 T: FieldValue + Ord,
544{
545 let Value::List(values) = value else {
546 return None;
547 };
548
549 let mut out = BTreeSet::new();
550 for value in values {
551 let item = T::from_value(value)?;
552 if !out.insert(item) {
553 return None;
554 }
555 }
556
557 Some(out)
558}
559
560pub fn field_value_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
570where
571 M: MapCollection,
572 M::Key: FieldValue,
573 M::Value: FieldValue,
574{
575 let mut entries: Vec<(Value, Value)> = map
576 .iter()
577 .map(|(key, value)| (FieldValue::to_value(key), FieldValue::to_value(value)))
578 .collect();
579
580 if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
581 debug_assert!(false, "invalid map field value for {path}: {err}");
582 return Value::Map(entries);
583 }
584
585 Value::sort_map_entries_in_place(entries.as_mut_slice());
586
587 for i in 1..entries.len() {
588 let (left_key, _) = &entries[i - 1];
589 let (right_key, _) = &entries[i];
590 if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
591 debug_assert!(
592 false,
593 "duplicate map key in {path} after FieldValue::to_value canonicalization",
594 );
595 break;
596 }
597 }
598
599 Value::Map(entries)
600}
601
602#[must_use]
611pub fn field_value_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
612where
613 K: FieldValue + Ord,
614 V: FieldValue,
615{
616 let Value::Map(entries) = value else {
617 return None;
618 };
619
620 let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
621 if normalized.as_slice() != entries.as_slice() {
622 return None;
623 }
624
625 let mut map = BTreeMap::new();
626 for (entry_key, entry_value) in normalized {
627 let key = K::from_value(&entry_key)?;
628 let value = V::from_value(&entry_value)?;
629 map.insert(key, value);
630 }
631
632 Some(map)
633}
634
635#[must_use]
644pub fn field_value_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
645where
646 I: Into<T>,
647{
648 entries.into_iter().map(Into::into).collect()
649}
650
651#[must_use]
660pub fn field_value_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
661where
662 I: Into<T>,
663 T: Ord,
664{
665 entries.into_iter().map(Into::into).collect()
666}
667
668#[must_use]
677pub fn field_value_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
678where
679 IK: Into<K>,
680 IV: Into<V>,
681 K: Ord,
682{
683 entries
684 .into_iter()
685 .map(|(key, value)| (key.into(), value.into()))
686 .collect()
687}
688
689#[must_use]
698pub fn field_value_into<T, U>(value: U) -> T
699where
700 U: Into<T>,
701{
702 value.into()
703}
704
705impl FieldValue for &str {
706 fn kind() -> FieldValueKind {
707 FieldValueKind::Atomic
708 }
709
710 fn to_value(&self) -> Value {
711 Value::Text((*self).to_string())
712 }
713
714 fn from_value(_value: &Value) -> Option<Self> {
715 None
716 }
717}
718
719impl FieldValue for String {
720 fn kind() -> FieldValueKind {
721 FieldValueKind::Atomic
722 }
723
724 fn to_value(&self) -> Value {
725 Value::Text(self.clone())
726 }
727
728 fn from_value(value: &Value) -> Option<Self> {
729 match value {
730 Value::Text(v) => Some(v.clone()),
731 _ => None,
732 }
733 }
734}
735
736impl<T: FieldValue> FieldValue for Option<T> {
737 fn kind() -> FieldValueKind {
738 T::kind()
739 }
740
741 fn to_value(&self) -> Value {
742 match self {
743 Some(v) => v.to_value(),
744 None => Value::Null,
745 }
746 }
747
748 fn from_value(value: &Value) -> Option<Self> {
749 if matches!(value, Value::Null) {
750 return Some(None);
751 }
752
753 T::from_value(value).map(Some)
754 }
755}
756
757impl<T: FieldValue> FieldValue for Box<T> {
758 fn kind() -> FieldValueKind {
759 T::kind()
760 }
761
762 fn to_value(&self) -> Value {
763 (**self).to_value()
764 }
765
766 fn from_value(value: &Value) -> Option<Self> {
767 T::from_value(value).map(Self::new)
768 }
769}
770
771impl<T: FieldValue> FieldValue for Vec<T> {
772 fn kind() -> FieldValueKind {
773 FieldValueKind::Structured { queryable: true }
774 }
775
776 fn to_value(&self) -> Value {
777 Value::List(self.iter().map(FieldValue::to_value).collect())
778 }
779
780 fn from_value(value: &Value) -> Option<Self> {
781 field_value_vec_from_value(value)
782 }
783}
784
785impl<T> FieldValue for BTreeSet<T>
786where
787 T: FieldValue + Ord,
788{
789 fn kind() -> FieldValueKind {
790 FieldValueKind::Structured { queryable: true }
791 }
792
793 fn to_value(&self) -> Value {
794 Value::List(self.iter().map(FieldValue::to_value).collect())
795 }
796
797 fn from_value(value: &Value) -> Option<Self> {
798 field_value_btree_set_from_value(value)
799 }
800}
801
802impl<K, V> FieldValue for BTreeMap<K, V>
803where
804 K: FieldValue + Ord,
805 V: FieldValue,
806{
807 fn kind() -> FieldValueKind {
808 FieldValueKind::Structured { queryable: true }
809 }
810
811 fn to_value(&self) -> Value {
812 let mut entries: Vec<(Value, Value)> = self
813 .iter()
814 .map(|(key, value)| (FieldValue::to_value(key), FieldValue::to_value(value)))
815 .collect();
816
817 if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
818 debug_assert!(
819 false,
820 "invalid map field value for {}: {err}",
821 std::any::type_name::<Self>()
822 );
823 return Value::Map(entries);
824 }
825
826 Value::sort_map_entries_in_place(entries.as_mut_slice());
827 Value::Map(entries)
828 }
829
830 fn from_value(value: &Value) -> Option<Self> {
831 field_value_btree_map_from_value(value)
832 }
833}
834
835#[macro_export]
837macro_rules! impl_field_value {
838 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
839 $(
840 impl FieldValue for $type {
841 fn kind() -> FieldValueKind {
842 FieldValueKind::Atomic
843 }
844
845 fn to_value(&self) -> Value {
846 Value::$variant((*self).into())
847 }
848
849 fn from_value(value: &Value) -> Option<Self> {
850 match value {
851 Value::$variant(v) => (*v).try_into().ok(),
852 _ => None,
853 }
854 }
855 }
856 )*
857 };
858}
859
860impl_field_value!(
861 i8 => Int,
862 i16 => Int,
863 i32 => Int,
864 i64 => Int,
865 u8 => Uint,
866 u16 => Uint,
867 u32 => Uint,
868 u64 => Uint,
869 bool => Bool,
870);
871
872pub trait Inner<T> {
883 fn inner(&self) -> &T;
884 fn into_inner(self) -> T;
885}
886
887impl<T> Inner<T> for T
888where
889 T: Atomic,
890{
891 fn inner(&self) -> &T {
892 self
893 }
894
895 fn into_inner(self) -> T {
896 self
897 }
898}
899
900pub trait Repr {
907 type Inner;
908
909 fn repr(&self) -> Self::Inner;
910 fn from_repr(inner: Self::Inner) -> Self;
911}
912
913pub trait Sanitizer<T> {
924 fn sanitize(&self, value: &mut T) -> Result<(), String>;
925
926 fn sanitize_with_context(
927 &self,
928 value: &mut T,
929 ctx: &mut dyn VisitorContext,
930 ) -> Result<(), String> {
931 let _ = ctx;
932
933 self.sanitize(value)
934 }
935}
936
937pub trait Validator<T: ?Sized> {
944 fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
945}