Skip to main content

appcore_provider/
factory.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: factory.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/07/22 15:41:18 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/07/24 16:07:49 by dnettoRaw
8//      ###########      S: 1.0.1-rc.8
9// =============================================================================
10
11use crate::{ProviderContext, ProviderError, ProviderResult, ProviderRole, SecretProvider};
12use appcore_contracts::{ProviderConfig, ProviderId};
13use std::collections::BTreeMap;
14use std::fmt::{Debug, Formatter};
15use std::sync::Arc;
16
17/// Factory for one provider implementation and output interface.
18pub trait ProviderFactory<T>: Send + Sync {
19    /// Infrastructure role implemented by this factory.
20    fn role(&self) -> ProviderRole;
21    /// Stable provider identity selected in deployment manifests.
22    fn provider_id(&self) -> &'static str;
23    /// Validates configuration and constructs a provider instance.
24    fn create(
25        &self,
26        config: &ProviderConfig,
27        context: &ProviderContext,
28        secrets: &dyn SecretProvider,
29    ) -> ProviderResult<T>;
30}
31
32/// Registry of explicit provider factories for one output interface.
33pub struct ProviderRegistry<T> {
34    factories: BTreeMap<(ProviderRole, String), Arc<dyn ProviderFactory<T>>>,
35}
36
37impl<T> Debug for ProviderRegistry<T> {
38    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
39        formatter
40            .debug_struct("ProviderRegistry")
41            .field("factory_count", &self.factories.len())
42            .finish()
43    }
44}
45
46impl<T> Default for ProviderRegistry<T> {
47    fn default() -> Self {
48        Self {
49            factories: BTreeMap::new(),
50        }
51    }
52}
53
54impl<T> ProviderRegistry<T> {
55    /// Creates an empty provider registry.
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    /// Registers one factory and rejects ambiguous duplicate ownership.
61    pub fn register<F>(&mut self, factory: F) -> ProviderResult<()>
62    where
63        F: ProviderFactory<T> + 'static,
64    {
65        let key = (factory.role(), factory.provider_id().to_string());
66        if self.factories.contains_key(&key) {
67            return Err(ProviderError::DuplicateFactory {
68                role: key.0,
69                provider_id: key.1,
70            });
71        }
72        self.factories.insert(key, Arc::new(factory));
73        Ok(())
74    }
75
76    /// Constructs the provider explicitly selected by a deployment manifest.
77    pub fn create(
78        &self,
79        role: ProviderRole,
80        config: &ProviderConfig,
81        context: &ProviderContext,
82        secrets: &dyn SecretProvider,
83    ) -> ProviderResult<T> {
84        let key = (role, config.provider_id().as_str().to_string());
85        let factory = self
86            .factories
87            .get(&key)
88            .ok_or_else(|| ProviderError::Unavailable {
89                role,
90                provider_id: config.provider_id().as_str().to_string(),
91            })?;
92        factory.create(config, context, secrets)
93    }
94
95    /// Reports whether a role and provider ID are available.
96    pub fn contains(&self, role: ProviderRole, provider_id: &ProviderId) -> bool {
97        self.factories
98            .contains_key(&(role, provider_id.as_str().to_string()))
99    }
100}