1use anyhow::Result;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct PluginMetadata {
12 pub name: String,
13 pub version: String,
14 pub description: String,
15 pub author: Option<String>,
16 pub functions: Vec<FunctionMetadata>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct FunctionMetadata {
22 pub name: String,
23 pub description: String,
24 pub parameters: Vec<ParameterMetadata>,
25 pub return_type: String,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ParameterMetadata {
31 pub name: String,
32 pub param_type: String,
33 pub required: bool,
34 pub default: Option<String>,
35 pub description: Option<String>,
36}
37
38pub trait PluginFunction: Send + Sync {
40 fn name(&self) -> &str;
41 fn execute(&self, args: &[String], data: &[Vec<String>]) -> Result<Vec<Vec<String>>>;
42 fn metadata(&self) -> FunctionMetadata;
43}
44
45pub struct PluginRegistry {
47 plugins: HashMap<String, Box<dyn PluginFunction>>,
48 metadata: HashMap<String, PluginMetadata>,
49}
50
51impl PluginRegistry {
52 pub fn new() -> Self {
53 Self {
54 plugins: HashMap::new(),
55 metadata: HashMap::new(),
56 }
57 }
58
59 pub fn register<F>(&mut self, function: F)
61 where
62 F: PluginFunction + 'static,
63 {
64 let name = function.name().to_string();
65 let func_metadata = function.metadata();
66
67 let plugin_meta = self
69 .metadata
70 .entry(name.clone())
71 .or_insert_with(|| PluginMetadata {
72 name: name.clone(),
73 version: "1.0.0".to_string(),
74 description: format!("Plugin: {}", name),
75 author: None,
76 functions: Vec::new(),
77 });
78
79 plugin_meta.functions.push(func_metadata);
80 self.plugins.insert(name, Box::new(function));
81 }
82
83 pub fn execute(
85 &self,
86 function_name: &str,
87 args: &[String],
88 data: &[Vec<String>],
89 ) -> Result<Vec<Vec<String>>> {
90 let function = self
91 .plugins
92 .get(function_name)
93 .ok_or_else(|| anyhow::anyhow!("Plugin function '{}' not found", function_name))?;
94
95 function.execute(args, data)
96 }
97
98 pub fn list_plugins(&self) -> Vec<&PluginMetadata> {
100 self.metadata.values().collect()
101 }
102
103 pub fn get_metadata(&self, name: &str) -> Option<&PluginMetadata> {
105 self.metadata.get(name)
106 }
107}
108
109pub struct UppercasePlugin;
111
112impl PluginFunction for UppercasePlugin {
113 fn name(&self) -> &str {
114 "uppercase"
115 }
116
117 fn execute(&self, args: &[String], data: &[Vec<String>]) -> Result<Vec<Vec<String>>> {
118 if args.is_empty() {
119 anyhow::bail!("Column index required");
120 }
121
122 let col_idx: usize = args[0]
123 .parse()
124 .map_err(|_| anyhow::anyhow!("Invalid column index: {}", args[0]))?;
125
126 let mut result = data.to_vec();
127
128 for row in result.iter_mut().skip(1) {
129 if let Some(cell) = row.get_mut(col_idx) {
131 *cell = cell.to_uppercase();
132 }
133 }
134
135 Ok(result)
136 }
137
138 fn metadata(&self) -> FunctionMetadata {
139 FunctionMetadata {
140 name: "uppercase".to_string(),
141 description: "Convert column values to uppercase".to_string(),
142 parameters: vec![ParameterMetadata {
143 name: "column".to_string(),
144 param_type: "usize".to_string(),
145 required: true,
146 default: None,
147 description: Some("Column index to transform".to_string()),
148 }],
149 return_type: "Vec<Vec<String>>".to_string(),
150 }
151 }
152}
153
154pub struct PrefixPlugin;
156
157impl PluginFunction for PrefixPlugin {
158 fn name(&self) -> &str {
159 "prefix"
160 }
161
162 fn execute(&self, args: &[String], data: &[Vec<String>]) -> Result<Vec<Vec<String>>> {
163 if args.len() < 2 {
164 anyhow::bail!("Column index and prefix required");
165 }
166
167 let col_idx: usize = args[0]
168 .parse()
169 .map_err(|_| anyhow::anyhow!("Invalid column index: {}", args[0]))?;
170 let prefix = &args[1];
171
172 let mut result = data.to_vec();
173
174 for row in result.iter_mut().skip(1) {
175 if let Some(cell) = row.get_mut(col_idx) {
177 *cell = format!("{}{}", prefix, cell);
178 }
179 }
180
181 Ok(result)
182 }
183
184 fn metadata(&self) -> FunctionMetadata {
185 FunctionMetadata {
186 name: "prefix".to_string(),
187 description: "Add prefix to column values".to_string(),
188 parameters: vec![
189 ParameterMetadata {
190 name: "column".to_string(),
191 param_type: "usize".to_string(),
192 required: true,
193 default: None,
194 description: Some("Column index to transform".to_string()),
195 },
196 ParameterMetadata {
197 name: "prefix".to_string(),
198 param_type: "String".to_string(),
199 required: true,
200 default: None,
201 description: Some("Prefix to add".to_string()),
202 },
203 ],
204 return_type: "Vec<Vec<String>>".to_string(),
205 }
206 }
207}
208
209impl Default for PluginRegistry {
210 fn default() -> Self {
211 let mut registry = Self::new();
212
213 registry.register(UppercasePlugin);
215 registry.register(PrefixPlugin);
216
217 registry
218 }
219}