pub mod callback; pub mod handle; pub mod new_stack; pub mod vtable; #[macro_use] extern crate tracing; use std::{any::Any, fmt::Debug, mem::transmute, ptr::null_mut, sync::Arc}; use callback::{OperationHandlerCallback, SettingGetterCallback, ValueGetterCallback}; use dlopen2::wrapper::WrapperApi; use giterated_models::{ object::GiteratedObject, operation::GiteratedOperation, settings::Setting, value::GiteratedObjectValue, }; use handle::PluginInitializationState; use new_stack::{FFIPluginMeta, PluginState}; #[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: &InitializationVTable), initialize: unsafe extern "C" fn() -> PluginState, initialize_registration: unsafe extern "C" fn( init_state: *mut PluginInitializationState, ) -> *mut PluginInitializationState, } #[repr(C)] pub struct FFIBox(*mut T); impl FFIBox { pub fn from_box(src: Box) -> Self { Self(Box::into_raw(src)) } pub fn untyped(self) -> FFIBox<()> { FFIBox(self.0 as *mut ()) } } #[repr(C)] pub struct FFIObject(&'static str); #[repr(C)] struct FFIOperationHandler( for<'a> unsafe extern "C" fn(operation: FFIOperation<'a>) -> Result, FFIBox<[u8]>>, ); #[repr(C)] struct FFIOperation<'a> { operation_name: &'a str, object_name: &'a str, object: FFIObject, operation: &'a [u8], } #[derive(Clone, Copy)] #[repr(C)] pub struct OperationVTable { pub serialize: unsafe extern "C" fn(AnyObject) -> Result, ()>, pub deserialize: unsafe extern "C" fn(&[u8]) -> Result, pub is_same: unsafe extern "C" fn(AnyObject) -> bool, pub serialize_success: unsafe extern "C" fn(()) -> Result, ()>, pub serialize_failure: unsafe extern "C" fn(()) -> Result, ()>, pub deserialize_success: unsafe extern "C" fn(&[u8]) -> Result<(), ()>, pub deserialize_failure: unsafe extern "C" fn(&[u8]) -> Result<(), ()>, } impl OperationVTable { pub fn new>() -> Self { Self { serialize: T::serialize, deserialize: T::deserialize, is_same: T::is_same, serialize_success: T::serialize_success, serialize_failure: T::serialize_failure, deserialize_success: T::deserialize_success, deserialize_failure: T::deserialize_failure, } } } pub struct AnyOperation { /// A pointer to the plugin-local object type. We are not capable of /// knowing what this type is, we use the provided vtable. inner: FFIBox<()>, vtable: OperationVTable, } impl AnyOperation { pub unsafe fn transmute_owned(&mut self) -> Box { Box::from_raw(self.inner.0 as *mut T) } pub unsafe fn transmute_ref(&self) -> &T { let ptr: *const T = transmute(self.inner.0); ptr.as_ref().unwrap() } } #[repr(C)] pub struct FFIValueChangeHandler(); #[derive(Clone, Copy)] #[repr(C)] pub struct ObjectVtable { pub to_str: unsafe extern "C" fn(AnyObject) -> FFIBox, pub from_str: unsafe extern "C" fn(&str) -> Result>, pub home_uri: unsafe extern "C" fn(AnyObject) -> FFIBox, pub is_same: unsafe extern "C" fn(AnyObject) -> bool, } impl ObjectVtable { pub const fn new() -> Self { Self { to_str: T::to_str, from_str: T::from_str, home_uri: T::home_uri, is_same: T::is_same, } } } #[repr(C)] pub struct NewAnySetting { /// A pointer to the plugin-local object type. We are not capable of /// knowing what this type is, we use the provided vtable. inner: FFIBox<()>, vtable: SettingVtable, } impl NewAnySetting { pub fn new(value: V) -> Self { Self { inner: FFIBox::from_box(Box::new(value)).untyped(), vtable: SettingVtable::new::(), } } } #[derive(Clone, Copy)] #[repr(C)] pub struct SettingVtable { pub deserialize: unsafe extern "C" fn(&[u8]) -> Result<(), ()>, pub serialize: unsafe extern "C" fn(NewAnySetting) -> Result, ()>, } impl SettingVtable { pub fn new() -> Self { Self { deserialize: T::deserialize, serialize: T::serialize, } } } #[repr(C)] pub struct NewAnyValue { /// A pointer to the plugin-local object type. We are not capable of /// knowing what this type is, we use the provided vtable. inner: FFIBox<()>, vtable: ValueVTable, } impl NewAnyValue { pub fn new>(value: V) -> Self { NewAnyValue { inner: FFIBox::from_box(Box::new(value)).untyped(), vtable: ValueVTable::new::(), } } } #[derive(Clone, Copy)] #[repr(C)] pub struct ValueVTable { pub deserialize: unsafe extern "C" fn(&[u8]) -> Result, pub serialize: unsafe extern "C" fn(NewAnyValue) -> Result, ()>, } impl ValueVTable { pub fn new>() -> Self { Self { deserialize: T::deserialize, serialize: T::serialize, } } } pub trait IntoObjectVTable { unsafe extern "C" fn to_str(this: AnyObject) -> FFIBox; unsafe extern "C" fn from_str(src: &str) -> Result>; unsafe extern "C" fn home_uri(this: AnyObject) -> FFIBox; unsafe extern "C" fn is_same(other: AnyObject) -> bool; } impl IntoObjectVTable for T { unsafe extern "C" fn to_str(mut this: AnyObject) -> FFIBox { let this: &Box = this.transmute_ref(); let result = this.to_string(); FFIBox::from_box(result.into_boxed_str()) } unsafe extern "C" fn from_str(src: &str) -> Result> { let result = T::from_object_str(src).unwrap(); let any_object = AnyObject::new(result); Ok(any_object) } unsafe extern "C" fn home_uri(this: AnyObject) -> FFIBox { todo!() } unsafe extern "C" fn is_same(other: AnyObject) -> bool { todo!() } } pub trait IntoOperationVTable { unsafe extern "C" fn serialize(this: AnyObject) -> Result, ()>; unsafe extern "C" fn deserialize(src: &[u8]) -> Result; unsafe extern "C" fn is_same(this: AnyObject) -> bool; unsafe extern "C" fn serialize_success(success: ()) -> Result, ()>; unsafe extern "C" fn serialize_failure(failure: ()) -> Result, ()>; unsafe extern "C" fn deserialize_success(src: &[u8]) -> Result<(), ()>; unsafe extern "C" fn deserialize_failure(src: &[u8]) -> Result<(), ()>; } impl IntoOperationVTable for D where D: GiteratedOperation, O: GiteratedObject, { unsafe extern "C" fn serialize(this: AnyObject) -> Result, ()> { todo!() } unsafe extern "C" fn deserialize(src: &[u8]) -> Result { let deserialized: D = serde_json::from_slice(src).unwrap(); Ok(AnyOperation { inner: FFIBox::from_box(Box::new(deserialized)).untyped(), vtable: OperationVTable::new::(), }) } unsafe extern "C" fn is_same(this: AnyObject) -> bool { todo!() } unsafe extern "C" fn serialize_success(success: ()) -> Result, ()> { todo!() } unsafe extern "C" fn serialize_failure(failure: ()) -> Result, ()> { todo!() } unsafe extern "C" fn deserialize_success(src: &[u8]) -> Result<(), ()> { todo!() } unsafe extern "C" fn deserialize_failure(src: &[u8]) -> Result<(), ()> { todo!() } } pub trait IntoSettingVTable { unsafe extern "C" fn deserialize(src: &[u8]) -> Result<(), ()>; unsafe extern "C" fn serialize(this: NewAnySetting) -> Result, ()>; } impl IntoSettingVTable for S where S: Setting, { unsafe extern "C" fn deserialize(src: &[u8]) -> Result<(), ()> { todo!() } unsafe extern "C" fn serialize(this: NewAnySetting) -> Result, ()> { todo!() } } pub trait IntoValueVTable { unsafe extern "C" fn deserialize(src: &[u8]) -> Result; unsafe extern "C" fn serialize(this: NewAnyValue) -> Result, ()>; } impl IntoValueVTable for V where O: GiteratedObject, V: GiteratedObjectValue, { unsafe extern "C" fn deserialize(src: &[u8]) -> Result { let _guard = trace_span!( "deserialize value", object = O::object_name(), value = V::value_name() ); trace!("Deserializing"); let deserialized: V = serde_json::from_slice(src).unwrap(); Ok(NewAnyValue { inner: FFIBox::from_box(Box::new(deserialized)).untyped(), vtable: ValueVTable::new::(), }) } unsafe extern "C" fn serialize(this: NewAnyValue) -> Result, ()> { todo!() } } #[repr(C)] pub struct AnyObject { /// A pointer to the plugin-local object type. We are not capable of /// knowing what this type is, we use the provided vtable. inner: FFIBox<()>, vtable: ObjectVtable, } impl AnyObject { pub fn new(inner: T) -> Self { Self { inner: FFIBox::from_box(Box::new(inner)).untyped(), vtable: ObjectVtable::new::(), } } } impl AnyObject { pub unsafe fn transmute_owned(&mut self) -> Box { Box::from_raw(self.inner.0 as *mut T) } pub unsafe fn transmute_ref(&self) -> &T { let ptr: *const T = transmute(self.inner.0); ptr.as_ref().unwrap() } } #[repr(C)] pub struct FFISettingMeta(); #[repr(C)] pub struct FFIValueMeta(); #[repr(C)] pub struct HostVTable { register_operation: unsafe extern "C" fn(&str, &str, FFIOperationHandler), register_value_change: unsafe extern "C" fn(&str, &str, FFIValueChangeHandler), register_object: unsafe extern "C" fn(&str, ObjectVtable), register_setting: unsafe extern "C" fn(&str, &str, FFISettingMeta), register_value: unsafe extern "C" fn(&str, &str, FFIValueMeta), } #[repr(C)] #[derive(Clone, Copy)] pub struct InitializationVTable { pub register_value_change: unsafe extern "C" fn(*mut PluginInitializationState, &str, &str, FFIValueChangeHandler), pub register_object: unsafe extern "C" fn(*mut PluginInitializationState, &'static str, ObjectVtable), pub register_operation: unsafe extern "C" fn( *mut PluginInitializationState, &'static str, &'static str, OperationVTable, ), pub register_setting: unsafe extern "C" fn( *mut PluginInitializationState, &'static str, &'static str, SettingVtable, ), pub register_value: unsafe extern "C" fn( *mut PluginInitializationState, &'static str, &'static str, ValueVTable, ), pub operation_handler: unsafe extern "C" fn( *mut PluginInitializationState, &'static str, &'static str, OperationHandlerCallback, ), pub value_getter: unsafe extern "C" fn( *mut PluginInitializationState, &'static str, &'static str, ValueGetterCallback, ), pub setting_getter: unsafe extern "C" fn( *mut PluginInitializationState, &'static str, &'static str, SettingGetterCallback, ), } impl Debug for InitializationVTable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("InitializationVTable").finish() } } unsafe impl Sync for InitializationVTable {} unsafe impl Send for InitializationVTable {}