pub struct Runtime { plugins: Vec, handlers: RuntimeHandlers, } pub struct FfiRuntimeMetadata { runtime: PluginState, } impl IntoRuntimeVtable for Runtime { unsafe extern "C" fn handle( _this: PluginState, _object_kind: FfiSliceRef, _operation_name: FfiSliceRef, _object: FfiSliceRef, _operation_payload: FfiSliceRef<[u8]>, _operation_state: FfiSliceRef<[u8]>, ) -> RuntimeFuture>> { todo!() } unsafe extern "C" fn get_object( this: PluginState, object_str: &str, operation_state: *mut OperationState, ) -> FfiResult> { let runtime_state = unsafe { RuntimeState::from_static() }; let type_metada = runtime_state .vtable .type_metadata .as_ref() .unwrap_or_else(|| { let runtime = this.transmute_ref::(); &runtime.plugins.first().unwrap().domain_metadata }); // for (object_type, object_vtable) in &type_metada.objects { // if let Ok(object) = (object_vtable.from_str)(object_str) { // return Ok(object); // } // } // Err(OperationError::Operation(ObjectRequestError::Invalid)) todo!() } } impl Runtime { pub fn new() -> Box { Box::new(Self { plugins: vec![], handlers: RuntimeHandlers::default(), }) } pub fn state(self: &Box) -> RuntimeState { RuntimeState { vtable: RuntimeVTable { runtime: PluginState::from(self), handle_fn: ::handle, get_object: ::get_object, type_metadata: unsafe { TypeMetadata::from_static() }, }, } } pub fn insert_plugin( &mut self, mut plugin: PluginHandle, mut initialization: PluginInitializationState, ) { let _guard = debug_span!("inserting plugin", meta = debug(&plugin.meta)).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) { 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!() } } #[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 struct RuntimeDomain { plugin: PluginHandle, } impl RuntimeDomain { pub fn from_plugin(plugin: &PluginHandle) -> Self { Self { plugin: plugin.clone(), } } pub fn object_vtable(&self, object_kind: &str) -> Option<&'static VTable> { self.plugin .domain_metadata .objects .get(object_kind) .copied() } pub fn operation_vtable( &self, object_kind: &str, operation_name: &str, ) -> Option<&'static VTable> { self.plugin .domain_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 .domain_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 .domain_metadata .values .get(&ObjectValuePair::new(object_kind, value_name)) .copied() } } #[derive(Clone, Debug)] pub struct PluginMeta { pub name: String, pub version: Version, } #[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 ()), }