fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.
https://fzyzcjy.github.io/flutter_rust_bridge/
MIT License
4.18k stars 289 forks source link

Pin<Box<dyn Future<Output = _>>> in Trait Object translate issue #2172

Closed canxin121 closed 3 weeks ago

canxin121 commented 3 months ago

Describe the bug

use std::{future::Future, pin::Pin};

#[flutter_rust_bridge::frb]
pub struct A();
impl TraitA for A {}

#[flutter_rust_bridge::frb]

pub trait TraitA {
    fn do_something(&self) -> Pin<Box<dyn Future<Output = ()> + 'static>> {
        Box::pin(async {})
    }
}

pub type TraitAObject = Box<dyn TraitA + Send + Sync>;

This minium code translation got 2 errors:

  1. impl SseDecode
    for RustOpaqueMoi<
        flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
            Pin<Box<dyn Future<Output = ()> + 'static>>,
        >,
    >
    {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        let mut inner = <usize>::sse_decode(deserializer);
        return decode_rust_opaque_moi(inner);
    }
    }

    got error:

    error[E0277]: `(dyn std::future::Future<Output = ()> + 'static)` cannot be shared between threads safely
    --> src\frb_generated.rs:183:16
     |
    183  |         return decode_rust_opaque_moi(inner);
     |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn std::future::Future<Output = ()> + 'static)` cannot be shared between threads safely
     |
     = help: the trait `std::marker::Sync` is not implemented for `(dyn std::future::Future<Output = ()> + 'static)`, which is required by `RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>: std::marker::Sync`
     = note: required for `Unique<(dyn std::future::Future<Output = ()> + 'static)>` to implement `std::marker::Sync`
    note: required because it appears within the type `Box<(dyn std::future::Future<Output = ()> + 'static)>`
    --> C:\Users\canxin.LAPTOP\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\alloc\src\boxed.rs:196:12
     |
    196  | pub struct Box<
     |            ^^^
    note: required because it appears within the type `std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>`
    --> C:\Users\canxin.LAPTOP\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\pin.rs:1090:12
     |
    1090 | pub struct Pin<Ptr> {
     |            ^^^
     = note: required for `flutter_rust_bridge::rust_async::RwLock<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>` to implement `std::marker::Sync`
    note: required because it appears within the type `RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>`
    --> C:\Users\canxin.LAPTOP\.cargo\registry\src\index.crates.io-6f17d22bba15001f\flutter_rust_bridge-2.0.0\src\rust_auto_opaque\inner.rs:4:12
     |
    4    | pub struct RustAutoOpaqueInner<T> {
     |            ^^^^^^^^^^^^^^^^^^^
    note: required by a bound in `decode_rust_opaque_moi`
    --> src\frb_generated.rs:39:1
     |
    39   | / flutter_rust_bridge::frb_generated_boilerplate!(
    40   | |     default_stream_sink_codec = SseCodec,
    41   | |     default_rust_opaque = RustOpaqueMoi,
    42   | |     default_rust_auto_opaque = RustAutoOpaqueMoi,
    43   | | );
     | |_^ required by this bound in `decode_rust_opaque_moi`
     = note: this error originates in the macro `$crate::frb_generated_rust_opaque_dart2rust` which comes from the expansion of the macro `flutter_rust_bridge::frb_generated_boilerplate` (in Nightly builds, run with -Z macro-backtrace for more info)
  2. 
    // Section: related_funcs

flutter_rust_bridge::frb_generated_moi_arc_impl_value!( flutter_rust_bridge::for_generated::RustAutoOpaqueInner< Pin<Box<dyn Future + 'static>>,

);

got error:
```md
error[E0277]: `(dyn std::future::Future<Output = ()> + 'static)` cannot be sent between threads safely
--> src\frb_generated.rs:153:1
|
153  | / flutter_rust_bridge::frb_generated_moi_arc_impl_value!(
154  | |     flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
155  | |         Pin<Box<dyn Future<Output = ()> + 'static>>,
156  | |     >
157  | | );
| |_^ `(dyn std::future::Future<Output = ()> + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn std::future::Future<Output = ()> + 'static)`, which is required by `std::sync::RwLock<MoiArcPoolInner<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>>: std::marker::Sync`
= note: required for `Unique<(dyn std::future::Future<Output = ()> + 'static)>` to implement `std::marker::Send`
note: required because it appears within the type `Box<(dyn std::future::Future<Output = ()> + 'static)>`
--> C:\Users\canxin.LAPTOP\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\alloc\src\boxed.rs:196:12
|
196  | pub struct Box<
|            ^^^
note: required because it appears within the type `std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>`
--> C:\Users\canxin.LAPTOP\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\pin.rs:1090:12
|
1090 | pub struct Pin<Ptr> {
|            ^^^
= note: required for `flutter_rust_bridge::rust_async::RwLock<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>` to implement `std::marker::Sync`
note: required because it appears within the type `RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>`
--> C:\Users\canxin.LAPTOP\.cargo\registry\src\index.crates.io-6f17d22bba15001f\flutter_rust_bridge-2.0.0\src\rust_auto_opaque\inner.rs:4:12
|
4    | pub struct RustAutoOpaqueInner<T> {
|            ^^^^^^^^^^^^^^^^^^^
= note: required for `Arc<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>` to implement `std::marker::Send`
note: required because it appears within the type `MoiArcPoolValue<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>`
--> src\frb_generated.rs:39:1
|
39   | / flutter_rust_bridge::frb_generated_boilerplate!(
40   | |     default_stream_sink_codec = SseCodec,
41   | |     default_rust_opaque = RustOpaqueMoi,
42   | |     default_rust_auto_opaque = RustAutoOpaqueMoi,
43   | | );
| |_^
= note: required because it appears within the type `(usize, MoiArcPoolValue<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>)`
= note: required for `RawTable<(usize, MoiArcPoolValue<RustAutoOpaqueInner<Pin<Box<dyn Future<Output = ()>>>>>)>` to implement `std::marker::Send`
note: required because it appears within the type `HashMap<usize, MoiArcPoolValue<RustAutoOpaqueInner<Pin<Box<dyn Future<Output = ()>>>>>, RandomState>`
--> /rust/deps\hashbrown-0.14.3\src\map.rs:190:12
note: required because it appears within the type `HashMap<usize, MoiArcPoolValue<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>>`
--> C:\Users\canxin.LAPTOP\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\std\src\collections\hash\map.rs:213:12
|
213  | pub struct HashMap<K, V, S = RandomState> {
|            ^^^^^^^
note: required because it appears within the type `MoiArcPoolInner<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>`
--> src\frb_generated.rs:39:1
|
39   | / flutter_rust_bridge::frb_generated_boilerplate!(
40   | |     default_stream_sink_codec = SseCodec,
41   | |     default_rust_opaque = RustOpaqueMoi,
42   | |     default_rust_auto_opaque = RustAutoOpaqueMoi,
43   | | );
| |_^
= note: required for `std::sync::RwLock<MoiArcPoolInner<RustAutoOpaqueInner<std::pin::Pin<Box<(dyn std::future::Future<Output = ()> + 'static)>>>>>` to implement `std::marker::Sync`
note: required by a bound in `lazy_static::lazy::Lazy`
--> C:\Users\canxin.LAPTOP\.cargo\registry\src\index.crates.io-6f17d22bba15001f\lazy_static-1.4.0\src\inline_lazy.rs:19:20
|
19   | pub struct Lazy<T: Sync>(Cell<Option<T>>, Once);
|                    ^^^^ required by this bound in `Lazy`
= note: the full name for the type has been written to 'C:\Users\canxin.LAPTOP\test_trait\rust\target\debug\deps\rust_lib_test_trait-82aa68d9a5eb476b.long-type-8598590409287766133.txt'
= note: consider using `--verbose` to print the full type name to the console
= note: the full name for the type has been written to 'C:\Users\canxin.LAPTOP\test_trait\rust\target\debug\deps\rust_lib_test_trait-82aa68d9a5eb476b.long-type-12697570336106566502.txt'
= note: consider using `--verbose` to print the full type name to the console
= note: this error originates in the macro `__lazy_static_create` which comes from the expansion of the macro `flutter_rust_bridge::frb_generated_boilerplate` (in Nightly builds, run with -Z macro-backtrace for more info)

Is there a way to translate the sync funcs in trait object that return Pin<Box<dyn Future<Output = _>>> to async funcs?

Steps to reproduce

Hint: A simple way to reproduce is to clone and modify the https://github.com/fzyzcjy/flutter_rust_bridge/tree/master/frb_example/dart_minimal example package according to your needs.

  1. use the minium code to translate
  2. got 2 error

Logs

The translate succeed without error or warn.

Expected behavior

    fn do_something(&self) -> Pin<Box<dyn Future<Output = ()> + 'static>> {
        Box::pin(async {})
    }

get the same translation as below async fn code

    fn async do_something(&self) -> () {
    }

Generated binding code

// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0.

#![allow(
    non_camel_case_types,
    unused,
    non_snake_case,
    clippy::needless_return,
    clippy::redundant_closure_call,
    clippy::redundant_closure,
    clippy::useless_conversion,
    clippy::unit_arg,
    clippy::unused_unit,
    clippy::double_parens,
    clippy::let_and_return,
    clippy::too_many_arguments,
    clippy::match_single_binding,
    clippy::clone_on_copy,
    clippy::let_unit_value,
    clippy::deref_addrof,
    clippy::explicit_auto_deref,
    clippy::borrow_deref_ref,
    clippy::needless_borrow
)]

// Section: imports

use std::future::Future;
use std::pin::Pin;

use crate::api::TraitA;
use crate::api::*;
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};

// Section: boilerplate

flutter_rust_bridge::frb_generated_boilerplate!(
    default_stream_sink_codec = SseCodec,
    default_rust_opaque = RustOpaqueMoi,
    default_rust_auto_opaque = RustAutoOpaqueMoi,
);
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.0.0";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -444446631;

// Section: executor

flutter_rust_bridge::frb_generated_default_handler!();

// Section: wire_funcs

fn wire__crate__api__a_do_something_impl(
    port_: flutter_rust_bridge::for_generated::MessagePort,
    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
    rust_vec_len_: i32,
    data_len_: i32,
) {
    FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
        flutter_rust_bridge::for_generated::TaskInfo {
            debug_name: "a_do_something",
            port: Some(port_),
            mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
        },
        move || {
            let message = unsafe {
                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
                    ptr_,
                    rust_vec_len_,
                    data_len_,
                )
            };
            let mut deserializer =
                flutter_rust_bridge::for_generated::SseDeserializer::new(message);
            let api_that = <crate::api::A>::sse_decode(&mut deserializer);
            deserializer.end();
            move |context| {
                transform_result_sse::<_, ()>((move || {
                    let output_ok = Result::<_, ()>::Ok(crate::api::A::do_something(&api_that))?;
                    Ok(output_ok)
                })())
            }
        },
    )
}
fn wire__crate__api__simple__greet_impl(
    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
    rust_vec_len_: i32,
    data_len_: i32,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
    FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::SseCodec, _>(
        flutter_rust_bridge::for_generated::TaskInfo {
            debug_name: "greet",
            port: None,
            mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,
        },
        move || {
            let message = unsafe {
                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
                    ptr_,
                    rust_vec_len_,
                    data_len_,
                )
            };
            let mut deserializer =
                flutter_rust_bridge::for_generated::SseDeserializer::new(message);
            let api_name = <String>::sse_decode(&mut deserializer);
            deserializer.end();
            transform_result_sse::<_, ()>((move || {
                let output_ok = Result::<_, ()>::Ok(crate::api::simple::greet(api_name))?;
                Ok(output_ok)
            })())
        },
    )
}
fn wire__crate__api__simple__init_app_impl(
    port_: flutter_rust_bridge::for_generated::MessagePort,
    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
    rust_vec_len_: i32,
    data_len_: i32,
) {
    FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
        flutter_rust_bridge::for_generated::TaskInfo {
            debug_name: "init_app",
            port: Some(port_),
            mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
        },
        move || {
            let message = unsafe {
                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
                    ptr_,
                    rust_vec_len_,
                    data_len_,
                )
            };
            let mut deserializer =
                flutter_rust_bridge::for_generated::SseDeserializer::new(message);
            deserializer.end();
            move |context| {
                transform_result_sse::<_, ()>((move || {
                    let output_ok = Result::<_, ()>::Ok({
                        crate::api::simple::init_app();
                    })?;
                    Ok(output_ok)
                })())
            }
        },
    )
}

