use std::collections::HashMap;
use std::sync::Arc;
use crate::provider::{RuntimeCapability, SecretCapability, SyncCapability};
pub struct ProviderRegistry {
sync_providers: Vec<Arc<dyn SyncCapability>>,
sync_by_name: HashMap<&'static str, usize>,
runtime_providers: Vec<Arc<dyn RuntimeCapability>>,
runtime_by_name: HashMap<&'static str, usize>,
secret_providers: Vec<Arc<dyn SecretCapability>>,
secret_by_name: HashMap<&'static str, usize>,
}
impl ProviderRegistry {
#[must_use]
pub fn new() -> Self {
Self {
sync_providers: Vec::new(),
sync_by_name: HashMap::new(),
runtime_providers: Vec::new(),
runtime_by_name: HashMap::new(),
secret_providers: Vec::new(),
secret_by_name: HashMap::new(),
}
}
pub fn register_sync<P>(&mut self, provider: P)
where
P: SyncCapability + 'static,
{
let name = provider.name();
let index = self.sync_providers.len();
self.sync_providers.push(Arc::new(provider));
self.sync_by_name.insert(name, index);
}
pub fn register_runtime<P>(&mut self, provider: P)
where
P: RuntimeCapability + 'static,
{
let name = provider.name();
let index = self.runtime_providers.len();
self.runtime_providers.push(Arc::new(provider));
self.runtime_by_name.insert(name, index);
}
pub fn register_secret<P>(&mut self, provider: P)
where
P: SecretCapability + 'static,
{
let name = provider.name();
let index = self.secret_providers.len();
self.secret_providers.push(Arc::new(provider));
self.secret_by_name.insert(name, index);
}
pub fn sync_providers(&self) -> impl Iterator<Item = &Arc<dyn SyncCapability>> {
self.sync_providers.iter()
}
pub fn runtime_providers(&self) -> impl Iterator<Item = &Arc<dyn RuntimeCapability>> {
self.runtime_providers.iter()
}
pub fn secret_providers(&self) -> impl Iterator<Item = &Arc<dyn SecretCapability>> {
self.secret_providers.iter()
}
#[must_use]
pub fn get_sync_provider(&self, name: &str) -> Option<&Arc<dyn SyncCapability>> {
self.sync_by_name
.get(name)
.map(|&idx| &self.sync_providers[idx])
}
#[must_use]
pub fn get_runtime_provider(&self, name: &str) -> Option<&Arc<dyn RuntimeCapability>> {
self.runtime_by_name
.get(name)
.map(|&idx| &self.runtime_providers[idx])
}
#[must_use]
pub fn get_secret_provider(&self, name: &str) -> Option<&Arc<dyn SecretCapability>> {
self.secret_by_name
.get(name)
.map(|&idx| &self.secret_providers[idx])
}
#[must_use]
pub fn sync_provider_names(&self) -> Vec<&'static str> {
self.sync_by_name.keys().copied().collect()
}
#[must_use]
pub fn runtime_provider_names(&self) -> Vec<&'static str> {
self.runtime_by_name.keys().copied().collect()
}
#[must_use]
pub fn secret_provider_names(&self) -> Vec<&'static str> {
self.secret_by_name.keys().copied().collect()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.sync_providers.is_empty()
&& self.runtime_providers.is_empty()
&& self.secret_providers.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.sync_providers.len() + self.runtime_providers.len() + self.secret_providers.len()
}
#[must_use]
pub fn sync_provider_count(&self) -> usize {
self.sync_providers.len()
}
#[must_use]
pub fn runtime_provider_count(&self) -> usize {
self.runtime_providers.len()
}
#[must_use]
pub fn secret_provider_count(&self) -> usize {
self.secret_providers.len()
}
}
impl Default for ProviderRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::providers::{CiProvider, CodegenProvider, RulesProvider};
#[test]
fn test_empty_registry() {
let registry = ProviderRegistry::new();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
}
#[test]
fn test_sync_provider_names() {
let registry = ProviderRegistry::new();
let names = registry.sync_provider_names();
assert!(names.is_empty());
}
#[test]
fn test_register_and_retrieve_sync_provider() {
let mut registry = ProviderRegistry::new();
registry.register_sync(CiProvider::new());
assert_eq!(registry.sync_provider_count(), 1);
assert!(!registry.is_empty());
let provider = registry.get_sync_provider("ci");
assert!(provider.is_some());
assert_eq!(provider.unwrap().name(), "ci");
}
#[test]
fn test_get_nonexistent_provider() {
let registry = ProviderRegistry::new();
assert!(registry.get_sync_provider("nonexistent").is_none());
assert!(registry.get_runtime_provider("nonexistent").is_none());
assert!(registry.get_secret_provider("nonexistent").is_none());
}
#[test]
fn test_multiple_sync_providers() {
let mut registry = ProviderRegistry::new();
registry.register_sync(CiProvider::new());
registry.register_sync(CodegenProvider::new());
registry.register_sync(RulesProvider::new());
assert_eq!(registry.sync_provider_count(), 3);
assert_eq!(registry.len(), 3);
assert!(registry.get_sync_provider("ci").is_some());
assert!(registry.get_sync_provider("codegen").is_some());
assert!(registry.get_sync_provider("rules").is_some());
}
#[test]
fn test_sync_provider_names_returns_all() {
let mut registry = ProviderRegistry::new();
registry.register_sync(CiProvider::new());
registry.register_sync(CodegenProvider::new());
let names = registry.sync_provider_names();
assert_eq!(names.len(), 2);
assert!(names.contains(&"ci"));
assert!(names.contains(&"codegen"));
}
#[test]
fn test_sync_providers_iterator() {
let mut registry = ProviderRegistry::new();
registry.register_sync(CiProvider::new());
registry.register_sync(CodegenProvider::new());
let providers: Vec<_> = registry.sync_providers().collect();
assert_eq!(providers.len(), 2);
}
#[test]
fn test_capability_counts_are_independent() {
let mut registry = ProviderRegistry::new();
registry.register_sync(CiProvider::new());
registry.register_sync(CodegenProvider::new());
assert_eq!(registry.sync_provider_count(), 2);
assert_eq!(registry.runtime_provider_count(), 0);
assert_eq!(registry.secret_provider_count(), 0);
assert_eq!(registry.len(), 2);
}
#[test]
fn test_default_registry() {
let registry = ProviderRegistry::default();
assert!(registry.is_empty());
}
}