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::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 {
480 fn kind() -> FieldValueKind
481 where
482 Self: Sized;
483
484 fn to_value(&self) -> Value;
485
486 #[must_use]
487 fn from_value(value: &Value) -> Option<Self>
488 where
489 Self: Sized;
490}
491
492pub fn field_value_collection_to_value<C>(collection: &C) -> Value
501where
502 C: Collection,
503 C::Item: FieldValue,
504{
505 Value::List(collection.iter().map(FieldValue::to_value).collect())
506}
507
508#[must_use]
517pub fn field_value_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
518where
519 T: FieldValue,
520{
521 let Value::List(values) = value else {
522 return None;
523 };
524
525 let mut out = Vec::with_capacity(values.len());
526 for value in values {
527 out.push(T::from_value(value)?);
528 }
529
530 Some(out)
531}
532
533#[must_use]
542pub fn field_value_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
543where
544 T: FieldValue + Ord,
545{
546 let Value::List(values) = value else {
547 return None;
548 };
549
550 let mut out = BTreeSet::new();
551 for value in values {
552 let item = T::from_value(value)?;
553 if !out.insert(item) {
554 return None;
555 }
556 }
557
558 Some(out)
559}
560
561pub fn field_value_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
571where
572 M: MapCollection,
573 M::Key: FieldValue,
574 M::Value: FieldValue,
575{
576 let mut entries: Vec<(Value, Value)> = map
577 .iter()
578 .map(|(key, value)| (FieldValue::to_value(key), FieldValue::to_value(value)))
579 .collect();
580
581 if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
582 debug_assert!(false, "invalid map field value for {path}: {err}");
583 return Value::Map(entries);
584 }
585
586 Value::sort_map_entries_in_place(entries.as_mut_slice());
587
588 for i in 1..entries.len() {
589 let (left_key, _) = &entries[i - 1];
590 let (right_key, _) = &entries[i];
591 if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
592 debug_assert!(
593 false,
594 "duplicate map key in {path} after FieldValue::to_value canonicalization",
595 );
596 break;
597 }
598 }
599
600 Value::Map(entries)
601}
602
603#[must_use]
612pub fn field_value_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
613where
614 K: FieldValue + Ord,
615 V: FieldValue,
616{
617 let Value::Map(entries) = value else {
618 return None;
619 };
620
621 let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
622 if normalized.as_slice() != entries.as_slice() {
623 return None;
624 }
625
626 let mut map = BTreeMap::new();
627 for (entry_key, entry_value) in normalized {
628 let key = K::from_value(&entry_key)?;
629 let value = V::from_value(&entry_value)?;
630 map.insert(key, value);
631 }
632
633 Some(map)
634}
635
636#[must_use]
645pub fn field_value_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
646where
647 I: Into<T>,
648{
649 entries.into_iter().map(Into::into).collect()
650}
651
652#[must_use]
661pub fn field_value_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
662where
663 I: Into<T>,
664 T: Ord,
665{
666 entries.into_iter().map(Into::into).collect()
667}
668
669#[must_use]
678pub fn field_value_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
679where
680 IK: Into<K>,
681 IV: Into<V>,
682 K: Ord,
683{
684 entries
685 .into_iter()
686 .map(|(key, value)| (key.into(), value.into()))
687 .collect()
688}
689
690#[must_use]
699pub fn field_value_into<T, U>(value: U) -> T
700where
701 U: Into<T>,
702{
703 value.into()
704}
705
706impl FieldValue for &str {
707 fn kind() -> FieldValueKind {
708 FieldValueKind::Atomic
709 }
710
711 fn to_value(&self) -> Value {
712 Value::Text((*self).to_string())
713 }
714
715 fn from_value(_value: &Value) -> Option<Self> {
716 None
717 }
718}
719
720impl FieldValue for String {
721 fn kind() -> FieldValueKind {
722 FieldValueKind::Atomic
723 }
724
725 fn to_value(&self) -> Value {
726 Value::Text(self.clone())
727 }
728
729 fn from_value(value: &Value) -> Option<Self> {
730 match value {
731 Value::Text(v) => Some(v.clone()),
732 _ => None,
733 }
734 }
735}
736
737impl<T: FieldValue> FieldValue for Option<T> {
738 fn kind() -> FieldValueKind {
739 T::kind()
740 }
741
742 fn to_value(&self) -> Value {
743 match self {
744 Some(v) => v.to_value(),
745 None => Value::Null,
746 }
747 }
748
749 fn from_value(value: &Value) -> Option<Self> {
750 if matches!(value, Value::Null) {
751 return Some(None);
752 }
753
754 T::from_value(value).map(Some)
755 }
756}
757
758impl<T: FieldValue> FieldValue for Box<T> {
759 fn kind() -> FieldValueKind {
760 T::kind()
761 }
762
763 fn to_value(&self) -> Value {
764 (**self).to_value()
765 }
766
767 fn from_value(value: &Value) -> Option<Self> {
768 T::from_value(value).map(Self::new)
769 }
770}
771
772impl<T: FieldValue> FieldValue for Vec<T> {
773 fn kind() -> FieldValueKind {
774 FieldValueKind::Structured { queryable: true }
775 }
776
777 fn to_value(&self) -> Value {
778 Value::List(self.iter().map(FieldValue::to_value).collect())
779 }
780
781 fn from_value(value: &Value) -> Option<Self> {
782 field_value_vec_from_value(value)
783 }
784}
785
786impl<T> FieldValue for BTreeSet<T>
787where
788 T: FieldValue + Ord,
789{
790 fn kind() -> FieldValueKind {
791 FieldValueKind::Structured { queryable: true }
792 }
793
794 fn to_value(&self) -> Value {
795 Value::List(self.iter().map(FieldValue::to_value).collect())
796 }
797
798 fn from_value(value: &Value) -> Option<Self> {
799 field_value_btree_set_from_value(value)
800 }
801}
802
803impl<K, V> FieldValue for BTreeMap<K, V>
804where
805 K: FieldValue + Ord,
806 V: FieldValue,
807{
808 fn kind() -> FieldValueKind {
809 FieldValueKind::Structured { queryable: true }
810 }
811
812 fn to_value(&self) -> Value {
813 let mut entries: Vec<(Value, Value)> = self
814 .iter()
815 .map(|(key, value)| (FieldValue::to_value(key), FieldValue::to_value(value)))
816 .collect();
817
818 if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
819 debug_assert!(
820 false,
821 "invalid map field value for {}: {err}",
822 std::any::type_name::<Self>()
823 );
824 return Value::Map(entries);
825 }
826
827 Value::sort_map_entries_in_place(entries.as_mut_slice());
828 Value::Map(entries)
829 }
830
831 fn from_value(value: &Value) -> Option<Self> {
832 field_value_btree_map_from_value(value)
833 }
834}
835
836#[macro_export]
838macro_rules! impl_field_value {
839 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
840 $(
841 impl FieldValue for $type {
842 fn kind() -> FieldValueKind {
843 FieldValueKind::Atomic
844 }
845
846 fn to_value(&self) -> Value {
847 Value::$variant((*self).into())
848 }
849
850 fn from_value(value: &Value) -> Option<Self> {
851 match value {
852 Value::$variant(v) => (*v).try_into().ok(),
853 _ => None,
854 }
855 }
856 }
857 )*
858 };
859}
860
861impl_field_value!(
862 i8 => Int,
863 i16 => Int,
864 i32 => Int,
865 i64 => Int,
866 u8 => Uint,
867 u16 => Uint,
868 u32 => Uint,
869 u64 => Uint,
870 bool => Bool,
871);
872
873pub trait Inner<T> {
884 fn inner(&self) -> &T;
885 fn into_inner(self) -> T;
886}
887
888impl<T> Inner<T> for T
889where
890 T: Atomic,
891{
892 fn inner(&self) -> &T {
893 self
894 }
895
896 fn into_inner(self) -> T {
897 self
898 }
899}
900
901pub trait Repr {
908 type Inner;
909
910 fn repr(&self) -> Self::Inner;
911 fn from_repr(inner: Self::Inner) -> Self;
912}
913
914pub trait Sanitizer<T> {
925 fn sanitize(&self, value: &mut T) -> Result<(), String>;
926
927 fn sanitize_with_context(
928 &self,
929 value: &mut T,
930 ctx: &mut dyn VisitorContext,
931 ) -> Result<(), String> {
932 let _ = ctx;
933
934 self.sanitize(value)
935 }
936}
937
938pub trait Validator<T: ?Sized> {
945 fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
946}