// Section: related_funcs

flutter_rust_bridge::frb_generated_moi_arc_impl_value!(
    flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
        Pin<Box<dyn Future<Output = ()> + 'static>>,
    >
);

// Section: dart2rust

impl SseDecode for Pin<Box<dyn Future<Output = ()> + 'static>> {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        let mut inner = <RustOpaqueMoi<
            flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
                Pin<Box<dyn Future<Output = ()> + 'static>>,
            >,
        >>::sse_decode(deserializer);
        return flutter_rust_bridge::for_generated::rust_auto_opaque_decode_owned(inner);
    }
}

impl SseDecode
    for RustOpaqueMoi<
        flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
            Pin<Box<dyn Future<Output = ()> + 'static>>,
        >,
    >
{
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        let mut inner = <usize>::sse_decode(deserializer);
        return decode_rust_opaque_moi(inner);
    }
}

impl SseDecode for String {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        let mut inner = <Vec<u8>>::sse_decode(deserializer);
        return String::from_utf8(inner).unwrap();
    }
}

impl SseDecode for crate::api::A {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        return crate::api::A();
    }
}

impl SseDecode for Vec<u8> {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        let mut len_ = <i32>::sse_decode(deserializer);
        let mut ans_ = vec![];
        for idx_ in 0..len_ {
            ans_.push(<u8>::sse_decode(deserializer));
        }
        return ans_;
    }
}

