Skip to main content

icydb_core/db/index/
store.rs

1//! Module: index::store
2//! Responsibility: stable index-entry persistence primitives.
3//! Does not own: range-scan resolution, continuation semantics, or predicate execution.
4//! Boundary: scan/executor layers depend on this storage boundary.
5
6use crate::db::index::{entry::RawIndexEntry, key::RawIndexKey};
7
8use canic_cdk::structures::{BTreeMap, DefaultMemoryImpl, memory::VirtualMemory};
9
10///
11/// IndexStore
12///
13/// Thin persistence wrapper over one stable BTreeMap.
14///
15/// Invariant: callers provide already-validated `RawIndexKey`/`RawIndexEntry`.
16///
17
18pub struct IndexStore {
19    pub(super) map: BTreeMap<RawIndexKey, RawIndexEntry, VirtualMemory<DefaultMemoryImpl>>,
20    generation: u64,
21}
22
23impl IndexStore {
24    #[must_use]
25    pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
26        Self {
27            map: BTreeMap::init(memory),
28            generation: 0,
29        }
30    }
31
32    /// Snapshot all index entry pairs (diagnostics only).
33    #[allow(clippy::redundant_closure_for_method_calls)]
34    pub(crate) fn entries(&self) -> Vec<(RawIndexKey, RawIndexEntry)> {
35        self.map.iter().map(|entry| entry.into_pair()).collect()
36    }
37
38    pub(in crate::db) fn get(&self, key: &RawIndexKey) -> Option<RawIndexEntry> {
39        self.map.get(key)
40    }
41
42    pub fn len(&self) -> u64 {
43        self.map.len()
44    }
45
46    pub fn is_empty(&self) -> bool {
47        self.map.is_empty()
48    }
49
50    #[must_use]
51    pub(in crate::db) const fn generation(&self) -> u64 {
52        self.generation
53    }
54
55    pub(crate) fn insert(
56        &mut self,
57        key: RawIndexKey,
58        entry: RawIndexEntry,
59    ) -> Option<RawIndexEntry> {
60        let previous = self.map.insert(key, entry);
61        self.bump_generation();
62        previous
63    }
64
65    pub(crate) fn remove(&mut self, key: &RawIndexKey) -> Option<RawIndexEntry> {
66        let previous = self.map.remove(key);
67        self.bump_generation();
68        previous
69    }
70
71    pub fn clear(&mut self) {
72        self.map.clear();
73        self.bump_generation();
74    }
75
76    /// Sum of bytes used by all stored index entries.
77    pub fn memory_bytes(&self) -> u64 {
78        self.map
79            .iter()
80            .map(|entry| entry.key().as_bytes().len() as u64 + entry.value().len() as u64)
81            .sum()
82    }
83
84    const fn bump_generation(&mut self) {
85        self.generation = self.generation.saturating_add(1);
86    }
87}