3
votes

I am trying to call a public function (located inside a Rust struct's impl block) from a C program using the FFI. Calling regular pub fns has not been too much trouble, but I am trying to call a pub fn from inside a struct's impl block, and not finding the right syntax to expose/call it. Surely this is possible, right?

lib.rs

#[repr(C)]
#[derive(Debug)]
pub struct MyStruct {
    var: i32,
}

#[no_mangle]
pub extern "C" fn new() -> MyStruct {
    MyStruct { var: 99 }
}

#[no_mangle]
impl MyStruct {
    #[no_mangle]
    pub extern "C" fn print_hellow(&self) {
        println!("{}", self.var);
    }
}

main.c

typedef struct MyStruct
{
    int var;
} MyStruct;
extern MyStruct new (void);
extern void print_hellow(MyStruct);

int main()
{
    MyStruct instance1;
    MyStruct instance2 = new ();

    printf("Instance1 var:%d\n", instance1.var);
    /// successfully prints the uninitialized 'var'
    
    printf("Instance2 var:%d\n", instance2.var);
    /// successfully prints the initialized 'var'
    
    print_hellow(instance1);
    /// fails to link during compilation

    return 0;
}
1
Surely this is possible, right? -- I don't see why it should be; the notion of an object with methods doesn't really exist in the "C" ABI. I'm kind of surprised you don't get an error just from putting #[no_mangle] on a method.trentcl
(Note that extern void print_hellow(MyStruct); and extern "C" fn print_hellow(&self) are at odds, anyway -- they don't accept the same type.)trentcl
I don't think that this is possible. You have to expose a function, similar like fn print_hellow(*MyStruct) and then you can "map that" to the member function of MyStruct.hellow
This has been my fall-back work around, but I've been hoping for more. Thanks. If this truly is the best answer, make it as an answer and I'll give you credit.sam

1 Answers

5
votes

No, this is not possible. You will need to write shim functions for every method you wish to access:

#[no_mangle]
pub unsafe extern "C" fn my_struct_print_hellow(me: *const MyStruct) {
    let me = &*me;
    me.print_hellow();
}

See also: