Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you run rust code from a c library being called from rust?

Tags:

rust

I've had a look over the rust foreign function interface, and successfully (and happily) can call a c library from my rust code.

However, I can't seem to find any details on how to register a callback to invoke rust code, from within the c-code scope.

Is this even possible?

As a justification for 'why would you even do that?'; specifically I'm looking at embedding either lua or python in a rust application, and exposing a scripting-api for scripts that run on the embedded runtime.

Invoking these would be something along the lines of:

  • Main rust application loads
  • Application uses ffi to initialize the scripting runtime
  • Application binds local rust functions to C-callbacks
  • Application invokes ffi to bind the C-callbacks to the scripting layer
  • Application runs~
  • Periodically ffi is used to trigger the scripting runtime to execute blocks of bytecode
  • The scripting code does various trivial logic and calls bound handles
  • The bound handles invoke the c code
  • The bound c code invokes local rust code

All of these steps except for the ones in bold I've managed to get working, and I've done some trivial work using a scheduler, which the C-callbacks dump 'run me' commands into a queue and when control returns to the rust scope, the application queries the queue and runs the commands in it...

...but it's a little awkward from the scripting side, because it means multiple nested async callbacks, and the point of the scripting layer is to simplify the code that needs to go into the scripting layer.

like image 407
Doug Avatar asked Jan 07 '14 09:01

Doug


1 Answers

Yes, you can pass a callback function from Rust to C and invoke it there. The main thing to know is that you have to define the function with the extern "C" attribute.

Untested example (no Rust compiler here):

Rust side:

extern "C" fn callback(a:i32) {
    println!("I'm called from C with value {0}", a);
}

#[link(name = "mylib")]
extern {
   fn register_callback(cb: extern "C" fn(i32)) -> i32;
}

fn main() {
    unsafe {
        register_callback(callback);
    }
    ...
}

C side:

typedef void (*rust_callback)(int32_t);
rust_callback cb;

int32_t register_callback(rust_callback callback) {
    cb = callback;
    return 1;
}

void thread() {
  // do sth
  cb(xyz);
}
like image 127
Matthias247 Avatar answered Nov 13 '22 05:11

Matthias247