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 {
23 Self(StoreRegistry::new())
24 }
25}
26
27#[derive(Deref, DerefMut)]
32pub struct DataStore(BTreeMap<DataKey, Vec<u8>, VirtualMemory<DefaultMemoryImpl>>);
33
34impl DataStore {
35 #[must_use]
36 pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
38 Self(BTreeMap::init(memory))
39 }
40
41 pub fn memory_bytes(&self) -> u64 {
43 self.iter()
44 .map(|entry| u64::from(DataKey::STORABLE_MAX_SIZE) + entry.value().len() as u64)
45 .sum()
46 }
47}
48
49pub type DataRow = (DataKey, Vec<u8>);
54
55#[derive(
60 CandidType, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize,
61)]
62pub struct DataKey {
63 entity_id: u64,
64 key: Key,
65}
66
67impl DataKey {
68 pub const STORABLE_MAX_SIZE: u32 = 160;
69
70 #[must_use]
71 pub fn new<E: EntityKind>(key: impl Into<Key>) -> Self {
73 Self {
74 entity_id: E::ENTITY_ID,
75 key: key.into(),
76 }
77 }
78
79 #[must_use]
80 pub const fn lower_bound<E: EntityKind>() -> Self {
81 Self {
82 entity_id: E::ENTITY_ID,
83 key: Key::lower_bound(),
84 }
85 }
86
87 #[must_use]
88 pub const fn upper_bound<E: EntityKind>() -> Self {
89 Self {
90 entity_id: E::ENTITY_ID,
91 key: Key::upper_bound(),
92 }
93 }
94
95 #[must_use]
97 pub const fn key(&self) -> Key {
98 self.key
99 }
100
101 #[must_use]
103 pub const fn entity_id(&self) -> u64 {
104 self.entity_id
105 }
106
107 #[must_use]
110 pub const fn entry_size_bytes(value_len: u64) -> u64 {
111 Self::STORABLE_MAX_SIZE as u64 + value_len
112 }
113
114 #[must_use]
115 pub fn max_storable() -> Self {
117 Self {
118 entity_id: u64::MAX,
119 key: Key::max_storable(),
120 }
121 }
122}
123
124impl Display for DataKey {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "#{} ({})", self.entity_id, self.key)
127 }
128}
129
130impl From<DataKey> for Key {
131 fn from(key: DataKey) -> Self {
132 key.key()
133 }
134}
135
136impl_storable_bounded!(DataKey, Self::STORABLE_MAX_SIZE, false);
137
138#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::traits::Storable;
146
147 #[test]
148 fn data_key_max_size_is_bounded() {
149 let data_key = DataKey::max_storable();
150 let size = Storable::to_bytes(&data_key).len();
151
152 assert!(
153 size <= DataKey::STORABLE_MAX_SIZE as usize,
154 "serialized DataKey too large: got {size} bytes (limit {})",
155 DataKey::STORABLE_MAX_SIZE
156 );
157 }
158}