impl SseDecode for u8 {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        deserializer.cursor.read_u8().unwrap()
    }
}

impl SseDecode for () {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {}
}

impl SseDecode for usize {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        deserializer.cursor.read_u64::<NativeEndian>().unwrap() as _
    }
}

impl SseDecode for i32 {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        deserializer.cursor.read_i32::<NativeEndian>().unwrap()
    }
}

impl SseDecode for bool {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
        deserializer.cursor.read_u8().unwrap() != 0
    }
}

fn pde_ffi_dispatcher_primary_impl(
    func_id: i32,
    port: flutter_rust_bridge::for_generated::MessagePort,
    ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
    rust_vec_len: i32,
    data_len: i32,
) {
    // Codec=Pde (Serialization + dispatch), see doc to use other codecs
    match func_id {
        2 => wire__crate__api__a_do_something_impl(port, ptr, rust_vec_len, data_len),
        4 => wire__crate__api__simple__init_app_impl(port, ptr, rust_vec_len, data_len),
        _ => unreachable!(),
    }
}

fn pde_ffi_dispatcher_sync_impl(
    func_id: i32,
    ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
    rust_vec_len: i32,
    data_len: i32,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
    // Codec=Pde (Serialization + dispatch), see doc to use other codecs
    match func_id {
        3 => wire__crate__api__simple__greet_impl(ptr, rust_vec_len, data_len),
        _ => unreachable!(),
    }
}

