Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crate compilation error when using mirrored third party Enum in StreamSink #1839

Closed
SilverMira opened this issue Mar 27, 2024 · 5 comments · Fixed by #1843
Closed

Crate compilation error when using mirrored third party Enum in StreamSink #1839

SilverMira opened this issue Mar 27, 2024 · 5 comments · Fixed by #1843
Labels
bug Something isn't working

Comments

@SilverMira
Copy link
Contributor

Describe the bug

Encountered a rust compilation error when I had both a function to return a third-party Enum to Dart land and a function that writes said Enum to a StreamSink.

cargo check errors
error[E0277]: the trait bound `allo_isolate::ffi::DartCObject: From<MyEnum>` is not satisfied
   --> src\frb_generated.rs:100:47
    |
100 | ...                   .stream_sink::<_, crate::api::simple::MyEnum>(),
    |                        -----------      ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<MyEnum>` is not implemented for `allo_isolate::ffi::DartCObject`, which is required by `MyEnum: IntoDart`
    |                        |
    |                        required by a bound introduced by this call
    |
    = help: the following other types implement trait `From<T>`:
              <allo_isolate::ffi::DartCObject as From<DartOpaque>>
              <allo_isolate::ffi::DartCObject as From<RustOpaqueBase<T, A>>>
    = note: required for `MyEnum` to implement `Into<allo_isolate::ffi::DartCObject>`
    = note: required for `MyEnum` to implement `IntoDart`
note: required by a bound in `flutter_rust_bridge::rust2dart::context::TaskRust2DartContext::<Rust2DartCodec>::stream_sink`
   --> C:\Users\Mira\.cargo\registry\src\index.crates.io-6f17d22bba15001f\flutter_rust_bridge-2.0.0-dev.28\src\rust2dart\context.rs:33:12
    |
30  |     pub fn stream_sink<T, D>(&self) -> StreamSinkBase<T, Rust2DartCodec>
    |            ----------- required by a bound in this associated function
...
33  |         D: IntoDart,
    |            ^^^^^^^^ required by this bound in `TaskRust2DartContext::<Rust2DartCodec>::stream_sink`

error[E0277]: the trait bound `MyEnum: IntoIntoDart<MyEnum>` is not satisfied
   --> src\frb_generated.rs:100:44
    |
100 | ...                   .stream_sink::<_, crate::api::simple::MyEnum>(),
    |                        -----------   ^ the trait `IntoIntoDart<MyEnum>` is not implemented for `MyEnum`
    |                        |
    |                        required by a bound introduced by this call
    |
    = help: the trait `IntoIntoDart<mirror_MyEnum>` is implemented for `MyEnum`
    = help: for that trait implementation, expected `mirror_MyEnum`, found `MyEnum`
note: required by a bound in `flutter_rust_bridge::rust2dart::context::TaskRust2DartContext::<Rust2DartCodec>::stream_sink`
   --> C:\Users\Mira\.cargo\registry\src\index.crates.io-6f17d22bba15001f\flutter_rust_bridge-2.0.0-dev.28\src\rust2dart\context.rs:32:12
    |
30  |     pub fn stream_sink<T, D>(&self) -> StreamSinkBase<T, Rust2DartCodec>
    |            ----------- required by a bound in this associated function
31  |     where
32  |         T: IntoIntoDart<D>,
    |            ^^^^^^^^^^^^^^^ required by this bound in `TaskRust2DartContext::<Rust2DartCodec>::stream_sink`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust_lib_repro_frb` (lib) due to 2 previous errors

Also, while preparing this repro, I noticed that apparently the mirrored 3rd party type must also implement Clone due to a derive(Clone) in frb_generated.rs, is this intended?

#[derive(Clone)]
pub struct mirror_MyEnum(crate::api::simple::MyEnum);

Steps to reproduce

  1. flutter_rust_bridge_codegen create repro_frb
  2. cd repro_frb
  3. cargo new --lib rust-3rdparty
  4. Modify and add Enum in rust-3rdparty/src/lib.rs
    #[derive(Clone)]
    pub enum MyEnum {
        Foo,
        Bar,
        Baz,
    }
  5. Modify rust/Cargo.toml to have dependency on rust-3rdparty
    [dependencies]
    rust-3rdparty = { path = "../rust-3rdparty" }
  6. Modify rust/src/api/simple.rs
    pub use rust_3rdparty::MyEnum;
    
    use crate::frb_generated::StreamSink;
    
    #[flutter_rust_bridge::frb(mirror(MyEnum))]
    pub enum _MyEnum {
        Foo,
        Bar,
        Baz,
    }
    
    pub fn get_enum() -> MyEnum {
        MyEnum::Foo
    }
    
    pub fn stream_enum(_sink: StreamSink<MyEnum>) {}
  7. flutter_rust_bridge_codegen generate

