use std::collections::HashMap;
use std::path::Path;
use super::types::{BuiltInFn, BuiltInObject, PluginInfo};
use super::config::PluginConfig;
use crate::runner::std_lib::register_core_builtins;
#[derive(Debug)]
pub enum PluginError {
NotFound(String),
LoadError(String),
RegistrationError(String),
ConfigError(String),
ObjectNotFound(String),
MethodNotFound(String, String),
}
impl std::fmt::Display for PluginError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PluginError::NotFound(path) => write!(f, "Plugin not found: {}", path),
PluginError::LoadError(msg) => write!(f, "Plugin load error: {}", msg),
PluginError::RegistrationError(msg) => write!(f, "Plugin registration error: {}", msg),
PluginError::ConfigError(msg) => write!(f, "Plugin config error: {}", msg),
PluginError::ObjectNotFound(name) => write!(f, "Object not found: {}", name),
PluginError::MethodNotFound(obj, method) => {
write!(f, "Method not found: {}.{}", obj, method)
}
}
}
}
impl std::error::Error for PluginError {}
pub struct LoadedPlugin {
pub info: PluginInfo,
pub source: PluginSource,
}
pub enum PluginSource {
BuiltIn,
Native(String),
JavaScript(String),
}
pub struct BuiltInRegistry {
objects: HashMap<String, BuiltInObject>,
plugins: Vec<LoadedPlugin>,
overrides: HashMap<String, Vec<String>>,
}
impl BuiltInRegistry {
pub fn new() -> Self {
BuiltInRegistry {
objects: HashMap::new(),
plugins: Vec::new(),
overrides: HashMap::new(),
}
}
pub fn with_core() -> Self {
let mut registry = Self::new();
register_core_builtins(&mut registry);
registry.plugins.push(LoadedPlugin {
info: PluginInfo::new("core", "0.1.0")
.with_provides(vec![
"console".to_string(),
"Object".to_string(),
"Array".to_string(),
"String".to_string(),
"Number".to_string(),
"Math".to_string(),
"JSON".to_string(),
"Error".to_string(),
]),
source: PluginSource::BuiltIn,
});
registry
}
pub fn register_object(&mut self, obj: BuiltInObject) {
self.objects.insert(obj.name.clone(), obj);
}
pub fn get_object(&self, name: &str) -> Option<&BuiltInObject> {
self.objects.get(name)
}
pub fn get_object_mut(&mut self, name: &str) -> Option<&mut BuiltInObject> {
self.objects.get_mut(name)
}
pub fn override_method(
&mut self,
object: &str,
method: &str,
func: BuiltInFn,
) -> Result<(), PluginError> {
let obj = self
.objects
.get_mut(object)
.ok_or_else(|| PluginError::ObjectNotFound(object.to_string()))?;
obj.methods.insert(method.to_string(), func);
let key = format!("{}.{}", object, method);
self.overrides
.entry(key)
.or_insert_with(Vec::new)
.push("manual".to_string());
Ok(())
}
pub fn get_method(&self, object: &str, method: &str) -> Option<&BuiltInFn> {
self.objects
.get(object)
.and_then(|obj| obj.methods.get(method))
}
pub fn get_constructor(&self, object: &str) -> Option<&BuiltInFn> {
self.objects
.get(object)
.and_then(|obj| obj.constructor.as_ref())
}
pub fn has_object(&self, name: &str) -> bool {
self.objects.contains_key(name)
}
pub fn has_method(&self, object: &str, method: &str) -> bool {
self.objects
.get(object)
.map(|obj| obj.methods.contains_key(method))
.unwrap_or(false)
}
pub fn load_native_plugin(&mut self, path: &Path) -> Result<PluginInfo, PluginError> {
Err(PluginError::LoadError(format!(
"Native plugin loading not yet implemented: {}",
path.display()
)))
}
pub fn load_js_plugin(&mut self, path: &Path) -> Result<PluginInfo, PluginError> {
Err(PluginError::LoadError(format!(
"JavaScript plugin loading not yet implemented: {}",
path.display()
)))
}
pub fn load_from_config(&mut self, config_path: &Path) -> Result<(), PluginError> {
let config = PluginConfig::load(config_path)?;
for native_plugin in &config.native_plugins {
if native_plugin.enabled {
self.load_native_plugin(Path::new(&native_plugin.path))?;
}
}
for js_plugin in &config.js_plugins {
if js_plugin.enabled {
self.load_js_plugin(Path::new(&js_plugin.path))?;
}
}
Ok(())
}
pub fn object_names(&self) -> Vec<&String> {
self.objects.keys().collect()
}
pub fn loaded_plugins(&self) -> &[LoadedPlugin] {
&self.plugins
}
}
impl Default for BuiltInRegistry {
fn default() -> Self {
Self::with_core()
}
}