use std::mem::transmute; use giterated_models::object::GiteratedObject; use crate::FFIBox; #[derive(Clone, Copy)] #[repr(C)] pub struct ObjectVtable { object_kind: *const u8, object_kind_len: usize, 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 fn new() -> Self { let object_kind = T::object_kind().as_ptr(); let object_kind_len = T::object_kind().len(); Self { to_str: T::to_str, from_str: T::from_str, home_uri: T::home_uri, is_same: T::is_same, object_kind, object_kind_len, } } pub fn kind(&self) -> &'static str { let slice = unsafe { std::slice::from_raw_parts(self.object_kind, self.object_kind_len) }; std::str::from_utf8(slice).unwrap() } } pub trait IntoObjectVTable { fn object_kind() -> &'static str; 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!() } fn object_kind() -> &'static str { 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::(), } } pub fn vtable(&self) -> ObjectVtable { self.vtable } } 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() } }