I'm new to rust.
I'm trying to wrap existing rust code so that I can call it from Swift. I have this working for simple rust functions using cbindgen. But the rust code that I want to wrap does work on a background thread and sometimes I would like to cancel that work before it completes.
Here's a simplified example of the rust function that I'd like to call:
// Created from copy/paste on internet. Seems to work for me.
// Let me know if there's improvements to be made.
use std::thread;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
fn schedule_do_work(work_was_done_callback: Box<Fn(i32) + Send>) -> impl Fn() {
let cancel = Arc::new(AtomicBool::new(false));
let threads_cancel = cancel.clone();
thread::spawn(move || {
let result_of_work = 42;
if !threads_cancel.load(Ordering::SeqCst) {
(work_was_done_callback)(result_of_work);
}
});
move || {
cancel.store(true, Ordering::SeqCst);
}
}
The function:
- accepts a callback.
- does work in background thread, calls the callback with result of work
- returns a function that can be used to cancel the work.
The trouble is I can't figure how to expose it through ffi so that I can call it from Swift/c. In particular I don't know how to map the incoming callback closure, or the returned "cancel" closure. Though web searches and documentation I sort of understand what some of the issues are... that passing closures between rust and c requires splitting out the function and captured environment into two values.
But after working on it all afternoon I can't figure out how to make it work.
Any tips on what I need to do next? I'm happy to start over by redesigning my approach in the schedule_do_work
if needed. I've also looked at an approached based on Using Rust objects from other languages and that helps with the "cancel" part of the equation. But I'm still left dealing with closures when trying to notify the Swift/c code that work is completed.
// This code is just a sketch of how I'm trying to wrap the function in ffi
// Doesn't compile, probably all wrong! :slight_smile:
use std::os::raw::c_void;
pub type Callback = fn(size: i32, context: c_void);
pub struct Cancelable {
callback: Box<Fn()>,
context: c_void,
}
#[no_mangle]
pub extern fn schedule_do_work_from_c(callback: Callback, context: c_void) -> Cancelable {
let cancelable = schedule_do_work(Box::new(move |value| {
callback(value, context);
}));
return cancelable;
}
Thanks for any help!