icydb_core/db/data/
store.rs1use crate::{
7 db::data::{
8 CanonicalRow, DataKey, RawDataKey, RawRow, SelectiveRowRead, StorageKey,
9 StructuralRowContract, decode_sparse_indexed_raw_row_with_contract,
10 decode_sparse_required_slot_with_contract,
11 },
12 error::InternalError,
13 value::Value,
14};
15use canic_cdk::structures::{BTreeMap, DefaultMemoryImpl, memory::VirtualMemory};
16#[cfg(feature = "diagnostics")]
17use std::cell::Cell;
18
19#[cfg(feature = "diagnostics")]
20thread_local! {
21 static DATA_STORE_GET_CALL_COUNT: Cell<u64> = const { Cell::new(0) };
22}
23
24#[cfg(feature = "diagnostics")]
25fn record_data_store_get_call() {
26 DATA_STORE_GET_CALL_COUNT.with(|count| {
27 count.set(count.get().saturating_add(1));
28 });
29}
30
31pub struct DataStore {
41 map: BTreeMap<RawDataKey, RawRow, VirtualMemory<DefaultMemoryImpl>>,
42}
43
44impl DataStore {
45 #[must_use]
47 pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
48 Self {
49 map: BTreeMap::init(memory),
50 }
51 }
52
53 pub(in crate::db) fn insert(&mut self, key: RawDataKey, row: CanonicalRow) -> Option<RawRow> {
55 self.map.insert(key, row.into_raw_row())
56 }
57
58 #[cfg(test)]
60 pub(crate) fn insert_raw_for_test(&mut self, key: RawDataKey, row: RawRow) -> Option<RawRow> {
61 self.map.insert(key, row)
62 }
63
64 pub fn remove(&mut self, key: &RawDataKey) -> Option<RawRow> {
66 self.map.remove(key)
67 }
68
69 pub fn get(&self, key: &RawDataKey) -> Option<RawRow> {
71 #[cfg(feature = "diagnostics")]
72 record_data_store_get_call();
73
74 self.map.get(key)
75 }
76
77 pub(in crate::db) fn read_slot_values(
79 &self,
80 key: &RawDataKey,
81 contract: StructuralRowContract,
82 expected_key: StorageKey,
83 required_slots: &[usize],
84 ) -> Result<SelectiveRowRead<Vec<Option<Value>>>, InternalError> {
85 let Some(raw_row) = self.get(key) else {
89 return Ok(SelectiveRowRead::MissingRow);
90 };
91
92 let values = if let [required_slot] = required_slots {
96 vec![decode_sparse_required_slot_with_contract(
97 &raw_row,
98 contract,
99 expected_key,
100 *required_slot,
101 )?]
102 } else {
103 decode_sparse_indexed_raw_row_with_contract(
104 &raw_row,
105 contract,
106 expected_key,
107 required_slots,
108 )?
109 };
110
111 Ok(SelectiveRowRead::Present(values))
112 }
113
114 #[must_use]
116 pub fn contains(&self, key: &RawDataKey) -> bool {
117 self.map.contains_key(key)
118 }
119
120 pub fn clear(&mut self) {
122 self.map.clear();
123 }
124
125 pub fn memory_bytes(&self) -> u64 {
127 self.iter()
129 .map(|entry| DataKey::STORED_SIZE_BYTES + entry.value().len() as u64)
130 .sum()
131 }
132
133 #[cfg(feature = "diagnostics")]
135 pub(in crate::db) fn current_get_call_count() -> u64 {
136 DATA_STORE_GET_CALL_COUNT.with(Cell::get)
137 }
138}
139
140impl std::ops::Deref for DataStore {
141 type Target = BTreeMap<RawDataKey, RawRow, VirtualMemory<DefaultMemoryImpl>>;
142
143 fn deref(&self) -> &Self::Target {
144 &self.map
145 }
146}