// Section: rust2dart

// Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for FrbWrapper<Pin<Box<dyn Future<Output = ()> + 'static>>> {
    fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
        flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self.0)
            .into_dart()
    }
}
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
    for FrbWrapper<Pin<Box<dyn Future<Output = ()> + 'static>>>
{
}

impl flutter_rust_bridge::IntoIntoDart<FrbWrapper<Pin<Box<dyn Future<Output = ()> + 'static>>>>
    for Pin<Box<dyn Future<Output = ()> + 'static>>
{
    fn into_into_dart(self) -> FrbWrapper<Pin<Box<dyn Future<Output = ()> + 'static>>> {
        self.into()
    }
}

// Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for crate::api::A {
    fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
        Vec::<u8>::new().into_dart()
    }
}
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::A {}
impl flutter_rust_bridge::IntoIntoDart<crate::api::A> for crate::api::A {
    fn into_into_dart(self) -> crate::api::A {
        self
    }
}

impl SseEncode for Pin<Box<dyn Future<Output = ()> + 'static>> {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        <RustOpaqueMoi<
            flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
                Pin<Box<dyn Future<Output = ()> + 'static>>,
            >,
        >>::sse_encode(
            flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self),
            serializer,
        );
    }
}

impl SseEncode
    for RustOpaqueMoi<
        flutter_rust_bridge::for_generated::RustAutoOpaqueInner<
            Pin<Box<dyn Future<Output = ()> + 'static>>,
        >,
    >
{
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        let (ptr, size) = self.sse_encode_raw();
        <usize>::sse_encode(ptr, serializer);
        <i32>::sse_encode(size, serializer);
    }
}

impl SseEncode for String {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        <Vec<u8>>::sse_encode(self.into_bytes(), serializer);
    }
}

