use interoptopus::lang::plugin::PluginLoadError;
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
pub struct PluginCache {
plugins: HashMap<(TypeId, PathBuf), Box<dyn Any + Send + Sync>>,
path_to_type: HashMap<PathBuf, TypeId>,
}
impl PluginCache {
pub fn new() -> Self {
Self { plugins: HashMap::new(), path_to_type: HashMap::new() }
}
pub fn check_uniqueness<T: 'static>(&self, path: &Path) -> Result<(), PluginLoadError> {
let type_id = TypeId::of::<T>();
if let Some(existing_type) = self.path_to_type.get(path)
&& *existing_type != type_id
{
return Err(PluginLoadError::load_failed(format!("DLL {} already loaded for a different plugin type", path.display())));
}
Ok(())
}
pub fn get_cached<T: Send + Sync + 'static>(&self, path: &Path) -> Option<Arc<T>> {
let key = (TypeId::of::<T>(), path.to_path_buf());
self.plugins.get(&key).map(|boxed| {
let arc = boxed.downcast_ref::<Arc<T>>().expect("type mismatch in plugin cache");
Arc::clone(arc)
})
}
pub fn insert<T: Send + Sync + 'static>(&mut self, path: PathBuf, arc: Arc<T>) {
let type_id = TypeId::of::<T>();
self.path_to_type.insert(path.clone(), type_id);
self.plugins.insert((type_id, path), Box::new(arc));
}
}
pub struct HandlerShim {
pub handler: Arc<dyn Fn(String) + Send + Sync>,
}
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn uncaught_exception_callback(ctx: *const u8, message: *const u8, len: i32) {
let shim = unsafe { &*ctx.cast::<HandlerShim>() };
let bytes = unsafe { std::slice::from_raw_parts(message, len.unsigned_abs() as usize) };
let msg = String::from_utf8_lossy(bytes).into_owned();
(shim.handler)(msg);
}