Logs

N/A

Expected behavior

Rust bridge can compile

Generated binding code

No response

OS

Windows

Version of flutter_rust_bridge_codegen

2.0.0-dev.28

Flutter info

No response

Version of clang++

No response

Additional context

No response

@SilverMira SilverMira added the bug Something isn't working label Mar 27, 2024
@fzyzcjy
Copy link
Owner

fzyzcjy commented Mar 27, 2024

Hmm, do you mean it is OK if we do either be return value or be in stream sink, but error if we do both; Or can the minimal reproducible sample be further reduced to halves?

I noticed that apparently the mirrored 3rd party type must also implement Clone due to a derive(Clone) in frb_generated.rs, is this intended?

If your enum does not support clone (or have other special properties), maybe just make it opaque instead of mirroring it.

@fzyzcjy fzyzcjy added the awaiting Waiting for responses, PR, further discussions, upstream release, etc label Mar 27, 2024
@SilverMira
Copy link
Contributor Author

The error happens as long as there is a mirrored Enum used in a StreamSink, even if the mirrored Enum is never used as a return value. Cargo check shows that the compilation error is within the generated code when instantiating the actual StreamSink during the .stream_sink call

StreamSink::new(
    context
        .rust2dart_context()
        .stream_sink::<_, MyEnum>(),
)

If MyEnum is not mirrored, then FRB generates it as opaque, which does compile, but makes it harder to use on the Dart land

@SilverMira
Copy link
Contributor Author

While messing around with the generated code, it looks like the crate can compile if I manually changed the following.

StreamSink::new(
    context
        .rust2dart_context()
        .stream_sink::<_, mirror_MyEnum>(), // codegen had MyEnum as the generic type originally
)

Additionally, not sure if I encountered the same issue but in another way, I'm getting the same compilation error if there is a StreamSink<Option<TestStruct>> where TestStruct is opaque.

#[flutter_rust_bridge::frb(opaque)]
pub struct TestStruct {}
pub fn stream_struct(_sink: StreamSink<TestStruct>) {}
pub fn stream_struct_option(_sink: StreamSink<Option<TestStruct>>) {}

I looked at the StreamSink instantiation for stream_struct and stream_struct_option and noticed there was a difference. The ordinary StreamSink<TestStruct> which is compiling fine uses Local_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockTestStruct as the generic type while the problematic StreamSink<Option<TestStruct>> was just using Option<TestStruct> as the generic type. Manually replacing the Option<TestStruct> generic type within frb_generated.rs with Option<Local_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockTestStruct> in fact fixed the compilation issue and Dart land is even receiving the objects correctly.

frb_generated.rs
fn wire_stream_struct_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: "stream_struct", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Stream }, 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 ||  {
                         Result::<_,()>::Ok(crate::api::simple::stream_struct(StreamSink::new(context.rust2dart_context().stream_sink::<_,Local_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedrust_asyncRwLockTestStruct>())))
                    })())
                } })
}
fn wire_stream_struct_option_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: "stream_struct_option",
            port: Some(port_),
            mode: flutter_rust_bridge::for_generated::FfiCallMode::Stream,
        },
        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 || {
                    Result::<_, ()>::Ok(crate::api::simple::stream_struct_option(StreamSink::new(
                        context
                            .rust2dart_context()
                            .stream_sink::<_, Option<TestStruct>>(), // <---- Problematic?
                    )))
                })())
            }
        },
    )
}

@fzyzcjy
Copy link
Owner

fzyzcjy commented Mar 27, 2024

it looks like the crate can compile if I manually changed the following

Briefly check it and it looks like it should be mirror_Something. For example, from pure_dart example we can see some working code looks like:

image

Feel free to PR to fix it! Alternatively I will work on it in the next batch (hopefully within several days)

Manually replacing the Option generic type within frb_generated.rs with

Good observation! Then looks like it is missing generating this.

Copy link
Contributor

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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 14, 2024
@fzyzcjy fzyzcjy removed the awaiting Waiting for responses, PR, further discussions, upstream release, etc label Jun 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants