use std::sync::Arc;
use ferrin_spec::ToolName;
use indexmap::IndexMap;
use crate::error::DuplicateToolError;
use crate::tool::Tool;
#[derive(Debug, Clone, Default)]
pub struct ToolSet {
tools: IndexMap<ToolName, Arc<Tool>>,
}
impl ToolSet {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn insert(
mut self,
name: impl Into<ToolName>,
tool: Tool,
) -> Result<Self, DuplicateToolError> {
self.try_insert(name, tool)?;
Ok(self)
}
pub fn try_insert(
&mut self,
name: impl Into<ToolName>,
tool: Tool,
) -> Result<(), DuplicateToolError> {
self.try_insert_arc(name, Arc::new(tool))
}
pub fn try_insert_arc(
&mut self,
name: impl Into<ToolName>,
tool: Arc<Tool>,
) -> Result<(), DuplicateToolError> {
let name = name.into();
if self.tools.contains_key(&name) {
return Err(DuplicateToolError { name });
}
self.tools.insert(name, tool);
Ok(())
}
pub fn replace(&mut self, name: impl Into<ToolName>, tool: Arc<Tool>) -> Option<Arc<Tool>> {
self.tools.insert(name.into(), tool)
}
pub fn remove(&mut self, name: &str) -> Option<Arc<Tool>> {
self.tools.shift_remove(name)
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&Arc<Tool>> {
self.tools.get(name)
}
#[must_use]
pub fn contains(&self, name: &str) -> bool {
self.tools.contains_key(name)
}
pub fn names(&self) -> impl Iterator<Item = &ToolName> + '_ {
self.tools.keys()
}
pub fn iter(&self) -> impl Iterator<Item = (&ToolName, &Arc<Tool>)> + '_ {
self.tools.iter()
}
#[must_use]
pub fn len(&self) -> usize {
self.tools.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.tools.is_empty()
}
#[must_use]
pub fn filter_active(&self, active: &[ToolName]) -> Self {
Self {
tools: self
.tools
.iter()
.filter(|(name, _)| active.contains(name))
.map(|(name, tool)| (name.clone(), Arc::clone(tool)))
.collect(),
}
}
pub fn merge(mut self, other: Self) -> Result<Self, DuplicateToolError> {
for (name, tool) in other.tools {
self.try_insert_arc(name, tool)?;
}
Ok(self)
}
#[must_use]
pub fn ordered(&self, order: &[ToolName]) -> Vec<(&ToolName, &Arc<Tool>)> {
let mut listed: Vec<(&ToolName, &Arc<Tool>)> = order
.iter()
.filter_map(|name| self.tools.get_key_value(name))
.collect();
let mut rest: Vec<(&ToolName, &Arc<Tool>)> = self
.tools
.iter()
.filter(|(name, _)| !order.contains(name))
.collect();
rest.sort_by(|(a, _), (b, _)| a.as_str().cmp(b.as_str()));
listed.append(&mut rest);
listed
}
}
impl<'a> IntoIterator for &'a ToolSet {
type Item = (&'a ToolName, &'a Arc<Tool>);
type IntoIter = indexmap::map::Iter<'a, ToolName, Arc<Tool>>;
fn into_iter(self) -> Self::IntoIter {
self.tools.iter()
}
}