use std::mem::transmute; use giterated_models::{object::GiteratedObject, operation::GiteratedOperation}; use crate::FFIBox; use super::AnyObject; #[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(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 { 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() } } 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() } pub fn vtable(&self) -> OperationVTable { self.vtable } } #[repr(C)] pub struct AnySuccess { inner: FFIBox<()>, vtable: OperationVTable, } #[repr(C)] pub struct AnyFailure { inner: FFIBox<()>, vtable: OperationVTable, } 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: 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: &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: 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!() } fn operation_kind() -> &'static str { todo!() } }