Skip to main content

lash_core/provider/
registry.rs

1use super::support::*;
2
3pub trait ProviderFactory: Send + Sync {
4    fn kind(&self) -> &'static str;
5
6    /// Instantiate a provider from its [`ProviderSpec::config`] blob.
7    fn deserialize(&self, config: serde_json::Value) -> Result<ProviderComponents, String>;
8}
9
10#[derive(Clone, Default)]
11pub struct ProviderRegistry {
12    factories: BTreeMap<&'static str, Arc<dyn ProviderFactory>>,
13}
14
15impl ProviderRegistry {
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    pub fn register(&mut self, factory: Arc<dyn ProviderFactory>) {
21        self.factories.insert(factory.kind(), factory);
22    }
23
24    pub fn build_from_spec(&self, spec: &ProviderSpec) -> Result<ProviderComponents, String> {
25        let factory = self.factories.get(spec.kind.as_str()).ok_or_else(|| {
26            format!(
27                "provider `{}` is not registered. Call `lash_core::register_provider_factory` at startup.",
28                spec.kind
29            )
30        })?;
31        factory.deserialize(spec.config.clone())
32    }
33
34    pub fn factory(&self, kind: &str) -> Option<&Arc<dyn ProviderFactory>> {
35        self.factories.get(kind)
36    }
37}
38
39static PROVIDER_REGISTRY: LazyLock<RwLock<ProviderRegistry>> =
40    LazyLock::new(|| RwLock::new(ProviderRegistry::new()));
41
42/// Register a provider factory in the global registry. Hosts call this
43/// once per backend at process startup, before constructing any
44/// `LashConfig` or session from disk.
45pub fn register_provider_factory(factory: Arc<dyn ProviderFactory>) {
46    PROVIDER_REGISTRY.write().unwrap().register(factory);
47}
48
49/// Materialize a provider from its serialized form using the global
50/// registry. Returns `Err` if no factory is registered for `spec.kind`.
51pub fn build_provider(spec: &ProviderSpec) -> Result<ProviderComponents, String> {
52    PROVIDER_REGISTRY.read().unwrap().build_from_spec(spec)
53}
54
55/// Look up a registered provider factory by kind. Returns `None` if no
56/// factory with that kind is registered.
57pub fn provider_factory(kind: &str) -> Option<Arc<dyn ProviderFactory>> {
58    PROVIDER_REGISTRY.read().unwrap().factory(kind).cloned()
59}