In the following example, I've got application state in my main thread and a UI running on another thread. The UI is implemented in another language and calls back to Rust over FFI. I'd like to use the Rust channels mechanism to communicate between the two threads. I've seen the Rust examples on channels and threading, but in all examples the thread is implemented in a closure and has access to the application state. With FFI, however, you only have C-like functions that do not have access to the application state, and therefore no way to access the channel that was created earlier.
use std::thread;
use std::sync::mpsc;
extern {
fn ui_create_and_run();
}
struct AppState {
foo: i32
}
enum Msg {
SetFoo(i32),
}
fn main() {
let mut state = AppState{ foo: 0 };
let (tx, rx) = mpsc::channel();
let ui_thr_handle = thread::spawn(|| {
unsafe { ui_create_and_run(); }
});
for msg in rx {
match msg {
Msg::SetFoo(x) => state.foo = x;
}
}
ui_thr_handle.join().unwrap();
}
#[no_mangle]
pub extern "C" fn set_foo(newFoo: i32) {
// PROBLEM: tx NOT AVAILABLE HERE!
tx.send(Msg::SetFoo(newFoo)).unwrap();
}
Is it possible to give my extern "C"
functions access to some global channel tx
without passing all kinds of nasty pointers around? I've tried
thread_local!(static CHANNEL: RefCell<(mpsc::Sender<Msg>, mpsc::Receiver<Msg>)> = RefCell::new(mpsc::channel()));
but can't seem to wrap my head around borrowing issues that this creates.