use std::collections::HashMap;
use std::sync::Arc;
use super::*;
#[derive(Clone)]
pub struct CapabilityRegistry {
capabilities: HashMap<String, Arc<dyn Capability>>,
index: everruns_capability::CapabilityIdIndex,
}
impl CapabilityRegistry {
pub fn new() -> Self {
Self {
capabilities: HashMap::new(),
index: everruns_capability::CapabilityIdIndex::new(),
}
}
pub fn register(&mut self, capability: impl Capability + 'static) {
self.register_arc(Arc::new(capability));
}
pub fn register_boxed(&mut self, capability: Box<dyn Capability>) {
self.register_arc(Arc::from(capability));
}
pub fn register_arc(&mut self, capability: Arc<dyn Capability>) {
let canonical = capability.id().to_string();
self.index
.insert_or_replace(canonical.clone(), &capability.aliases());
self.capabilities.insert(canonical, capability);
}
pub fn try_register_arc(
&mut self,
capability: Arc<dyn Capability>,
) -> Result<(), everruns_capability::CapabilityError> {
let canonical = capability.id().to_string();
self.index
.insert(canonical.clone(), &capability.aliases())?;
self.capabilities.insert(canonical, capability);
Ok(())
}
pub fn register_plugins<'a>(
&mut self,
plugins: impl IntoIterator<Item = &'a IntegrationPlugin>,
mut include: impl FnMut(&IntegrationPlugin) -> bool,
) {
for plugin in plugins {
if include(plugin) {
self.register_boxed((plugin.factory)());
}
}
}
pub fn get(&self, id: &str) -> Option<&Arc<dyn Capability>> {
self.capabilities.get(self.index.canonical_of(id)?)
}
pub fn canonical_id<'a>(&'a self, id: &'a str) -> Option<&'a str> {
self.index.canonical_of(id)
}
pub fn unregister(&mut self, id: &str) -> Option<Arc<dyn Capability>> {
let canonical = self.index.remove(id)?;
self.capabilities.remove(&canonical)
}
pub fn has(&self, id: &str) -> bool {
self.get(id).is_some()
}
pub fn list(&self) -> Vec<&Arc<dyn Capability>> {
self.capabilities.values().collect()
}
pub fn len(&self) -> usize {
self.capabilities.len()
}
pub fn is_empty(&self) -> bool {
self.capabilities.is_empty()
}
pub fn builder() -> CapabilityRegistryBuilder {
CapabilityRegistryBuilder::new()
}
pub fn blueprint(&self, id: &str) -> Option<AgentBlueprint> {
for cap in self.capabilities.values() {
for bp in cap.agent_blueprints() {
if bp.id == id {
return Some(bp);
}
}
}
None
}
pub fn blueprint_with_capability(&self, id: &str) -> Option<(String, AgentBlueprint)> {
for (capability_id, cap) in &self.capabilities {
for bp in cap.agent_blueprints() {
if bp.id == id {
return Some((capability_id.clone(), bp));
}
}
}
None
}
pub fn all_blueprints(&self) -> Vec<AgentBlueprint> {
self.capabilities
.values()
.flat_map(|cap| cap.agent_blueprints())
.collect()
}
}
impl Default for CapabilityRegistry {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for CapabilityRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ids: Vec<_> = self.capabilities.keys().collect();
f.debug_struct("CapabilityRegistry")
.field("capabilities", &ids)
.finish()
}
}
pub struct CapabilityRegistryBuilder {
registry: CapabilityRegistry,
}
impl CapabilityRegistryBuilder {
pub fn new() -> Self {
Self {
registry: CapabilityRegistry::new(),
}
}
pub fn capability(mut self, capability: impl Capability + 'static) -> Self {
self.registry.register(capability);
self
}
pub fn build(self) -> CapabilityRegistry {
self.registry
}
}
impl Default for CapabilityRegistryBuilder {
fn default() -> Self {
Self::new()
}
}