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