use std::mem::transmute_copy; mod game { #[repr(C)] struct FooVmt { idx0: extern "C" fn(&Foo) -> i32, idx1: extern "C" fn(&mut Foo, i32) -> i32, idx2: extern "C" fn(&Foo) -> &i32, } #[repr(C)] pub struct Foo { vmt: &'static FooVmt, health: i32, } impl Foo { pub fn new() -> Self { Foo { vmt: &FooVmt { idx0: Foo::get_health, idx1: Foo::set_health, idx2: Foo::get_health_ref, }, health: 100, } } } impl Foo { pub extern "C" fn get_health(&self) -> i32 { self.health } pub extern "C" fn set_health(&mut self, new: i32) -> i32 { let old = self.health; self.health = new; old } pub extern "C" fn get_health_ref(&self) -> &i32 { &self.health } } } #[allow(dead_code)] struct CFoo([u8; 0x10]); memflex::interface! { pub trait IFoo impl for CFoo { extern fn get_health() -> i32 = #0; extern fn set_health(new: i32) -> i32 = #1; extern fn get_health_ref() -> &'this i32 = #2; } } #[test] #[allow(clippy::disallowed_names)] fn test_interface() { let foo = game::Foo::new(); unsafe { let this = transmute_copy::<_, CFoo>(&foo); assert_eq!(this.get_health(), 100); assert_eq!(this.set_health(50), 100); assert_eq!(this.get_health(), 50); assert_eq!(CFoo::FUNCTION_COUNT, 3); } }