use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginMetadata {
pub name: String,
pub version: String,
pub description: String,
pub author: Option<String>,
pub functions: Vec<FunctionMetadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionMetadata {
pub name: String,
pub description: String,
pub parameters: Vec<ParameterMetadata>,
pub return_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterMetadata {
pub name: String,
pub param_type: String,
pub required: bool,
pub default: Option<String>,
pub description: Option<String>,
}
pub trait PluginFunction: Send + Sync {
fn name(&self) -> &str;
fn execute(&self, args: &[String], data: &[Vec<String>]) -> Result<Vec<Vec<String>>>;
fn metadata(&self) -> FunctionMetadata;
}
pub struct PluginRegistry {
plugins: HashMap<String, Box<dyn PluginFunction>>,
metadata: HashMap<String, PluginMetadata>,
}
impl PluginRegistry {
pub fn new() -> Self {
Self {
plugins: HashMap::new(),
metadata: HashMap::new(),
}
}
pub fn register<F>(&mut self, function: F)
where
F: PluginFunction + 'static,
{
let name = function.name().to_string();
let func_metadata = function.metadata();
let plugin_meta = self
.metadata
.entry(name.clone())
.or_insert_with(|| PluginMetadata {
name: name.clone(),
version: "1.0.0".to_string(),
description: format!("Plugin: {}", name),
author: None,
functions: Vec::new(),
});
plugin_meta.functions.push(func_metadata);
self.plugins.insert(name, Box::new(function));
}
pub fn execute(
&self,
function_name: &str,
args: &[String],
data: &[Vec<String>],
) -> Result<Vec<Vec<String>>> {
let function = self
.plugins
.get(function_name)
.ok_or_else(|| anyhow::anyhow!("Plugin function '{}' not found", function_name))?;
function.execute(args, data)
}
pub fn list_plugins(&self) -> Vec<&PluginMetadata> {
self.metadata.values().collect()
}
pub fn get_metadata(&self, name: &str) -> Option<&PluginMetadata> {
self.metadata.get(name)
}
}
pub struct UppercasePlugin;
impl PluginFunction for UppercasePlugin {
fn name(&self) -> &str {
"uppercase"
}
fn execute(&self, args: &[String], data: &[Vec<String>]) -> Result<Vec<Vec<String>>> {
if args.is_empty() {
anyhow::bail!("Column index required");
}
let col_idx: usize = args[0]
.parse()
.map_err(|_| anyhow::anyhow!("Invalid column index: {}", args[0]))?;
let mut result = data.to_vec();
for row in result.iter_mut().skip(1) {
if let Some(cell) = row.get_mut(col_idx) {
*cell = cell.to_uppercase();
}
}
Ok(result)
}
fn metadata(&self) -> FunctionMetadata {
FunctionMetadata {
name: "uppercase".to_string(),
description: "Convert column values to uppercase".to_string(),
parameters: vec![ParameterMetadata {
name: "column".to_string(),
param_type: "usize".to_string(),
required: true,
default: None,
description: Some("Column index to transform".to_string()),
}],
return_type: "Vec<Vec<String>>".to_string(),
}
}
}
pub struct PrefixPlugin;
impl PluginFunction for PrefixPlugin {
fn name(&self) -> &str {
"prefix"
}
fn execute(&self, args: &[String], data: &[Vec<String>]) -> Result<Vec<Vec<String>>> {
if args.len() < 2 {
anyhow::bail!("Column index and prefix required");
}
let col_idx: usize = args[0]
.parse()
.map_err(|_| anyhow::anyhow!("Invalid column index: {}", args[0]))?;
let prefix = &args[1];
let mut result = data.to_vec();
for row in result.iter_mut().skip(1) {
if let Some(cell) = row.get_mut(col_idx) {
*cell = format!("{}{}", prefix, cell);
}
}
Ok(result)
}
fn metadata(&self) -> FunctionMetadata {
FunctionMetadata {
name: "prefix".to_string(),
description: "Add prefix to column values".to_string(),
parameters: vec![
ParameterMetadata {
name: "column".to_string(),
param_type: "usize".to_string(),
required: true,
default: None,
description: Some("Column index to transform".to_string()),
},
ParameterMetadata {
name: "prefix".to_string(),
param_type: "String".to_string(),
required: true,
default: None,
description: Some("Prefix to add".to_string()),
},
],
return_type: "Vec<Vec<String>>".to_string(),
}
}
}
impl Default for PluginRegistry {
fn default() -> Self {
let mut registry = Self::new();
registry.register(UppercasePlugin);
registry.register(PrefixPlugin);
registry
}
}