use std::collections::HashMap;
use std::sync::Arc;
use crate::error::{Error, Result};
use crate::skills::skill::Skill;
#[derive(Clone, Default, Debug)]
pub struct SkillRegistry {
skills: Arc<HashMap<String, Arc<dyn Skill>>>,
}
impl SkillRegistry {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register(self, skill: Arc<dyn Skill>) -> Result<Self> {
let name = skill.name().to_owned();
if self.skills.contains_key(&name) {
return Err(Error::config(format!(
"SkillRegistry: skill {name:?} is already registered"
)));
}
let mut next = (*self.skills).clone();
next.insert(name, skill);
Ok(Self {
skills: Arc::new(next),
})
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&Arc<dyn Skill>> {
self.skills.get(name)
}
#[must_use]
pub fn has(&self, name: &str) -> bool {
self.skills.contains_key(name)
}
#[must_use]
pub fn len(&self) -> usize {
self.skills.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.skills.is_empty()
}
#[must_use]
pub fn summaries(&self) -> Vec<SkillSummary<'_>> {
let mut entries: Vec<&Arc<dyn Skill>> = self.skills.values().collect();
entries.sort_by_key(|s| s.name());
entries
.into_iter()
.map(|s| SkillSummary {
name: s.name(),
description: s.description(),
version: s.version(),
})
.collect()
}
#[must_use]
pub fn filter(&self, allowed: &[&str]) -> Self {
let mut next: HashMap<String, Arc<dyn Skill>> = HashMap::with_capacity(allowed.len());
for name in allowed {
if let Some(skill) = self.skills.get(*name) {
next.insert((*name).to_owned(), Arc::clone(skill));
}
}
Self {
skills: Arc::new(next),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SkillSummary<'a> {
pub name: &'a str,
pub description: &'a str,
pub version: Option<&'a str>,
}