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