Skip to main content

ferrin_tool/
set.rs

1//! [`ToolSet`]: an insertion-ordered map of tool names to tools.
2
3use std::sync::Arc;
4
5use ferrin_spec::ToolName;
6use indexmap::IndexMap;
7
8use crate::error::DuplicateToolError;
9use crate::tool::Tool;
10
11/// Named tools available to a call. Insertion order is preserved; names are
12/// unique.
13#[derive(Debug, Clone, Default)]
14pub struct ToolSet {
15    tools: IndexMap<ToolName, Arc<Tool>>,
16}
17
18impl ToolSet {
19    /// An empty set.
20    #[must_use]
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    /// Adds a tool, consuming and returning the set.
26    ///
27    /// # Errors
28    ///
29    /// Returns [`DuplicateToolError`] when `name` is already present.
30    pub fn insert(
31        mut self,
32        name: impl Into<ToolName>,
33        tool: Tool,
34    ) -> Result<Self, DuplicateToolError> {
35        self.try_insert(name, tool)?;
36        Ok(self)
37    }
38
39    /// Adds a tool in place.
40    ///
41    /// # Errors
42    ///
43    /// Returns [`DuplicateToolError`] when `name` is already present.
44    pub fn try_insert(
45        &mut self,
46        name: impl Into<ToolName>,
47        tool: Tool,
48    ) -> Result<(), DuplicateToolError> {
49        self.try_insert_arc(name, Arc::new(tool))
50    }
51
52    /// Adds a shared tool in place.
53    ///
54    /// # Errors
55    ///
56    /// Returns [`DuplicateToolError`] when `name` is already present.
57    pub fn try_insert_arc(
58        &mut self,
59        name: impl Into<ToolName>,
60        tool: Arc<Tool>,
61    ) -> Result<(), DuplicateToolError> {
62        let name = name.into();
63        if self.tools.contains_key(&name) {
64            return Err(DuplicateToolError { name });
65        }
66        self.tools.insert(name, tool);
67        Ok(())
68    }
69
70    /// Inserts or replaces a tool, keeping its position when replacing.
71    pub fn replace(&mut self, name: impl Into<ToolName>, tool: Arc<Tool>) -> Option<Arc<Tool>> {
72        self.tools.insert(name.into(), tool)
73    }
74
75    /// Removes a tool, preserving the order of the others.
76    pub fn remove(&mut self, name: &str) -> Option<Arc<Tool>> {
77        self.tools.shift_remove(name)
78    }
79
80    /// Looks up a tool.
81    #[must_use]
82    pub fn get(&self, name: &str) -> Option<&Arc<Tool>> {
83        self.tools.get(name)
84    }
85
86    /// Returns `true` when `name` is present.
87    #[must_use]
88    pub fn contains(&self, name: &str) -> bool {
89        self.tools.contains_key(name)
90    }
91
92    /// Tool names in insertion order.
93    pub fn names(&self) -> impl Iterator<Item = &ToolName> + '_ {
94        self.tools.keys()
95    }
96
97    /// Tools in insertion order.
98    pub fn iter(&self) -> impl Iterator<Item = (&ToolName, &Arc<Tool>)> + '_ {
99        self.tools.iter()
100    }
101
102    /// Number of tools.
103    #[must_use]
104    pub fn len(&self) -> usize {
105        self.tools.len()
106    }
107
108    /// Returns `true` when the set has no tools.
109    #[must_use]
110    pub fn is_empty(&self) -> bool {
111        self.tools.is_empty()
112    }
113
114    /// Keeps only the named tools (order of this set). Unknown names are
115    /// ignored.
116    #[must_use]
117    pub fn filter_active(&self, active: &[ToolName]) -> Self {
118        Self {
119            tools: self
120                .tools
121                .iter()
122                .filter(|(name, _)| active.contains(name))
123                .map(|(name, tool)| (name.clone(), Arc::clone(tool)))
124                .collect(),
125        }
126    }
127
128    /// Merges another set into this one.
129    ///
130    /// # Errors
131    ///
132    /// Returns [`DuplicateToolError`] for the first name present in both.
133    pub fn merge(mut self, other: Self) -> Result<Self, DuplicateToolError> {
134        for (name, tool) in other.tools {
135            self.try_insert_arc(name, tool)?;
136        }
137        Ok(self)
138    }
139
140    /// Tools in sending order: names listed in `order` first (in that order),
141    /// the rest sorted alphabetically.
142    #[must_use]
143    pub fn ordered(&self, order: &[ToolName]) -> Vec<(&ToolName, &Arc<Tool>)> {
144        let mut listed: Vec<(&ToolName, &Arc<Tool>)> = order
145            .iter()
146            .filter_map(|name| self.tools.get_key_value(name))
147            .collect();
148        let mut rest: Vec<(&ToolName, &Arc<Tool>)> = self
149            .tools
150            .iter()
151            .filter(|(name, _)| !order.contains(name))
152            .collect();
153        rest.sort_by(|(a, _), (b, _)| a.as_str().cmp(b.as_str()));
154        listed.append(&mut rest);
155        listed
156    }
157}
158
159impl<'a> IntoIterator for &'a ToolSet {
160    type Item = (&'a ToolName, &'a Arc<Tool>);
161    type IntoIter = indexmap::map::Iter<'a, ToolName, Arc<Tool>>;
162
163    fn into_iter(self) -> Self::IntoIter {
164        self.tools.iter()
165    }
166}