use cpp_oop::gen_oop; use cpp_oop::CastPtr; gen_oop! { #[default] struct Foo { foo: u32, } struct FooLayout { foo: fn(this: &Self, a: i32) -> u32, foo2: fn(this: &Self) -> u32, } impl FooMethodsInner for Foo { extern "C" fn foo_inner(_this: &Self, _a: i32) -> u32 { 1 } extern "C" fn foo2_inner(_this: &Self) -> u32 { 2 } } } gen_oop! { #[default] #[base(Foo)] struct Bar { bar: u32, } struct BarLayout { bar: fn(this: &Self) -> u32, } impl BarMethodsInner for Bar { extern "C" fn bar_inner(_this: &Self) -> u32 { 3 } } impl FooMethodsInner for Bar { extern "C" fn foo_inner(_this: &Self, _a: i32) -> u32 { 10 } #[unused] extern "C" fn foo2_inner(_this: &Self) -> u32 {} } } #[test] fn layout() { assert_eq!(std::mem::size_of::(), std::mem::size_of::()); assert_eq!(std::mem::size_of::(), std::mem::size_of::() * 2); } #[test] fn basic() { let b = Bar::default(); let b_ptr = &b as *const Bar; let f_ptr: *const Foo = Foo::cast_const(b_ptr); assert_eq!(Foo::foo_inner(&b.base_foo, 0), 1); // manual selection of the method to call assert_eq!(Bar::foo_inner(&b, 0), 10); // manual selection of the method to call assert_eq!(Foo::foo2_inner(&b.base_foo), 2); // manual selection of the method to call // Bar::foo2_inner will give an error cuz its unused assert_eq!(Bar::bar_inner(&b), 3); // manual selection of the method to call assert_eq!(b.foo(0), 10); // static dispatch assert_eq!(b.foo2(), 2); // static dispatch assert_eq!(b.bar(), 3); // static dispatch assert_eq!(f_ptr.foo(0), 1); // this one has no vtable (no virtual methods) so it will use static dispatch assert_eq!(f_ptr.foo2(), 2); // this one has no vtable (no virtual methods) so it will use static dispatch assert_eq!(b_ptr.foo(0), 10); // this one has no vtable (no virtual methods) so it will use static dispatch assert_eq!(b_ptr.foo2(), 2); // this one has no vtable (no virtual methods) so it will use static dispatch assert_eq!(b_ptr.bar(), 3); // this one has no vtable (no virtual methods) so it will use static dispatch }