Skip to main content

icydb_core/db/store/
mod.rs

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