mod operation_walker; pub mod plugin; use std::{collections::HashMap, sync::Arc}; use anyhow::Error; use dlopen2::wrapper::Container; use giterated_abi::{ callback::{ operation::OperationHandlerCallback, setting::{SettingChangeCallback, SettingGetterCallback}, value::{ValueChangeCallback, ValueGetterCallback}, CallbackPtr, }, plugin::GiteratedPluginAbi, vtable::{operation::Operation, plugin::Plugin, Object, Setting, VTable, Value}, }; use giterated_core::types::TypeMetadata; use giterated_models::{ error::OperationError, object::{GiteratedObject, ObjectOperationPair}, operation::GiteratedOperation, settings::ObjectSettingPair, value::ObjectValuePair, }; use operation_walker::OperationHandlerRules; use plugin::initialization::PluginInitializationState; use tracing::{debug, debug_span, trace, trace_span, warn}; pub use giterated_abi::vtable::runtime::RuntimeHandle; pub struct Runtime { plugins: Vec, handlers: RuntimeHandlers, } #[derive(Clone)] pub struct RuntimePlugin { vtable: &'static VTable, library: Arc>, } impl RuntimePlugin { pub fn name(&self) -> &'static str { todo!() } pub fn version(&self) -> &'static str { todo!() } pub fn metadata(&self) -> &TypeMetadata { todo!() } } impl Runtime { pub fn new() -> Box { Box::new(Self { plugins: vec![], handlers: RuntimeHandlers::default(), }) } pub fn state(self: &Box) -> RuntimeHandle { RuntimeHandle } pub fn load_dylib(&mut self, path: impl AsRef) -> Result<(), Error> { let path = path.as_ref(); let _guard = debug_span!("loading dylib", path = debug(path)).entered(); let library: Container = unsafe { Container::load(path) }?; let vtable = unsafe { library.__get_plugin_vtable() }; self.plugins.push(RuntimePlugin { vtable, library: Arc::new(library), }); Ok(()) } pub fn insert_plugin( &mut self, plugin: RuntimePlugin, mut initialization: PluginInitializationState, ) { let _guard = debug_span!("inserting plugin", meta = debug(&plugin.name())).entered(); for (pair, callback) in initialization.operation_handlers.drain() { let _guard = trace_span!("processing operation handler callbacks", pair = debug(pair)).entered(); if self .handlers .operation_handlers .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback)) .is_some() { warn!("Warning! Insertion of handler for overwrote a previous handler.") } trace!("Insertion of operation handler successful") } for (pair, callback) in initialization.value_getters.drain() { let _guard = trace_span!("processing value getter callbacks", pair = debug(pair)).entered(); if self .handlers .value_getters .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback)) .is_some() { warn!("Warning! Insertion of handler for overwrote a previous handler.") } trace!("Insertion of operation handler successful") } for (pair, callback) in initialization.setting_getters { let _guard = trace_span!("processing setting getter callbacks", pair = debug(pair)).entered(); if self .handlers .setting_getters .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback)) .is_some() { warn!("Warning! Insertion of setting handler for overwrote a previous handler.") } trace!("Insertion of setting handler successful") } self.plugins.push(plugin); } pub fn init(self: Box) { todo!() // unsafe { giterated_static_runtime::initialize_runtime(Box::into_raw(self).cast::<()>()) } } // pub async fn handle( // &self, // object_kind: &str, // operation_name: &str, // object: &str, // operation_payload: &[u8], // operation_state: &OperationState, // ) -> Result> { // let rules = self.handlers.handle_operation(object_kind, operation_name); // let state = self.state(operation_state); // rules.handle(&state, object, operation_payload).await // } pub fn handle_typed>( &self, _object: O, _operation: D, ) -> Result> { todo!() } } pub struct RuntimeDomain { plugin: RuntimePlugin, } impl RuntimeDomain { pub fn from_plugin(plugin: &RuntimePlugin) -> Self { Self { plugin: plugin.clone(), } } pub fn object_vtable(&self, object_kind: &str) -> Option<&'static VTable> { self.plugin.metadata().objects.get(object_kind).copied() } pub fn operation_vtable( &self, object_kind: &str, operation_name: &str, ) -> Option<&'static VTable> { self.plugin .metadata() .operations .get(&ObjectOperationPair::new(object_kind, operation_name)) .copied() } pub fn setting_vtable( &self, object_kind: &str, setting_name: &str, ) -> Option<&'static VTable> { self.plugin .metadata() .settings .get(&ObjectSettingPair::new(object_kind, setting_name)) .copied() } pub fn value_vtable( &self, object_kind: &str, value_name: &str, ) -> Option<&'static VTable> { self.plugin .metadata() .values .get(&ObjectValuePair::new(object_kind, value_name)) .copied() } } #[repr(C)] pub struct FFIPluginMeta { pub name: *const u8, pub name_len: usize, pub version: *const u8, pub version_len: usize, } // pub struct RuntimePlugin { // handle: PluginHandle, // type_metadata: Arc, // } impl RuntimePlugin { // pub fn plugin_meta(&self) -> PluginMeta { // let meta = unsafe { self.handle.raw.plugin_meta() }; // let name = unsafe { std::slice::from_raw_parts(meta.name, meta.name_len) }; // let version = unsafe { std::slice::from_raw_parts(meta.version, meta.version_len) }; // let name = std::str::from_utf8(name).unwrap(); // let version = std::str::from_utf8(version).unwrap(); // PluginMeta { // name: String::from(name), // version: Version::parse(version).unwrap(), // } // } } // #[derive(WrapperApi)] // pub struct GiteratedPluginApi { // plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta, // load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable), // load_initialization_vtable: unsafe extern "C" fn(vtable: &'static VTable), // initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState, // initialize_registration: unsafe extern "C" fn( // init_state: *mut PluginInitializationState, // ) -> *mut PluginInitializationState, // load_type_metadata: unsafe extern "C" fn(metadata: *mut ()), // } #[derive(Default)] pub struct RuntimeHandlers { operation_handlers: HashMap< ObjectOperationPair<'static>, (RuntimeDomain, CallbackPtr), >, value_getters: HashMap, (RuntimeDomain, CallbackPtr)>, setting_getters: HashMap, (RuntimeDomain, CallbackPtr)>, value_change: HashMap, (RuntimeDomain, CallbackPtr)>, setting_change: HashMap, (RuntimeDomain, CallbackPtr)>, } unsafe impl Send for RuntimeHandlers {} unsafe impl Sync for RuntimeHandlers {} impl RuntimeHandlers { pub fn operation_handler( &mut self, pair: ObjectOperationPair<'static>, handler: CallbackPtr, domain: RuntimeDomain, ) { trace!( "Inserting operation handler for {}::{}", pair.object_kind, pair.operation_name ); // There can only be one handler per operation (at least for now?), send a warning if // a newly registered handler overwrites the previous handler. if self .operation_handlers .insert(pair, (domain, handler)) .is_some() { debug!("Warning! A newly inserted operation handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.operation_name); } } pub fn value_getter( &mut self, pair: ObjectValuePair<'static>, handler: CallbackPtr, domain: RuntimeDomain, ) { trace!( "Inserting value getter for {}::{}", pair.object_kind, pair.value_name ); if self.value_getters.insert(pair, (domain, handler)).is_some() { debug!( "Warning! A newly inserted value getter for {}::{} overwrites a previous handler.", pair.object_kind, pair.value_name ); } } pub fn setting_getter( &mut self, pair: ObjectSettingPair<'static>, handler: CallbackPtr, domain: RuntimeDomain, ) { trace!( "Inserting setting getter for {}::{}", pair.object_kind, pair.setting_name ); if self .setting_getters .insert(pair, (domain, handler)) .is_some() { debug!("Warning! A newly inserted setting getter for {}::{} overwrites a previous handler.", pair.object_kind, pair.setting_name); } } pub fn value_change( &mut self, pair: ObjectValuePair<'static>, handler: CallbackPtr, domain: RuntimeDomain, ) { trace!( "Inserting value change handler for {}::{}", pair.object_kind, pair.value_name ); if self.value_change.insert(pair, (domain, handler)).is_some() { debug!("Warning! A newly inserted value change handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.value_name); panic!("Not intended"); } } pub fn setting_change( &mut self, pair: ObjectSettingPair<'static>, handler: CallbackPtr, domain: RuntimeDomain, ) { trace!( "Inserting setting change handler for {}::{}", pair.object_kind, pair.setting_name ); if self .setting_change .insert(pair, (domain, handler)) .is_some() { debug!("Warning! A newly inserted setting change handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.setting_name); panic!("Not intended"); } } } impl RuntimeHandlers { pub fn handle_operation<'o>( &'o self, object_kind: &'o str, operation_name: &'o str, ) -> OperationHandlerRules<'o> { OperationHandlerRules::new(object_kind, operation_name, self) } } pub trait StaticRuntimeExt { fn from_static() -> Self; } impl StaticRuntimeExt for RuntimeHandle { fn from_static() -> Self { todo!() } }