synapto_interface/
command.rs1#![doc = include_str!("command.md")]
2
3use crate::llm::LLMSafe;
4
5#[async_trait::async_trait]
6pub trait Command: Send + Sync + 'static {
7 type Arguments: schemars::JsonSchema
8 + serde::de::DeserializeOwned
9 + LLMSafe
10 + Send
11 + Sync
12 + 'static;
13 const NAME: &'static str;
14 async fn execute(&self, args: Self::Arguments) -> Result<(), String>;
15}
16
17#[async_trait::async_trait]
18pub trait ErasedCommand: Send + Sync + 'static {
19 fn name(&self) -> &'static str;
20 fn schema(&self) -> schemars::Schema;
21 async fn erased_execute(&self, args: serde_json::Value) -> Result<(), String>;
22}
23
24#[async_trait::async_trait]
25impl<T> ErasedCommand for T
26where
27 T: Command,
28{
29 fn name(&self) -> &'static str {
30 <T as Command>::NAME
31 }
32 fn schema(&self) -> schemars::Schema {
33 schemars::schema_for!(<T as Command>::Arguments)
34 }
35 async fn erased_execute(&self, args: serde_json::Value) -> Result<(), String> {
36 let parsed_args = serde_json::from_value(args).map_err(|e| e.to_string())?;
37 <T as Command>::execute(self, parsed_args).await
38 }
39}
40
41#[derive(Default)]
42pub struct CommandRegistryBuilder {
43 pub commands:
44 std::sync::RwLock<std::collections::HashMap<String, std::sync::Arc<dyn ErasedCommand>>>,
45}
46
47impl CommandRegistryBuilder {
48 pub fn register<T>(&self, command: T)
49 where
50 T: ErasedCommand + 'static,
51 {
52 let command_arc: std::sync::Arc<dyn ErasedCommand> = std::sync::Arc::new(command);
53 self.register_erased(command_arc);
54 }
55 pub fn register_erased(&self, command: std::sync::Arc<dyn ErasedCommand>) {
56 self.commands
57 .write()
58 .unwrap_or_else(|e| panic!("Failed to acquire write lock on commands: {:?}", e))
59 .insert(command.name().to_string(), command);
60 }
61}