Skip to main content

icydb_core/db/registry/
registry.rs

1use crate::{
2    db::{
3        data::DataStore,
4        index::IndexStore,
5        registry::{StoreHandle, StoreRegistryError},
6    },
7    error::InternalError,
8};
9use std::{cell::RefCell, thread::LocalKey};
10
11///
12/// StoreRegistry
13///
14/// StoreRegistry owns the generated mapping from schema `Store` paths to their
15/// row/index store handles.
16/// It validates registration invariants once at generated wiring time and then
17/// serves cheap immutable lookups during runtime operations.
18///
19
20#[derive(Default)]
21pub struct StoreRegistry {
22    stores: Vec<(&'static str, StoreHandle)>,
23}
24
25impl StoreRegistry {
26    /// Create an empty store registry.
27    #[must_use]
28    pub fn new() -> Self {
29        Self::default()
30    }
31
32    /// Iterate registered stores.
33    ///
34    /// Iteration order follows registration order. Semantic result ordering
35    /// must still not depend on this iteration order; callers that need
36    /// deterministic ordering must sort by store path.
37    pub fn iter(&self) -> impl Iterator<Item = (&'static str, StoreHandle)> {
38        self.stores.iter().copied()
39    }
40
41    /// Register a `Store` path to its row/index store pair.
42    pub fn register_store(
43        &mut self,
44        name: &'static str,
45        data: &'static LocalKey<RefCell<DataStore>>,
46        index: &'static LocalKey<RefCell<IndexStore>>,
47    ) -> Result<(), InternalError> {
48        if self
49            .stores
50            .iter()
51            .any(|(existing_name, _)| *existing_name == name)
52        {
53            return Err(StoreRegistryError::StoreAlreadyRegistered(name.to_string()).into());
54        }
55
56        // Keep one canonical logical store name per physical row/index store pair.
57        if let Some(existing_name) =
58            self.stores
59                .iter()
60                .find_map(|(existing_name, existing_handle)| {
61                    (std::ptr::eq(existing_handle.data_store(), data)
62                        && std::ptr::eq(existing_handle.index_store(), index))
63                    .then_some(*existing_name)
64                })
65        {
66            return Err(StoreRegistryError::StoreHandlePairAlreadyRegistered {
67                name: name.to_string(),
68                existing_name: existing_name.to_string(),
69            }
70            .into());
71        }
72
73        self.stores.push((name, StoreHandle::new(data, index)));
74
75        Ok(())
76    }
77
78    /// Look up a store handle by path.
79    pub fn try_get_store(&self, path: &str) -> Result<StoreHandle, InternalError> {
80        self.stores
81            .iter()
82            .find_map(|(existing_path, handle)| (*existing_path == path).then_some(*handle))
83            .ok_or_else(|| StoreRegistryError::StoreNotFound(path.to_string()).into())
84    }
85}