use crate::error::Error;
use crate::types::Value;
use std::collections::HashMap;
pub trait CustomFunction: Send + Sync {
fn execute(&self, args: &[Value]) -> Result<Value, Error>;
fn name(&self) -> &str;
fn description(&self) -> &str {
"Custom function"
}
fn arity(&self) -> Option<usize> {
None
}
fn validate_args(&self, args: &[Value]) -> Result<(), Error> {
if let Some(expected) = self.arity() {
if args.len() != expected {
return Err(Error::new(
format!("{} expects {} arguments, got {}",
self.name(), expected, args.len()),
None,
));
}
}
Ok(())
}
}
pub trait TypeConverter: Send + Sync {
fn convert(&self, value: Value) -> Result<Value, Error>;
fn target_type(&self) -> &str;
fn can_convert(&self, value: &Value) -> bool;
}
pub trait VariableResolver: Send + Sync {
fn resolve(&self, name: &str) -> Result<Option<Value>, Error>;
fn has_variable(&self, name: &str) -> bool;
fn get_all_variables(&self) -> HashMap<String, Value>;
}
pub trait MethodHandler: Send + Sync {
fn can_handle(&self, value: &Value, method_name: &str) -> bool;
fn execute_method(
&self,
value: &Value,
method_name: &str,
args: &[Value],
) -> Result<Value, Error>;
fn supported_methods(&self, value: &Value) -> Vec<&str>;
}
pub trait ExpressionEvaluator: Send + Sync {
fn evaluate(&self, expr: &crate::ast::Expr, context: &dyn EvaluationContext) -> Result<Value, Error>;
}
pub trait EvaluationContext: Send + Sync {
fn get_variable(&self, name: &str) -> Option<&Value>;
fn set_variable(&mut self, _name: String, _value: Value) -> Result<(), Error> {
Err(Error::new("Context does not support variable assignment", None))
}
fn get_custom_registry(&self) -> Option<&std::sync::Arc<std::sync::RwLock<crate::custom::FunctionRegistry>>>;
fn clone_variables(&self) -> HashMap<String, Value>;
fn get_resolver(&self) -> Option<&dyn VariableResolver> {
None
}
}
pub trait DataSource: Send + Sync {
fn fetch(&self, key: &str) -> Result<Value, Error>;
fn exists(&self, key: &str) -> bool;
fn name(&self) -> &str;
fn refresh(&mut self) -> Result<(), Error> {
Ok(())
}
}
pub struct ExtensionRegistry {
custom_functions: HashMap<String, Box<dyn CustomFunction>>,
type_converters: HashMap<String, Box<dyn TypeConverter>>,
method_handlers: Vec<Box<dyn MethodHandler>>,
data_sources: HashMap<String, Box<dyn DataSource>>,
}
impl ExtensionRegistry {
pub fn new() -> Self {
Self {
custom_functions: HashMap::new(),
type_converters: HashMap::new(),
method_handlers: Vec::new(),
data_sources: HashMap::new(),
}
}
pub fn register_function(&mut self, func: Box<dyn CustomFunction>) {
self.custom_functions.insert(func.name().to_string(), func);
}
pub fn register_converter(&mut self, converter: Box<dyn TypeConverter>) {
self.type_converters.insert(converter.target_type().to_string(), converter);
}
pub fn register_method_handler(&mut self, handler: Box<dyn MethodHandler>) {
self.method_handlers.push(handler);
}
pub fn register_data_source(&mut self, source: Box<dyn DataSource>) {
self.data_sources.insert(source.name().to_string(), source);
}
pub fn get_function(&self, name: &str) -> Option<&dyn CustomFunction> {
self.custom_functions.get(name).map(|f| f.as_ref())
}
pub fn get_converter(&self, target_type: &str) -> Option<&dyn TypeConverter> {
self.type_converters.get(target_type).map(|c| c.as_ref())
}
pub fn find_method_handler(&self, value: &Value, method_name: &str) -> Option<&dyn MethodHandler> {
self.method_handlers
.iter()
.find(|h| h.can_handle(value, method_name))
.map(|h| h.as_ref())
}
pub fn get_data_source(&self, name: &str) -> Option<&dyn DataSource> {
self.data_sources.get(name).map(|d| d.as_ref())
}
}
impl Default for ExtensionRegistry {
fn default() -> Self {
Self::new()
}
}
pub struct MemoryVariableResolver {
variables: HashMap<String, Value>,
}
impl MemoryVariableResolver {
pub fn new(variables: HashMap<String, Value>) -> Self {
Self { variables }
}
}
impl VariableResolver for MemoryVariableResolver {
fn resolve(&self, name: &str) -> Result<Option<Value>, Error> {
Ok(self.variables.get(name).cloned())
}
fn has_variable(&self, name: &str) -> bool {
self.variables.contains_key(name)
}
fn get_all_variables(&self) -> HashMap<String, Value> {
self.variables.clone()
}
}
pub struct ConstantDataSource {
name: String,
data: HashMap<String, Value>,
}
impl ConstantDataSource {
pub fn new(name: String, data: HashMap<String, Value>) -> Self {
Self { name, data }
}
}
impl DataSource for ConstantDataSource {
fn fetch(&self, key: &str) -> Result<Value, Error> {
self.data
.get(key)
.cloned()
.ok_or_else(|| Error::new(format!("Key '{}' not found in data source '{}'", key, self.name), None))
}
fn exists(&self, key: &str) -> bool {
self.data.contains_key(key)
}
fn name(&self) -> &str {
&self.name
}
}