appcore_provider/
factory.rs1use 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
17pub trait ProviderFactory<T>: Send + Sync {
19 fn role(&self) -> ProviderRole;
21 fn provider_id(&self) -> &'static str;
23 fn create(
25 &self,
26 config: &ProviderConfig,
27 context: &ProviderContext,
28 secrets: &dyn SecretProvider,
29 ) -> ProviderResult<T>;
30}
31
32pub 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 pub fn new() -> Self {
57 Self::default()
58 }
59
60 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 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 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}