icydb_core/db/store/
mod.rs

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