fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.

Home Page:https://fzyzcjy.github.io/flutter_rust_bridge/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 :)