icydb_core/db/store/
data.rs1use crate::{Key, db::store::StoreRegistry, traits::EntityKind};
2use candid::CandidType;
3use canic::{
4 cdk::structures::{BTreeMap, DefaultMemoryImpl, memory::VirtualMemory},
5 impl_storable_bounded,
6};
7use derive_more::{Deref, DerefMut};
8use serde::{Deserialize, Serialize};
9use std::fmt::{self, Display};
10
11#[derive(Deref, DerefMut)]
16pub struct DataStoreRegistry(StoreRegistry<DataStore>);
17
18impl DataStoreRegistry {
19 #[must_use]
20 #[allow(clippy::new_without_default)]
21 pub fn new() -> Self {
22 Self(StoreRegistry::new())
23 }
24}
25
26#[derive(Deref, DerefMut)]
31pub struct DataStore(BTreeMap<DataKey, Vec<u8>, VirtualMemory<DefaultMemoryImpl>>);
32
33impl DataStore {
34 #[must_use]
35 pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
36 Self(BTreeMap::init(memory))
37 }
38
39 pub fn memory_bytes(&self) -> u64 {
40 self.iter()
41 .map(|entry| u64::from(DataKey::STORABLE_MAX_SIZE) + entry.value().len() as u64)
42 .sum()
43 }
44}
45
46pub type DataRow = (DataKey, Vec<u8>);
51
52#[derive(
57 CandidType, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize,
58)]
59pub struct DataKey {
60 entity_id: u64,
61 key: Key,
62}
63
64impl DataKey {
65 pub const STORABLE_MAX_SIZE: u32 = 160;
66
67 #[must_use]
68 pub fn new<E: EntityKind>(key: impl Into<Key>) -> Self {
69 Self {
70 entity_id: E::ENTITY_ID,
71 key: key.into(),
72 }
73 }
74
75 #[must_use]
76 pub const fn lower_bound<E: EntityKind>() -> Self {
77 Self {
78 entity_id: E::ENTITY_ID,
79 key: Key::lower_bound(),
80 }
81 }
82
83 #[must_use]
84 pub const fn upper_bound<E: EntityKind>() -> Self {
85 Self {
86 entity_id: E::ENTITY_ID,
87 key: Key::upper_bound(),
88 }
89 }
90
91 #[must_use]
93 pub const fn key(&self) -> Key {
94 self.key
95 }
96
97 #[must_use]
99 pub const fn entity_id(&self) -> u64 {
100 self.entity_id
101 }
102
103 #[must_use]
106 pub const fn entry_size_bytes(value_len: u64) -> u64 {
107 Self::STORABLE_MAX_SIZE as u64 + value_len
108 }
109
110 #[must_use]
111 pub fn max_storable() -> Self {
112 Self {
113 entity_id: u64::MAX,
114 key: Key::max_storable(),
115 }
116 }
117}
118
119impl Display for DataKey {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 write!(f, "#{} ({})", self.entity_id, self.key)
122 }
123}
124
125impl From<DataKey> for Key {
126 fn from(key: DataKey) -> Self {
127 key.key()
128 }
129}
130
131impl_storable_bounded!(DataKey, Self::STORABLE_MAX_SIZE, false);
132
133#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::traits::Storable;
141
142 #[test]
143 fn data_key_max_size_is_bounded() {
144 let data_key = DataKey::max_storable();
145 let size = Storable::to_bytes(&data_key).len();
146
147 assert!(
148 size <= DataKey::STORABLE_MAX_SIZE as usize,
149 "serialized DataKey too large: got {size} bytes (limit {})",
150 DataKey::STORABLE_MAX_SIZE
151 );
152 }
153}