I have created a simple API to test networking on Rust and trying to use in the IOS project.
It is working fine in Rust environment.
Extern function:
//Works fine
#[no_mangle]
pub extern "C" fn create_swapi_client() -> *mut SwapiClient {
Box::into_raw(Box::new(SwapiClient::new()))
}
//Throw error
#[no_mangle]
pub unsafe extern "C" fn load_name_cb(client: *mut SwapiClient, c_callback: fn(*mut c_char)) {
assert!(!client.is_null());
let local_client = client.as_ref().unwrap();
let cb = Callback {
callback: Box::new(|name| {
println!("Callback result: {}", name);
let result = CString::new(name.to_owned()).unwrap().into_raw();
(c_callback)(result); //borrowed value does not live long enough. How to set proper lifetime?
//If I remove this call I can compile and see logs.
}),
};
let callback: Box<Callback> = Box::new(cb);
local_client.load_name(1, callback);
}
Networking API:
pub struct Callback {
pub callback: Box<dyn FnMut(String)>,
}
unsafe impl Send for Callback {}
impl OnThreadEvent for Callback {
fn on_load(&mut self, name: &str) {
(self.callback)(name.to_string().clone());
}
}
pub trait OnThreadEvent {
fn on_load(&mut self, s: &str);
}
pub struct SwapiClient();
impl SwapiClient {
pub fn new() -> SwapiClient {
SwapiClient()
}
pub fn load_name(&self, id: i32, mut callback: Box<dyn OnThreadEvent + Send>) {
///Using Tokio runtime
(*RUN_TIME).spawn(async move {
let res = load_swapi_async().await; //reqwest function, works fine
match res {
Ok(name) => {
let result = format!("ID: {}; Name: {}", id, name);
callback.on_load(result.as_str());
}
Err(err) => {
let error = format!("ID: {}; Failed to load name {}", id, err);
callback.on_load(error.as_str())
}
}
});
}
}
I also tried to use thread directly in the extern function
- it works fine:
#[no_mangle]
pub extern "C" fn countdown(callback: fn(c_int)) {
thread::spawn(move || {
for x in (0..=15).rev() {
thread::sleep(Duration::from_secs(1));
callback(x);
}
});
}
Please, help. How can I bind the callback functions
lifecycle with Callback struct
?