1#[macro_use]
8mod macros;
9mod atomic;
10mod numeric_value;
11mod visitor;
12
13use crate::{
14 error::InternalError,
15 model::field::{FieldKind, FieldStorageDecode},
16 prelude::*,
17 types::{EntityTag, Id},
18 value::{Value, ValueEnum},
19 visitor::VisitorContext,
20};
21use std::collections::{BTreeMap, BTreeSet};
22
23pub use atomic::*;
24pub use numeric_value::*;
25pub use visitor::*;
26
27pub use canic_cdk::structures::storable::Storable;
32pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
33pub use std::{
34 cmp::{Eq, Ordering, PartialEq},
35 convert::From,
36 default::Default,
37 fmt::Debug,
38 hash::Hash,
39 ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign},
40};
41
42pub trait Path {
56 const PATH: &'static str;
57}
58
59pub trait Kind: Path + 'static {}
65impl<T> Kind for T where T: Path + 'static {}
66
67pub trait CanisterKind: Kind {
73 const COMMIT_MEMORY_ID: u8;
75}
76
77pub trait StoreKind: Kind {
83 type Canister: CanisterKind;
84}
85
86pub trait EntityKey {
108 type Key: Copy + Debug + Eq + Ord + KeyValueCodec + EntityKeyBytes + 'static;
109}
110
111pub trait EntityKeyBytes {
116 const BYTE_LEN: usize;
118
119 fn write_bytes(&self, out: &mut [u8]);
121}
122
123macro_rules! impl_entity_key_bytes_numeric {
124 ($($ty:ty),* $(,)?) => {
125 $(
126 impl EntityKeyBytes for $ty {
127 const BYTE_LEN: usize = ::core::mem::size_of::<Self>();
128
129 fn write_bytes(&self, out: &mut [u8]) {
130 assert_eq!(out.len(), Self::BYTE_LEN);
131 out.copy_from_slice(&self.to_be_bytes());
132 }
133 }
134 )*
135 };
136}
137
138impl_entity_key_bytes_numeric!(i8, i16, i32, i64, u8, u16, u32, u64);
139
140impl EntityKeyBytes for () {
141 const BYTE_LEN: usize = 0;
142
143 fn write_bytes(&self, out: &mut [u8]) {
144 assert_eq!(out.len(), Self::BYTE_LEN);
145 }
146}
147
148pub trait KeyValueCodec {
158 fn to_key_value(&self) -> Value;
159
160 #[must_use]
161 fn from_key_value(value: &Value) -> Option<Self>
162 where
163 Self: Sized;
164}
165
166impl<T> KeyValueCodec for T
167where
168 T: ValueCodec,
169{
170 fn to_key_value(&self) -> Value {
171 self.to_value()
172 }
173
174 fn from_key_value(value: &Value) -> Option<Self> {
175 Self::from_value(value)
176 }
177}
178
179pub trait ValueCodec {
189 fn to_value(&self) -> Value;
190
191 #[must_use]
192 fn from_value(value: &Value) -> Option<Self>
193 where
194 Self: Sized;
195}
196
197pub trait PersistedByKindCodec: Sized {
208 fn encode_persisted_slot_payload_by_kind(
210 &self,
211 kind: FieldKind,
212 field_name: &'static str,
213 ) -> Result<Vec<u8>, InternalError>;
214
215 fn decode_persisted_option_slot_payload_by_kind(
219 bytes: &[u8],
220 kind: FieldKind,
221 field_name: &'static str,
222 ) -> Result<Option<Self>, InternalError>;
223}
224
225pub trait PersistedStructuredFieldCodec {
234 fn encode_persisted_structured_payload(&self) -> Result<Vec<u8>, InternalError>;
236
237 fn decode_persisted_structured_payload(bytes: &[u8]) -> Result<Self, InternalError>
239 where
240 Self: Sized;
241}
242
243pub trait EntitySchema: EntityKey {
254 const NAME: &'static str;
255 const MODEL: &'static EntityModel;
256}
257
258pub trait EntityPlacement {
272 type Store: StoreKind;
273 type Canister: CanisterKind;
274}
275
276pub trait EntityKind: EntitySchema + EntityPlacement + Kind + TypeKind {
286 const ENTITY_TAG: EntityTag;
287}
288
289pub trait EntityValue: EntityKey + FieldProjection + Sized {
307 fn id(&self) -> Id<Self>;
308}
309
310pub struct EntityCreateMaterialization<E> {
319 entity: E,
320 authored_slots: Vec<usize>,
321}
322
323impl<E> EntityCreateMaterialization<E> {
324 #[must_use]
326 pub const fn new(entity: E, authored_slots: Vec<usize>) -> Self {
327 Self {
328 entity,
329 authored_slots,
330 }
331 }
332
333 #[must_use]
335 pub fn into_entity(self) -> E {
336 self.entity
337 }
338
339 #[must_use]
341 pub const fn authored_slots(&self) -> &[usize] {
342 self.authored_slots.as_slice()
343 }
344}
345
346pub trait EntityCreateInput: Sized {
355 type Entity: EntityValue + Default;
356
357 fn materialize_create(self) -> EntityCreateMaterialization<Self::Entity>;
359}
360
361pub trait EntityCreateType: EntityValue {
371 type Create: EntityCreateInput<Entity = Self>;
372}
373
374pub trait SingletonEntity: EntityValue {}
376
377pub trait TypeKind:
395 Kind + Clone + Default + DeserializeOwned + Sanitize + Validate + Visitable + PartialEq
396{
397}
398
399impl<T> TypeKind for T where
400 T: Kind + Clone + Default + DeserializeOwned + PartialEq + Sanitize + Validate + Visitable
401{
402}
403
404pub trait FieldTypeMeta {
413 const KIND: FieldKind;
415
416 const STORAGE_DECODE: FieldStorageDecode;
418}
419
420pub trait PersistedFieldMetaCodec: FieldTypeMeta + Sized {
431 fn encode_persisted_slot_payload_by_meta(
434 &self,
435 field_name: &'static str,
436 ) -> Result<Vec<u8>, InternalError>;
437
438 fn decode_persisted_slot_payload_by_meta(
441 bytes: &[u8],
442 field_name: &'static str,
443 ) -> Result<Self, InternalError>;
444
445 fn encode_persisted_option_slot_payload_by_meta(
448 value: &Option<Self>,
449 field_name: &'static str,
450 ) -> Result<Vec<u8>, InternalError>;
451
452 fn decode_persisted_option_slot_payload_by_meta(
455 bytes: &[u8],
456 field_name: &'static str,
457 ) -> Result<Option<Self>, InternalError>;
458}
459
460impl<T> FieldTypeMeta for Option<T>
461where
462 T: FieldTypeMeta,
463{
464 const KIND: FieldKind = T::KIND;
465 const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
466}
467
468impl<T> FieldTypeMeta for Box<T>
469where
470 T: FieldTypeMeta,
471{
472 const KIND: FieldKind = T::KIND;
473 const STORAGE_DECODE: FieldStorageDecode = T::STORAGE_DECODE;
474}
475
476impl<T> FieldTypeMeta for Vec<T>
480where
481 T: FieldTypeMeta,
482{
483 const KIND: FieldKind = FieldKind::List(&T::KIND);
484 const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
485}
486
487impl<T> FieldTypeMeta for BTreeSet<T>
488where
489 T: FieldTypeMeta,
490{
491 const KIND: FieldKind = FieldKind::Set(&T::KIND);
492 const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
493}
494
495impl<K, V> FieldTypeMeta for BTreeMap<K, V>
496where
497 K: FieldTypeMeta,
498 V: FieldTypeMeta,
499{
500 const KIND: FieldKind = FieldKind::Map {
501 key: &K::KIND,
502 value: &V::KIND,
503 };
504 const STORAGE_DECODE: FieldStorageDecode = FieldStorageDecode::Value;
505}
506
507pub trait Collection {
520 type Item;
521
522 type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
524 where
525 Self: 'a;
526
527 fn iter(&self) -> Self::Iter<'_>;
529
530 fn len(&self) -> usize;
532
533 fn is_empty(&self) -> bool {
535 self.len() == 0
536 }
537}
538
539pub trait MapCollection {
548 type Key;
549 type Value;
550
551 type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
553 where
554 Self: 'a;
555
556 fn iter(&self) -> Self::Iter<'_>;
558
559 fn len(&self) -> usize;
561
562 fn is_empty(&self) -> bool {
564 self.len() == 0
565 }
566}
567
568impl<T> Collection for Vec<T> {
569 type Item = T;
570 type Iter<'a>
571 = std::slice::Iter<'a, T>
572 where
573 Self: 'a;
574
575 fn iter(&self) -> Self::Iter<'_> {
576 self.as_slice().iter()
577 }
578
579 fn len(&self) -> usize {
580 self.as_slice().len()
581 }
582}
583
584impl<T> Collection for BTreeSet<T> {
585 type Item = T;
586 type Iter<'a>
587 = std::collections::btree_set::Iter<'a, T>
588 where
589 Self: 'a;
590
591 fn iter(&self) -> Self::Iter<'_> {
592 self.iter()
593 }
594
595 fn len(&self) -> usize {
596 self.len()
597 }
598}
599
600impl<K, V> MapCollection for BTreeMap<K, V> {
601 type Key = K;
602 type Value = V;
603 type Iter<'a>
604 = std::collections::btree_map::Iter<'a, K, V>
605 where
606 Self: 'a;
607
608 fn iter(&self) -> Self::Iter<'_> {
609 self.iter()
610 }
611
612 fn len(&self) -> usize {
613 self.len()
614 }
615}
616
617pub trait EnumValue {
618 fn to_value_enum(&self) -> ValueEnum;
619}
620
621pub trait FieldProjection {
622 fn get_value_by_index(&self, index: usize) -> Option<Value>;
624}
625
626#[derive(Clone, Copy, Debug, Eq, PartialEq)]
634pub enum ValueSurfaceKind {
635 Atomic,
637
638 Structured {
641 queryable: bool,
643 },
644}
645
646impl ValueSurfaceKind {
647 #[must_use]
648 pub const fn is_queryable(self) -> bool {
649 match self {
650 Self::Atomic => true,
651 Self::Structured { queryable } => queryable,
652 }
653 }
654}
655
656pub trait ValueSurfaceMeta {
665 fn kind() -> ValueSurfaceKind
666 where
667 Self: Sized;
668}
669
670pub fn value_codec_collection_to_value<C>(collection: &C) -> Value
679where
680 C: Collection,
681 C::Item: ValueCodec,
682{
683 Value::List(collection.iter().map(ValueCodec::to_value).collect())
684}
685
686#[must_use]
695pub fn value_codec_vec_from_value<T>(value: &Value) -> Option<Vec<T>>
696where
697 T: ValueCodec,
698{
699 let Value::List(values) = value else {
700 return None;
701 };
702
703 let mut out = Vec::with_capacity(values.len());
704 for value in values {
705 out.push(T::from_value(value)?);
706 }
707
708 Some(out)
709}
710
711#[must_use]
720pub fn value_codec_btree_set_from_value<T>(value: &Value) -> Option<BTreeSet<T>>
721where
722 T: Ord + ValueCodec,
723{
724 let Value::List(values) = value else {
725 return None;
726 };
727
728 let mut out = BTreeSet::new();
729 for value in values {
730 let item = T::from_value(value)?;
731 if !out.insert(item) {
732 return None;
733 }
734 }
735
736 Some(out)
737}
738
739pub fn value_codec_map_collection_to_value<M>(map: &M, path: &'static str) -> Value
749where
750 M: MapCollection,
751 M::Key: ValueCodec,
752 M::Value: ValueCodec,
753{
754 let mut entries: Vec<(Value, Value)> = map
755 .iter()
756 .map(|(key, value)| (ValueCodec::to_value(key), ValueCodec::to_value(value)))
757 .collect();
758
759 if let Err(err) = Value::validate_map_entries(entries.as_slice()) {
760 debug_assert!(false, "invalid map field value for {path}: {err}");
761 return Value::Map(entries);
762 }
763
764 Value::sort_map_entries_in_place(entries.as_mut_slice());
765
766 for i in 1..entries.len() {
767 let (left_key, _) = &entries[i - 1];
768 let (right_key, _) = &entries[i];
769 if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
770 debug_assert!(
771 false,
772 "duplicate map key in {path} after ValueCodec::to_value canonicalization",
773 );
774 break;
775 }
776 }
777
778 Value::Map(entries)
779}
780
781#[must_use]
790pub fn value_codec_btree_map_from_value<K, V>(value: &Value) -> Option<BTreeMap<K, V>>
791where
792 K: Ord + ValueCodec,
793 V: ValueCodec,
794{
795 let Value::Map(entries) = value else {
796 return None;
797 };
798
799 let normalized = Value::normalize_map_entries(entries.clone()).ok()?;
800 if normalized.as_slice() != entries.as_slice() {
801 return None;
802 }
803
804 let mut map = BTreeMap::new();
805 for (entry_key, entry_value) in normalized {
806 let key = K::from_value(&entry_key)?;
807 let value = V::from_value(&entry_value)?;
808 map.insert(key, value);
809 }
810
811 Some(map)
812}
813
814#[must_use]
823pub fn value_codec_from_vec_into<T, I>(entries: Vec<I>) -> Vec<T>
824where
825 I: Into<T>,
826{
827 entries.into_iter().map(Into::into).collect()
828}
829
830#[must_use]
839pub fn value_codec_from_vec_into_btree_set<T, I>(entries: Vec<I>) -> BTreeSet<T>
840where
841 I: Into<T>,
842 T: Ord,
843{
844 entries.into_iter().map(Into::into).collect()
845}
846
847#[must_use]
856pub fn value_codec_from_vec_into_btree_map<K, V, IK, IV>(entries: Vec<(IK, IV)>) -> BTreeMap<K, V>
857where
858 IK: Into<K>,
859 IV: Into<V>,
860 K: Ord,
861{
862 entries
863 .into_iter()
864 .map(|(key, value)| (key.into(), value.into()))
865 .collect()
866}
867
868#[must_use]
877pub fn value_codec_into<T, U>(value: U) -> T
878where
879 U: Into<T>,
880{
881 value.into()
882}
883
884impl ValueSurfaceMeta for &str {
885 fn kind() -> ValueSurfaceKind {
886 ValueSurfaceKind::Atomic
887 }
888}
889
890impl ValueCodec for &str {
891 fn to_value(&self) -> Value {
892 Value::Text((*self).to_string())
893 }
894
895 fn from_value(_value: &Value) -> Option<Self> {
896 None
897 }
898}
899
900impl ValueSurfaceMeta for String {
901 fn kind() -> ValueSurfaceKind {
902 ValueSurfaceKind::Atomic
903 }
904}
905
906impl ValueCodec for String {
907 fn to_value(&self) -> Value {
908 Value::Text(self.clone())
909 }
910
911 fn from_value(value: &Value) -> Option<Self> {
912 match value {
913 Value::Text(v) => Some(v.clone()),
914 _ => None,
915 }
916 }
917}
918
919impl<T: ValueSurfaceMeta> ValueSurfaceMeta for Option<T> {
920 fn kind() -> ValueSurfaceKind {
921 T::kind()
922 }
923}
924
925impl<T: ValueCodec> ValueCodec for Option<T> {
926 fn to_value(&self) -> Value {
927 match self {
928 Some(v) => v.to_value(),
929 None => Value::Null,
930 }
931 }
932
933 fn from_value(value: &Value) -> Option<Self> {
934 if matches!(value, Value::Null) {
935 return Some(None);
936 }
937
938 T::from_value(value).map(Some)
939 }
940}
941
942impl<T: ValueSurfaceMeta> ValueSurfaceMeta for Box<T> {
943 fn kind() -> ValueSurfaceKind {
944 T::kind()
945 }
946}
947
948impl<T: ValueCodec> ValueCodec for Box<T> {
949 fn to_value(&self) -> Value {
950 (**self).to_value()
951 }
952
953 fn from_value(value: &Value) -> Option<Self> {
954 T::from_value(value).map(Self::new)
955 }
956}
957
958impl<T> ValueSurfaceMeta for Vec<T> {
959 fn kind() -> ValueSurfaceKind {
960 ValueSurfaceKind::Structured { queryable: true }
961 }
962}
963
964impl<T: ValueCodec> ValueCodec for Vec<T> {
965 fn to_value(&self) -> Value {
966 value_codec_collection_to_value(self)
967 }
968
969 fn from_value(value: &Value) -> Option<Self> {
970 value_codec_vec_from_value(value)
971 }
972}
973
974impl<T> ValueSurfaceMeta for BTreeSet<T>
975where
976 T: Ord,
977{
978 fn kind() -> ValueSurfaceKind {
979 ValueSurfaceKind::Structured { queryable: true }
980 }
981}
982
983impl<T> ValueCodec for BTreeSet<T>
984where
985 T: Ord + ValueCodec,
986{
987 fn to_value(&self) -> Value {
988 value_codec_collection_to_value(self)
989 }
990
991 fn from_value(value: &Value) -> Option<Self> {
992 value_codec_btree_set_from_value(value)
993 }
994}
995
996impl<K, V> ValueSurfaceMeta for BTreeMap<K, V>
997where
998 K: Ord,
999{
1000 fn kind() -> ValueSurfaceKind {
1001 ValueSurfaceKind::Structured { queryable: true }
1002 }
1003}
1004
1005impl<K, V> ValueCodec for BTreeMap<K, V>
1006where
1007 K: Ord + ValueCodec,
1008 V: ValueCodec,
1009{
1010 fn to_value(&self) -> Value {
1011 value_codec_map_collection_to_value(self, std::any::type_name::<Self>())
1012 }
1013
1014 fn from_value(value: &Value) -> Option<Self> {
1015 value_codec_btree_map_from_value(value)
1016 }
1017}
1018
1019#[macro_export]
1021macro_rules! impl_field_value {
1022 ( $( $type:ty => $variant:ident ),* $(,)? ) => {
1023 $(
1024 impl ValueSurfaceMeta for $type {
1025 fn kind() -> ValueSurfaceKind {
1026 ValueSurfaceKind::Atomic
1027 }
1028 }
1029
1030 impl ValueCodec for $type {
1031 fn to_value(&self) -> Value {
1032 Value::$variant((*self).into())
1033 }
1034
1035 fn from_value(value: &Value) -> Option<Self> {
1036 match value {
1037 Value::$variant(v) => (*v).try_into().ok(),
1038 _ => None,
1039 }
1040 }
1041 }
1042 )*
1043 };
1044}
1045
1046impl_field_value!(
1047 i8 => Int,
1048 i16 => Int,
1049 i32 => Int,
1050 i64 => Int,
1051 u8 => Uint,
1052 u16 => Uint,
1053 u32 => Uint,
1054 u64 => Uint,
1055 bool => Bool,
1056);
1057
1058pub trait Inner<T> {
1069 fn inner(&self) -> &T;
1070 fn into_inner(self) -> T;
1071}
1072
1073impl<T> Inner<T> for T
1074where
1075 T: Atomic,
1076{
1077 fn inner(&self) -> &T {
1078 self
1079 }
1080
1081 fn into_inner(self) -> T {
1082 self
1083 }
1084}
1085
1086pub trait Repr {
1093 type Inner;
1094
1095 fn repr(&self) -> Self::Inner;
1096 fn from_repr(inner: Self::Inner) -> Self;
1097}
1098
1099pub trait Sanitizer<T> {
1110 fn sanitize(&self, value: &mut T) -> Result<(), String>;
1111
1112 fn sanitize_with_context(
1113 &self,
1114 value: &mut T,
1115 ctx: &mut dyn VisitorContext,
1116 ) -> Result<(), String> {
1117 let _ = ctx;
1118
1119 self.sanitize(value)
1120 }
1121}
1122
1123pub trait Validator<T: ?Sized> {
1130 fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
1131}