memflex 0.8.4

Memory hacking library
Documentation
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);
    }
}