use std::mem::transmute; use giterated_models::{object::GiteratedObject, operation::GiteratedOperation}; use crate::FFIBox; #[derive(Clone, Copy)] #[repr(C)] pub struct OperationVTable { operation_kind: *const u8, operation_kind_len: usize, pub serialize: unsafe extern "C" fn(&AnyOperation) -> Result, ()>, pub deserialize: unsafe extern "C" fn(&[u8]) -> Result, pub is_same: unsafe extern "C" fn(&AnyOperation) -> 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 { let operation_kind = T::operation_kind().as_ptr(); let operation_kind_len = T::operation_kind().len(); 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, operation_kind, operation_kind_len, } } pub fn kind(&self) -> &'static str { let slice = unsafe { std::slice::from_raw_parts(self.operation_kind, self.operation_kind_len) }; std::str::from_utf8(slice).unwrap() } } #[repr(C)] 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 fn new>(_operation: D) -> Self { todo!() } 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() } pub fn vtable(&self) -> OperationVTable { self.vtable } pub fn operation_kind(&self) -> &str { unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts( self.vtable.operation_kind, self.vtable.operation_kind_len, )) } } pub fn serialize(&self) -> Result, anyhow::Error> { todo!() } pub fn deserialize(_source: &[u8], _vtable: OperationVTable) -> Result { todo!() } pub fn is_same(&self, _other: &AnyOperation) -> bool { todo!() } } #[repr(C)] pub struct AnySuccess { inner: FFIBox<()>, vtable: OperationVTable, } impl AnySuccess { pub unsafe fn inner(&self) -> &T { self.inner.transmute_ref() } pub unsafe fn from_raw(inner: FFIBox<()>, vtable: OperationVTable) -> Self { Self { inner, vtable } } pub fn serialize(&self) -> Result, anyhow::Error> { todo!() } pub fn deserialize_from_operation( _source: &[u8], _vtable: OperationVTable, ) -> Result { todo!() } } unsafe impl Send for AnySuccess {} unsafe impl Sync for AnySuccess {} impl std::fmt::Debug for AnySuccess { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("AnySuccess").finish() } } #[repr(C)] pub struct AnyFailure { inner: FFIBox<()>, vtable: OperationVTable, } unsafe impl Send for AnyFailure {} unsafe impl Sync for AnyFailure {} impl std::fmt::Debug for AnyFailure { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("AnyFailure").finish() } } pub trait IntoOperationVTable { fn operation_kind() -> &'static str; unsafe extern "C" fn serialize(this: &AnyOperation) -> Result, ()>; unsafe extern "C" fn deserialize(src: &[u8]) -> Result; unsafe extern "C" fn is_same(this: &AnyOperation) -> 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: &AnyOperation) -> 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: &AnyOperation) -> 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!() } fn operation_kind() -> &'static str { >::operation_name() } }