Rust calls Dart
randsoy opened this issue · comments
For example, in this code snippet:
pub async fn rust_function(dart_callback: impl Fn(String) -> DartFnFuture<String>) {
dart_callback("Tom".to_owned()).await; // Will get `Hello, Tom!`
}
I want to define the content of this code as a type and store it in a struct (possibly unsafe, it would be best to add safety checks).
thanks!
I want to define the content of this code as a type and store it in a struct
Not sure what does this mean, could you please elaborate it a little bit more?
use std::sync::{Arc, Mutex};
use futures::future::FutureExt;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::future::Future;
use async_trait::async_trait;
pub struct FfiEvent {
msg_cb: Arc<Mutex<dyn FnMut(Vec<u8>, String, String) -> DartFnFuture<bool> + Send>>,
msg_err_cb: Arc<Mutex<dyn FnMut(String, u32, String) -> DartFnFuture<bool> + Send>>,
unauthorized_cb: Arc<Mutex<dyn FnMut() -> DartFnFuture<bool> + Send>>,
}
impl FfiEvent {
pub fn new(
msg_cb: impl FnMut(Vec<u8>, String, String) -> DartFnFuture<bool> + 'static + Send,
msg_err_cb: impl FnMut(String, u32, String) -> DartFnFuture<bool> + 'static + Send,
unauthorized_cb: impl FnMut() -> DartFnFuture<bool> + 'static + Send,
) -> Self {
Self {
msg_cb: Arc::new(Mutex::new(Box::new(msg_cb))),
msg_err_cb: Arc::new(Mutex::new(Box::new(msg_err_cb))),
unauthorized_cb: Arc::new(Mutex::new(Box::new(unauthorized_cb))),
}
}
}
#[async_trait]
impl Event for FfiEvent {
async fn message_event(
&self,
from: String,
message: Vec<u8>,
message_id: String,
) -> bool {
let mut cb = self.msg_cb.lock().unwrap();
cb(message, from, message_id).await
}
}
#[async_trait]
trait Event:Send {
async fn message_event(&self, from: String, message: Vec<u8>, message_id: String) ->bool;
}
That code looks OK at first glance - is there any problem of that?
future cannot be sent between threads safely
within {async block@bridge/rust/src/store/event.rs:56:15: 60:6}
, the trait std::marker::Send
is not implemented for MutexGuard<'_, dyn Fn(Vec<u8>, String, String) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send>
required for the cast from Pin<Box<{async block@bridge/rust/src/store/event.rs:56:15: 60:6}>>
to Pin<Box<dyn std::future::Future<Output = bool> + std::marker::Send>>
rustcClick for full compiler diagnostic
event.rs(58, 51): future is not Send
as this value is used across an await
error: future cannot be sent between threads safely
--> bridge/rust/src/store/event.rs:56:15
|
56 | ) -> bool {
| __________^
57 | | let cb = self.msg_cb.lock().unwrap();
58 | | let resut = cb(message, from, message_id).await;
59 | | resut
60 | | }
| |^ future created by async block is not Send
My goal is to implement the Event interface. The code I just modified a lot still has compile time exceptions. Do you have a good example of this?
let mut cb = self.msg_cb.lock().unwrap();
cb(message, from, message_id).await
Looks like this one makes Rust unhappy, thus may not be a problem with flutter_rust_bridge. what if you use tokio's Mutex, instead of std sync Mutex?
Btw it would be great to paste full error logs as well.
I am very grateful for your immediate response.
It's indeed a rust issue, but I don't know how to fix the error.
use std::sync::{Arc, Mutex, RwLock};
use async_trait::async_trait;
use flutter_rust_bridge::DartFnFuture;
use libchatio::models::request::Event;
// #[derive(Clone)]
pub struct FfiEvent {
msg_cb: Arc<
Mutex<
Box<
dyn Fn(Vec<u8>, String, String) -> DartFnFuture<bool>
+ Send
+ 'static,
>,
>,
>,
}
impl FfiEvent {
pub fn new(
msg_cb: impl Fn(Vec<u8>, String, String) -> DartFnFuture<bool>
+ 'static
+ Send,
) -> Self {
Self {
msg_cb: Arc::new(Mutex::new(Box::new(msg_cb))),
}
}
}
#[async_trait]
impl Event for FfiEvent {
async fn message_event(
&self,
from: String,
message: Vec<u8>,
message_id: String,
) -> bool {
let cb = self.msg_cb.lock().unwrap();
let fut = cb(message, from, message_id);
let result = fut.await;
result
}
async fn message_error_event(
&self,
from_name: String,
from_device_id: u32,
message_id: String,
) -> bool {
log::info!(
"message_error_event, from:{}, message_id:{:?}",
from_name,
message_id
);
false
}
async fn unauthorized_event(&self) -> bool {
log::info!("unauthorized_event");
false
}
}
#[async_trait]
pub trait Event: Send {
async fn message_event(
&self,
from: String,
message: Vec<u8>,
message_id: String,
) -> bool;
async fn message_error_event(
&self,
from: String,
from_device_id: u32,
message_id: String,
) -> bool;
async fn unauthorized_event(&self) -> bool;
}
log
error: future cannot be sent between threads safely
--> bridge/rust/src/store/event.rs:41:15
|
41 | ) -> bool {
| _______________^
42 | | let cb = self.msg_cb.lock().unwrap();
43 | | let fut = cb(message, from, message_id);
44 | | let result = fut.await;
45 | | result
46 | | }
| |_____^ future created by async block is not `Send`
|
= help: within `{async block@bridge/rust/src/store/event.rs:41:15: 46:6}`, the trait `std::marker::Send` is not implemented for `MutexGuard<'_, Box<dyn Fn(Vec<u8>, String, String) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send>>`
note: future is not `Send` as this value is used across an await
--> bridge/rust/src/store/event.rs:44:26
|
42 | let cb = self.msg_cb.lock().unwrap();
| -- has type `std::sync::MutexGuard<'_, Box<dyn Fn(Vec<u8>, std::string::String, std::string::String) -> Pin<Box<dyn std::future::Future<Output = bool> + std::marker::Send>> + std::marker::Send>>` which is not `Send`
43 | let fut = cb(message, from, message_id);
44 | let result = fut.await;
| ^^^^^ await occurs here, with `cb` maybe used later
= note: required for the cast from `Pin<Box<{async block@bridge/rust/src/store/event.rs:41:15: 46:6}>>` to `Pin<Box<dyn std::future::Future<Output = bool> + std::marker::Send>>`
You are welcome. As mentioned earlier:
what if you use tokio's Mutex, instead of std sync Mutex?
i.e. use std::sync::{Arc, Mutex, RwLock};
change this one
It seems that I still need to learn more about Rust.
It's OK - everyone was a beginner :)