icydb_core/db/store/
mod.rs

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