icydb_core/db/store/
mod.rs

1mod data;
2mod index;
3
4pub use data::*;
5pub use index::*;
6
7use crate::runtime_error::{ErrorClass, ErrorOrigin, RuntimeError};
8use std::{cell::RefCell, collections::HashMap, thread::LocalKey};
9use thiserror::Error as ThisError;
10
11///
12/// StoreError
13///
14
15#[derive(Debug, ThisError)]
16pub enum StoreError {
17    #[error("store '{0}' not found")]
18    StoreNotFound(String),
19}
20
21impl StoreError {
22    pub(crate) const fn class(&self) -> ErrorClass {
23        match self {
24            Self::StoreNotFound(_) => ErrorClass::Internal,
25        }
26    }
27}
28
29impl From<StoreError> for RuntimeError {
30    fn from(err: StoreError) -> Self {
31        Self::new(err.class(), ErrorOrigin::Store, err.to_string())
32    }
33}
34
35///
36/// StoreRegistry
37///
38
39#[derive(Default)]
40pub struct StoreRegistry<T: 'static>(HashMap<&'static str, &'static LocalKey<RefCell<T>>>);
41
42impl<T: 'static> StoreRegistry<T> {
43    // new
44    #[must_use]
45    /// Create an empty store registry.
46    pub fn new() -> Self {
47        Self(HashMap::new())
48    }
49
50    // iter
51    /// Iterate registered store names and thread-local keys.
52    pub fn iter(&self) -> impl Iterator<Item = (&'static str, &'static LocalKey<RefCell<T>>)> {
53        self.0.iter().map(|(k, v)| (*k, *v))
54    }
55
56    // for_each
57    /// Borrow each registered store immutably.
58    pub fn for_each<R>(&self, mut f: impl FnMut(&'static str, &T) -> R) {
59        for (path, accessor) in &self.0 {
60            accessor.with(|cell| {
61                let store = cell.borrow();
62                f(path, &store);
63            });
64        }
65    }
66
67    // register
68    /// Register a thread-local store accessor under a path.
69    pub fn register(&mut self, name: &'static str, accessor: &'static LocalKey<RefCell<T>>) {
70        self.0.insert(name, accessor);
71    }
72
73    // try_get_store
74    /// Look up a store accessor by path.
75    pub fn try_get_store(&self, path: &str) -> Result<&'static LocalKey<RefCell<T>>, RuntimeError> {
76        self.0
77            .get(path)
78            .copied()
79            .ok_or_else(|| StoreError::StoreNotFound(path.to_string()).into())
80    }
81
82    // with_store
83    /// Borrow a store immutably by path.
84    pub fn with_store<R>(&self, path: &str, f: impl FnOnce(&T) -> R) -> Result<R, RuntimeError> {
85        let store = self.try_get_store(path)?;
86
87        Ok(store.with_borrow(|s| f(s)))
88    }
89
90    // with_store_mut
91    /// Borrow a store mutably by path.
92    pub fn with_store_mut<R>(
93        &self,
94        path: &str,
95        f: impl FnOnce(&mut T) -> R,
96    ) -> Result<R, RuntimeError> {
97        let store = self.try_get_store(path)?;
98
99        Ok(store.with_borrow_mut(|s| f(s)))
100    }
101}