impl SseEncode for crate::api::A {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {}
}

impl SseEncode for Vec<u8> {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        <i32>::sse_encode(self.len() as _, serializer);
        for item in self {
            <u8>::sse_encode(item, serializer);
        }
    }
}

impl SseEncode for u8 {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        serializer.cursor.write_u8(self).unwrap();
    }
}

impl SseEncode for () {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {}
}

impl SseEncode for usize {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        serializer
            .cursor
            .write_u64::<NativeEndian>(self as _)
            .unwrap();
    }
}

impl SseEncode for i32 {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        serializer.cursor.write_i32::<NativeEndian>(self).unwrap();
    }
}

impl SseEncode for bool {
    // Codec=Sse (Serialization based), see doc to use other codecs
    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
        serializer.cursor.write_u8(self as _).unwrap();
    }
}

#[cfg(not(target_family = "wasm"))]
#[path = "frb_generated.io.rs"]
mod io;
#[cfg(not(target_family = "wasm"))]
pub use io::*;

/// cbindgen:ignore
#[cfg(target_family = "wasm")]
#[path = "frb_generated.web.rs"]
mod web;
#[cfg(target_family = "wasm")]
pub use web::*;

OS

Windows 10

Version of flutter_rust_bridge_codegen

=2.0.0

Flutter info

not related.

Version of clang++

not related

Additional context

no more

fzyzcjy commented 3 months ago

That complex type does not seem to be supported yet. However, frb does support normal Rust async fns. What about using https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html thus to write

pub trait TraitA {
    async fn do_something(&self) {
        //
    }
}
canxin121 commented 3 months ago

That complex type does not seem to be supported yet. However, frb does support normal Rust async fns. What about using https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html thus to write

pub trait TraitA {
    async fn do_something(&self) {
        //
    }
}
error[E0038]: the trait `TraitA` cannot be made into an object
  --> src\api\mod.rs:17:10
   |
17 | struct B(TraitAObject);
   |          ^^^^^^^^^^^^ `TraitA` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> src\api\mod.rs:11:14
   |
10 | pub trait TraitA {
   |           ------ this trait cannot be made into an object...
11 |     async fn do_something(&self) -> () {}
   |              ^^^^^^^^^^^^ ...because method `do_something` is `async`
   = help: consider moving `do_something` to another trait
   = help: only type `api::A` is seen to implement the trait in this crate, consider using it directly instead
   = note: `TraitA` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type

There is a crate about it async-trait This crate's macro translate async fn to fn -> Pin<Box<dyn Future<Output = _>>> to make the trait "object safe"

fzyzcjy commented 3 months ago

Hmm I see. Then maybe we can fix it like: Whenever we see Pin<Box<dyn Future<Output = WhateverType>>>, we internally treat it as async fn f() -> WhateverType. What do you think?

And btw, is there a full list what types needs to be treated like this pined boxed future?

canxin121 commented 3 months ago

Hmm I see. Then maybe we can fix it like: Whenever we see Pin<Box<dyn Future<Output = WhateverType>>>, we internally treat it as async fn f() -> WhateverType. What do you think?

And btw, is there a full list what types needs to be treated like this pined boxed future?

I'm not sure about other types.

And I currently use a wrapper like below. And it works well.

use std::{future::Future, pin::Pin};

use flutter_rust_bridge::frb;

pub mod simple;

#[frb(ignore)]
struct A();
impl TraitA for A {}
#[frb(ignore)]
pub trait TraitA {
    #[frb(ignore)]
    fn do_something(&self) -> Pin<Box<dyn Future<Output = ()> + 'static>> {
        Box::pin(async {})
    }
}

#[frb(ignore)]
type TraitAObject = Box<dyn TraitA + Send + Sync>;

#[frb]
pub struct TraitAObjectWrapper(TraitAObject);

impl TraitAObjectWrapper {
    async fn do_something(&self) {
        self.0.do_something().await;
    }
}
fzyzcjy commented 3 months ago

That looks great!

Feel free to PR for the type translation, alternatively I will work on it in the next batch.

canxin121 commented 3 months ago

I'm afraid I've been busy lately and haven't had time to read the flutter_rust_bridge code to figure out how to implement it.

fzyzcjy commented 3 months ago

No worries

stale[bot] commented 1 month ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] commented 1 week ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.