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.23k stars 291 forks source link

[Bug] Mirroring does not work for external Enums as function return values, only as parts of structs #1384

Closed CollinDietz closed 10 months ago

CollinDietz commented 1 year ago

Describe the bug

I cannot mirror an external enum to flutter by returning it from a function unless it is be used as a value in a struct.

pub use external_crate::SomeEnum;
#[frb(mirror(SomeEnum))]
pub enum _SomeEnum {
    Item1,
    Item2,
    Item3,
    Item4,
    Item5,
    Item6,
    Item7,
    Item8,
    Item9,
}

// doesnt work
pub fn some_enum() -> SomeEnum {
    SomeEnum::Item1
}

pub use external_crate::SomeOtherStruct;
#[frb(mirror(SomeOtherStruct))]
pub struct _SomeOtherStruct {
    pub a: u8,
    pub b: u16,
    pub c: SomeEnum
}

// works!
pub fn some_other_struct() -> SomeOtherStruct {
    SomeOtherStruct { a: 0, b: 0, c: SomeEnum::Item1 }
}

Minimum reproducible example: bug.zip Just unzip and run / look at run_me.sh

native/src/api.rs:33-35 are the lines that cause the failure, commenting them out makes it all happy

Note: I don't see any barfing until I run cargo build inside of native/, which might be incorrect? But I would expect the rust lib to be buildable after code gen

Codegen logs with RUST_LOG=debug environment variable

~/code/bug$ RUST_LOG=debug flutter_rust_bridge_codegen
Found config file .flutter_rust_bridge.yml
2023/10/04 23:30:35 [DEBUG] configs=[Opts { rust_input_path: "/Users/collindietz/code/bug/native/src/api.rs", dart_output_path: "/Users/collindietz/code/bug/dart/bridge_generated.dart", dart_decl_output_path: Some("/Users/collindietz/code/bug/dart/bridge_definitions.dart"), c_output_path: ["/Users/collindietz/code/bug/ios/Runner/bridge_generated.h", "macos/Runner/bridge_generated.h"], rust_crate_dir: "/Users/collindietz/code/bug/native", rust_output_path: "/Users/collindietz/code/bug/native/src/bridge_generated.rs", class_name: "Native", dart_format_line_length: 80, dart_enums_style: false, skip_add_mod_to_lib: false, llvm_path: ["/opt/homebrew/opt/llvm", "/usr/local/opt/llvm", "/usr/lib/llvm-9", "/usr/lib/llvm-10", "/usr/lib/llvm-11", "/usr/lib/llvm-12", "/usr/lib/llvm-13", "/usr/lib/llvm-14", "/usr/lib/", "/usr/lib64/", "C:/Program Files/llvm", "C:/msys64/mingw64"], llvm_compiler_opts: "", manifest_path: "/Users/collindietz/code/bug/native/Cargo.toml", dart_root: Some("/Users/collindietz/code/bug/dart"), build_runner: true, block_index: BlockIndex(0), skip_deps_check: false, wasm_enabled: true, inline_rust: false, bridge_in_method: true, extra_headers: "", dart3: true, keep_going: false }]
2023/10/04 23:30:35 [INFO] Running cargo expand in '/Users/collindietz/code/bug/native'
2023/10/04 23:30:35 [DEBUG] execute command: bin=cargo args="expand --theme=none --ugly" current_dir=Some("/Users/collindietz/code/bug/native") cmd=cd "/Users/collindietz/code/bug/native" && "cargo" "expand" "--theme=none" "--ugly"
2023/10/04 23:30:35 [DEBUG] command=cd "/Users/collindietz/code/bug/native" && "cargo" "expand" "--theme=none" "--ugly" stdout=#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
mod api {
    use flutter_rust_bridge::frb;
    pub use external_crate::SomeEnum;
    /// frb_marker: #[frb(mirror(SomeEnum))]
    pub enum _SomeEnum {
        Item1,
        Item2,
        Item3,
        Item4,
        Item5,
        Item6,
        Item7,
        Item8,
        Item9,
    }
    pub use external_crate::SomeStruct;
    /// frb_marker: #[frb(mirror(SomeStruct))]
    pub struct _SomeStruct {
        pub a: u8,
        pub b: u16,
    }
    pub use external_crate::SomeOtherStruct;
    /// frb_marker: #[frb(mirror(SomeOtherStruct))]
    pub struct _SomeOtherStruct {
        pub a: u8,
        pub b: u16,
        pub c: SomeEnum,
    }
    pub fn some_enum() -> SomeEnum { SomeEnum::Item1 }
    pub fn some_struct() -> SomeStruct { SomeStruct { a: 0, b: 0 } }
    pub fn some_other_struct() -> SomeOtherStruct {
        SomeOtherStruct { a: 0, b: 0, c: SomeEnum::Item1 }
    }
}
mod bridge_generated {
    #![allow(non_camel_case_types, unused, clippy :: redundant_closure, clippy
    :: useless_conversion, clippy :: unit_arg, clippy :: double_parens,
    non_snake_case, clippy :: too_many_arguments)]
    use crate::api::*;
    use core::panic::UnwindSafe;
    use flutter_rust_bridge::rust2dart::IntoIntoDart;
    use flutter_rust_bridge::*;
    use std::ffi::c_void;
    use std::sync::Arc;
    fn wire_some_enum_impl(port_: MessagePort) {
        FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, SomeEnum,
            _>(WrapInfo {
                debug_name: "some_enum",
                port: Some(port_),
                mode: FfiCallMode::Normal,
            }, move || move |task_callback| Result::<_, ()>::Ok(some_enum()))
    }
    fn wire_some_struct_impl(port_: MessagePort) {
        FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, mirror_SomeStruct,
            _>(WrapInfo {
                debug_name: "some_struct",
                port: Some(port_),
                mode: FfiCallMode::Normal,
            },
            move || move |task_callback| Result::<_, ()>::Ok(some_struct()))
    }
    fn wire_some_other_struct_impl(port_: MessagePort) {
        FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, mirror_SomeOtherStruct,
            _>(WrapInfo {
                debug_name: "some_other_struct",
                port: Some(port_),
                mode: FfiCallMode::Normal,
            },
            move ||
                move |task_callback| Result::<_, ()>::Ok(some_other_struct()))
    }
    pub struct mirror_SomeEnum(SomeEnum);
    #[automatically_derived]
    impl ::core::clone::Clone for mirror_SomeEnum {
        #[inline]
        fn clone(&self) -> mirror_SomeEnum {
            mirror_SomeEnum(::core::clone::Clone::clone(&self.0))
        }
    }
    pub struct mirror_SomeOtherStruct(SomeOtherStruct);
    #[automatically_derived]
    impl ::core::clone::Clone for mirror_SomeOtherStruct {
        #[inline]
        fn clone(&self) -> mirror_SomeOtherStruct {
            mirror_SomeOtherStruct(::core::clone::Clone::clone(&self.0))
        }
    }
    pub struct mirror_SomeStruct(SomeStruct);
    #[automatically_derived]
    impl ::core::clone::Clone for mirror_SomeStruct {
        #[inline]
        fn clone(&self) -> mirror_SomeStruct {
            mirror_SomeStruct(::core::clone::Clone::clone(&self.0))
        }
    }
    const _: fn() =
        ||
            {
                match None::<SomeEnum>.unwrap() {
                    SomeEnum::Item1 => {}
                    SomeEnum::Item2 => {}
                    SomeEnum::Item3 => {}
                    SomeEnum::Item4 => {}
                    SomeEnum::Item5 => {}
                    SomeEnum::Item6 => {}
                    SomeEnum::Item7 => {}
                    SomeEnum::Item8 => {}
                    SomeEnum::Item9 => {}
                }
                {
                    let SomeOtherStruct = None::<SomeOtherStruct>.unwrap();
                    let _: u8 = SomeOtherStruct.a;
                    let _: u16 = SomeOtherStruct.b;
                    let _: SomeEnum = SomeOtherStruct.c;
                }
                {
                    let SomeStruct = None::<SomeStruct>.unwrap();
                    let _: u8 = SomeStruct.a;
                    let _: u16 = SomeStruct.b;
                }
            };
    pub trait Wire2Api<T> {
        fn wire2api(self)
        -> T;
    }
    impl<T, S> Wire2Api<Option<T>> for *mut S where *mut S: Wire2Api<T> {
        fn wire2api(self) -> Option<T> {
            (!self.is_null()).then(|| self.wire2api())
        }
    }
    impl support::IntoDart for mirror_SomeEnum {
        fn into_dart(self) -> support::DartAbi {
            match self.0 {
                    SomeEnum::Item1 => 0,
                    SomeEnum::Item2 => 1,
                    SomeEnum::Item3 => 2,
                    SomeEnum::Item4 => 3,
                    SomeEnum::Item5 => 4,
                    SomeEnum::Item6 => 5,
                    SomeEnum::Item7 => 6,
                    SomeEnum::Item8 => 7,
                    SomeEnum::Item9 => 8,
                }.into_dart()
        }
    }
    impl support::IntoDartExceptPrimitive for mirror_SomeEnum {}
    impl rust2dart::IntoIntoDart<mirror_SomeEnum> for SomeEnum {
        fn into_into_dart(self) -> mirror_SomeEnum { mirror_SomeEnum(self) }
    }
    impl support::IntoDart for mirror_SomeOtherStruct {
        fn into_dart(self) -> support::DartAbi {
            <[_]>::into_vec(#[rustc_box] ::alloc::boxed::Box::new([self.0.a.into_into_dart().into_dart(),
                                self.0.b.into_into_dart().into_dart(),
                                self.0.c.into_into_dart().into_dart()])).into_dart()
        }
    }
    impl support::IntoDartExceptPrimitive for mirror_SomeOtherStruct {}
    impl rust2dart::IntoIntoDart<mirror_SomeOtherStruct> for SomeOtherStruct {
        fn into_into_dart(self) -> mirror_SomeOtherStruct {
            mirror_SomeOtherStruct(self)
        }
    }
    impl support::IntoDart for mirror_SomeStruct {
        fn into_dart(self) -> support::DartAbi {
            <[_]>::into_vec(#[rustc_box] ::alloc::boxed::Box::new([self.0.a.into_into_dart().into_dart(),
                                self.0.b.into_into_dart().into_dart()])).into_dart()
        }
    }
    impl support::IntoDartExceptPrimitive for mirror_SomeStruct {}
    impl rust2dart::IntoIntoDart<mirror_SomeStruct> for SomeStruct {
        fn into_into_dart(self) -> mirror_SomeStruct {
            mirror_SomeStruct(self)
        }
    }
    #[allow(missing_copy_implementations)]
    #[allow(non_camel_case_types)]
    #[allow(dead_code)]
    pub struct FLUTTER_RUST_BRIDGE_HANDLER {
        __private_field: (),
    }
    #[doc(hidden)]
    pub static FLUTTER_RUST_BRIDGE_HANDLER: FLUTTER_RUST_BRIDGE_HANDLER =
        FLUTTER_RUST_BRIDGE_HANDLER { __private_field: () };
    impl ::lazy_static::__Deref for FLUTTER_RUST_BRIDGE_HANDLER {
        type Target = support::DefaultHandler;
        fn deref(&self) -> &support::DefaultHandler {
            #[inline(always)]
            fn __static_ref_initialize() -> support::DefaultHandler {
                Default::default()
            }
            #[inline(always)]
            fn __stability() -> &'static support::DefaultHandler {
                static LAZY:
                    ::lazy_static::lazy::Lazy<support::DefaultHandler> =
                    ::lazy_static::lazy::Lazy::INIT;
                LAZY.get(__static_ref_initialize)
            }
            __stability()
        }
    }
    impl ::lazy_static::LazyStatic for FLUTTER_RUST_BRIDGE_HANDLER {
        fn initialize(lazy: &Self) { let _ = &**lazy; }
    }
    #[cfg(not(target_family = "wasm"))]
    #[path = "bridge_generated.io.rs"]
    mod io {
        use super::*;
        #[no_mangle]
        pub extern "C" fn wire_some_enum(port_: i64) {
            wire_some_enum_impl(port_)
        }
        #[no_mangle]
        pub extern "C" fn wire_some_struct(port_: i64) {
            wire_some_struct_impl(port_)
        }
        #[no_mangle]
        pub extern "C" fn wire_some_other_struct(port_: i64) {
            wire_some_other_struct_impl(port_)
        }
        pub trait NewWithNullPtr {
            fn new_with_null_ptr()
            -> Self;
        }
        impl<T> NewWithNullPtr for *mut T {
            fn new_with_null_ptr() -> Self { std::ptr::null_mut() }
        }
        #[no_mangle]
        pub extern "C" fn free_WireSyncReturn(ptr: support::WireSyncReturn) {
            unsafe { let _ = support::box_from_leak_ptr(ptr); };
        }
    }
    #[cfg(not(target_family = "wasm"))]
    pub use io::*;
}
 stderr=    Checking native v0.1.0 (/Users/collindietz/code/bug/native)
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s

2023/10/04 23:30:35 [DEBUG] Trying to parse "/Users/collindietz/code/bug/native/src/api.rs"
2023/10/04 23:30:35 [DEBUG] Trying to parse "/Users/collindietz/code/bug/native/src/bridge_generated.rs"
2023/10/04 23:30:35 [DEBUG] parse_function function name: Ident(some_enum)
2023/10/04 23:30:35 [DEBUG] parse_function function name: Ident(some_struct)
2023/10/04 23:30:35 [DEBUG] parse_function function name: Ident(some_other_struct)
2023/10/04 23:30:35 [INFO] Phase: Validate config(s)
2023/10/04 23:30:35 [INFO] Picked config: Opts { rust_input_path: "/Users/collindietz/code/bug/native/src/api.rs", dart_output_path: "/Users/collindietz/code/bug/dart/bridge_generated.dart", dart_decl_output_path: Some("/Users/collindietz/code/bug/dart/bridge_definitions.dart"), c_output_path: ["/Users/collindietz/code/bug/ios/Runner/bridge_generated.h", "macos/Runner/bridge_generated.h"], rust_crate_dir: "/Users/collindietz/code/bug/native", rust_output_path: "/Users/collindietz/code/bug/native/src/bridge_generated.rs", class_name: "Native", dart_format_line_length: 80, dart_enums_style: false, skip_add_mod_to_lib: false, llvm_path: ["/opt/homebrew/opt/llvm", "/usr/local/opt/llvm", "/usr/lib/llvm-9", "/usr/lib/llvm-10", "/usr/lib/llvm-11", "/usr/lib/llvm-12", "/usr/lib/llvm-13", "/usr/lib/llvm-14", "/usr/lib/", "/usr/lib64/", "C:/Program Files/llvm", "C:/msys64/mingw64"], llvm_compiler_opts: "", manifest_path: "/Users/collindietz/code/bug/native/Cargo.toml", dart_root: Some("/Users/collindietz/code/bug/dart"), build_runner: true, block_index: BlockIndex(0), skip_deps_check: false, wasm_enabled: true, inline_rust: false, bridge_in_method: true, extra_headers: "", dart3: true, keep_going: false }
2023/10/04 23:30:35 [INFO] Phase: Parse source code to AST, then to IR
2023/10/04 23:30:35 [DEBUG] Trying to parse "/Users/collindietz/code/bug/native/src/api.rs"
2023/10/04 23:30:35 [DEBUG] Trying to parse "/Users/collindietz/code/bug/native/src/bridge_generated.rs"
2023/10/04 23:30:35 [DEBUG] parse_function function name: Ident(some_enum)
2023/10/04 23:30:35 [DEBUG] parse_function function name: Ident(some_struct)
2023/10/04 23:30:35 [DEBUG] parse_function function name: Ident(some_other_struct)
2023/10/04 23:30:35 [INFO] Phase: Transform IR
2023/10/04 23:30:35 [INFO] Phase: Generate Rust code
2023/10/04 23:30:35 [DEBUG] execute format_rust path=["/Users/collindietz/code/bug/native/src/bridge_generated.rs", "/Users/collindietz/code/bug/native/src/bridge_generated.io.rs", "/Users/collindietz/code/bug/native/src/bridge_generated.web.rs"]
2023/10/04 23:30:35 [DEBUG] execute command: bin=rustfmt args="/Users/collindietz/code/bug/native/src/bridge_generated.rs /Users/collindietz/code/bug/native/src/bridge_generated.io.rs /Users/collindietz/code/bug/native/src/bridge_generated.web.rs" current_dir=None cmd="rustfmt" "/Users/collindietz/code/bug/native/src/bridge_generated.rs" "/Users/collindietz/code/bug/native/src/bridge_generated.io.rs" "/Users/collindietz/code/bug/native/src/bridge_generated.web.rs"
2023/10/04 23:30:35 [DEBUG] command="rustfmt" "/Users/collindietz/code/bug/native/src/bridge_generated.rs" "/Users/collindietz/code/bug/native/src/bridge_generated.io.rs" "/Users/collindietz/code/bug/native/src/bridge_generated.web.rs" stdout= stderr=
2023/10/04 23:30:35 [INFO] Phase: Generate Dart code
2023/10/04 23:30:35 [DEBUG] Guessing toolchain the runner is run into
2023/10/04 23:30:35 [DEBUG] execute command: bin=sh args="-c \"dart\" \"--version\"" current_dir=None cmd="sh" "-c" "\"dart\" \"--version\""
2023/10/04 23:30:35 [DEBUG] command="sh" "-c" "\"dart\" \"--version\"" stdout=Dart SDK version: 3.1.3 (stable) (Tue Sep 26 14:25:13 2023 +0000) on "macos_arm64"
 stderr=
2023/10/04 23:30:35 [DEBUG] Checking presence of ffi in dependencies at /Users/collindietz/code/bug/dart
2023/10/04 23:30:35 [DEBUG] Checking presence of ffi in dependencies at /Users/collindietz/code/bug/dart
2023/10/04 23:30:35 [DEBUG] Checking presence of ffigen in dev_dependencies at /Users/collindietz/code/bug/dart
2023/10/04 23:30:35 [DEBUG] Checking presence of ffigen in dev_dependencies at /Users/collindietz/code/bug/dart
2023/10/04 23:30:35 [INFO] Phase: Generating Dart bindings for Rust
2023/10/04 23:30:35 [DEBUG] execute cbindgen rust_crate_dir=/Users/collindietz/code/bug/native c_output_path=/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpxgy7eY.h
2023/10/04 23:30:35 [DEBUG] cbindgen config: Config {
    header: None,
    includes: [],
    sys_includes: [
        "stdbool.h",
        "stdint.h",
        "stdlib.h",
    ],
    after_includes: Some(
        "typedef struct _Dart_Handle* Dart_Handle;",
    ),
    trailer: None,
    include_guard: None,
    pragma_once: false,
    no_includes: true,
    autogen_warning: None,
    include_version: false,
    namespace: None,
    namespaces: None,
    using_namespaces: None,
    braces: SameLine,
    line_length: 100,
    tab_width: 2,
    line_endings: LF,
    language: C,
    cpp_compat: false,
    style: Both,
    sort_by: None,
    usize_is_size_t: false,
    parse: ParseConfig {
        parse_deps: false,
        include: None,
        exclude: [],
        expand: ParseExpandConfig {
            crates: [],
            all_features: false,
            default_features: true,
            features: None,
            profile: Debug,
        },
        clean: false,
        extra_bindings: [],
    },
    export: ExportConfig {
        include: [
            "\"wire_SomeOtherStruct\"",
            "\"wire_SomeStruct\"",
        ],
        exclude: [],
        rename: {},
        pre_body: {},
        body: {},
        prefix: None,
        item_types: [],
        renaming_overrides_prefixing: false,
        mangle: MangleConfig {
            rename_types: None,
            remove_underscores: false,
        },
    },
    macro_expansion: MacroExpansionConfig {
        bitflags: false,
    },
    layout: LayoutConfig {
        packed: None,
        aligned_n: None,
    },
    function: FunctionConfig {
        prefix: None,
        postfix: None,
        must_use: None,
        args: Auto,
        rename_args: None,
        swift_name_macro: None,
        sort_by: None,
        no_return: None,
    },
    structure: StructConfig {
        rename_fields: None,
        derive_constructor: false,
        derive_eq: false,
        derive_neq: false,
        derive_lt: false,
        derive_lte: false,
        derive_gt: false,
        derive_gte: false,
        derive_ostream: false,
        associated_constants_in_body: false,
        must_use: None,
    },
    enumeration: EnumConfig {
        rename_variants: None,
        rename_variant_name_fields: SnakeCase,
        add_sentinel: false,
        prefix_with_name: false,
        derive_helper_methods: false,
        derive_const_casts: false,
        derive_mut_casts: false,
        cast_assert_name: None,
        must_use: None,
        derive_tagged_enum_destructor: false,
        derive_tagged_enum_copy_constructor: false,
        derive_tagged_enum_copy_assignment: false,
        derive_ostream: false,
        enum_class: true,
        private_default_tagged_enum_constructor: false,
    },
    constant: ConstantConfig {
        allow_static_const: true,
        allow_constexpr: true,
        sort_by: None,
    },
    defines: {},
    documentation: true,
    documentation_style: Auto,
    documentation_length: Full,
    pointer: PtrConfig {
        non_null_attribute: None,
    },
    only_target_dependencies: false,
    cython: CythonConfig {
        header: None,
        cimports: {},
    },
}
2023/10/04 23:30:35 [DEBUG] Parsing crate native
2023/10/04 23:30:35 [INFO] Take native::_SomeEnum - opaque (Enum is not marked with a valid #[repr(prim)] or #[repr(C)].).
2023/10/04 23:30:35 [INFO] Take native::_SomeStruct - opaque (Struct is not marked #[repr(C)] or #[repr(transparent)].).
2023/10/04 23:30:35 [INFO] Take native::_SomeOtherStruct - opaque (Struct is not marked #[repr(C)] or #[repr(transparent)].).
2023/10/04 23:30:35 [INFO] Take native::mirror_SomeEnum - opaque (Struct is not marked #[repr(C)] or #[repr(transparent)].).
2023/10/04 23:30:35 [INFO] Take native::mirror_SomeOtherStruct - opaque (Struct is not marked #[repr(C)] or #[repr(transparent)].).
2023/10/04 23:30:35 [INFO] Take native::mirror_SomeStruct - opaque (Struct is not marked #[repr(C)] or #[repr(transparent)].).
2023/10/04 23:30:35 [WARN] Skip native::_ - (not `pub`).
2023/10/04 23:30:35 [INFO] Take native::DartPort.
2023/10/04 23:30:35 [INFO] Take native::DartPostCObjectFnType.
2023/10/04 23:30:35 [INFO] Take native::store_dart_post_cobject.
2023/10/04 23:30:35 [INFO] Take native::get_dart_object.
2023/10/04 23:30:35 [INFO] Take native::drop_dart_object.
2023/10/04 23:30:35 [INFO] Take native::new_dart_opaque.
2023/10/04 23:30:35 [INFO] Take native::init_frb_dart_api_dl.
2023/10/04 23:30:35 [INFO] Take native::DartCObject - opaque (Struct is not marked #[repr(C)] or #[repr(transparent)].).
2023/10/04 23:30:35 [INFO] Take native::WireSyncReturn.
2023/10/04 23:30:35 [INFO] Take native::wire_some_enum.
2023/10/04 23:30:35 [INFO] Take native::wire_some_struct.
2023/10/04 23:30:35 [INFO] Take native::wire_some_other_struct.
2023/10/04 23:30:35 [INFO] Take native::free_WireSyncReturn.
2023/10/04 23:30:35 [WARN] Can't find Dart_Handle. This usually means that this type was incompatible or not found.
2023/10/04 23:30:35 [WARN] Can't find Dart_Handle. This usually means that this type was incompatible or not found.
2023/10/04 23:30:35 [WARN] Missing `[defines]` entry for `target_family = "wasm"` in cbindgen config.
2023/10/04 23:30:35 [WARN] Missing `[defines]` entry for `target_family = "wasm"` in cbindgen config.
2023/10/04 23:30:35 [WARN] Missing `[defines]` entry for `target_family = "wasm"` in cbindgen config.
2023/10/04 23:30:35 [WARN] Missing `[defines]` entry for `target_family = "wasm"` in cbindgen config.
2023/10/04 23:30:35 [DEBUG] execute ffigen c_path=/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpxgy7eY.h dart_path=/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpVoAg8J llvm_path=["/opt/homebrew/opt/llvm", "/usr/local/opt/llvm", "/usr/lib/llvm-9", "/usr/lib/llvm-10", "/usr/lib/llvm-11", "/usr/lib/llvm-12", "/usr/lib/llvm-13", "/usr/lib/llvm-14", "/usr/lib/", "/usr/lib64/", "C:/Program Files/llvm", "C:/msys64/mingw64"]
2023/10/04 23:30:35 [DEBUG] ffigen config: 
        output: '/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpVoAg8J'
        name: 'NativeWire'
        description: 'generated by flutter_rust_bridge'
        headers:
          entry-points:
            - '/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpxgy7eY.h'
          include-directives:
            - '/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpxgy7eY.h'
        comments: false
        preamble: |
          // ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names

        llvm-path:
           - '/opt/homebrew/opt/llvm'
           - '/usr/local/opt/llvm'
           - '/usr/lib/llvm-9'
           - '/usr/lib/llvm-10'
           - '/usr/lib/llvm-11'
           - '/usr/lib/llvm-12'
           - '/usr/lib/llvm-13'
           - '/usr/lib/llvm-14'
           - '/usr/lib/'
           - '/usr/lib64/'
           - 'C:/Program Files/llvm'
           - 'C:/msys64/mingw64'

2023/10/04 23:30:35 [DEBUG] ffigen config_file: NamedTempFile("/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpsAoNvG")
2023/10/04 23:30:35 [DEBUG] Guessing toolchain the runner is run into
2023/10/04 23:30:35 [DEBUG] execute command: bin=sh args="-c \"dart\" \"run\" \"ffigen\" \"--config\" \"/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpsAoNvG\"" current_dir=Some("/Users/collindietz/code/bug/dart") cmd=cd "/Users/collindietz/code/bug/dart" && "sh" "-c" "\"dart\" \"run\" \"ffigen\" \"--config\" \"/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpsAoNvG\""
2023/10/04 23:30:36 [DEBUG] command=cd "/Users/collindietz/code/bug/dart" && "sh" "-c" "\"dart\" \"run\" \"ffigen\" \"--config\" \"/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpsAoNvG\"" stdout=Running in Directory: '/Users/collindietz/code/bug/dart'
Input Headers: [/var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpxgy7eY.h]
[WARNING]: No definition found for declaration - (Cursor) spelling: _Dart_Handle, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct _Dart_Handle, usr: c:@S@_Dart_Handle
[WARNING]: No definition found for declaration - (Cursor) spelling: _Dart_Handle, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct _Dart_Handle, usr: c:@S@_Dart_Handle
[WARNING]: No definition found for declaration - (Cursor) spelling: DartCObject, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct DartCObject, usr: c:@S@DartCObject
[WARNING]: No definition found for declaration - (Cursor) spelling: DartCObject, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct DartCObject, usr: c:@S@DartCObject
[WARNING]: No definition found for declaration - (Cursor) spelling: _Dart_Handle, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct _Dart_Handle, usr: c:@S@_Dart_Handle
[WARNING]: No definition found for declaration - (Cursor) spelling: _Dart_Handle, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct _Dart_Handle, usr: c:@S@_Dart_Handle
[WARNING]: No definition found for declaration - (Cursor) spelling: _Dart_Handle, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct _Dart_Handle, usr: c:@S@_Dart_Handle
[WARNING]: No definition found for declaration - (Cursor) spelling: _Dart_Handle, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct _Dart_Handle, usr: c:@S@_Dart_Handle
[WARNING]: No definition found for declaration - (Cursor) spelling: DartCObject, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct DartCObject, usr: c:@S@DartCObject
[WARNING]: Generated declaration '_Dart_Handle' start's with '_' and therefore will be private.
Finished, Bindings generated in /var/folders/0_/15mxn1k15qd442ll80411kjh0000gr/T/.tmpVoAg8J
 stderr=
the path is "/Users/collindietz/code/bug/ios/Runner/bridge_generated.h"
the path is "macos/Runner/bridge_generated.h"
2023/10/04 23:30:36 [DEBUG] distinct_input_types=[]
2023/10/04 23:30:36 [DEBUG] distinct_output_types=[Primitive(I32), Delegate(PrimitiveEnum { ir: IrTypeEnumRef { name: "SomeEnum", is_exception: false }, repr: I32 }), StructRef(IrTypeStructRef { name: "SomeOtherStruct", freezed: false, empty: false, is_exception: false }), StructRef(IrTypeStructRef { name: "SomeStruct", freezed: false, empty: false, is_exception: false }), Primitive(U16), Primitive(U8)]
2023/10/04 23:30:36 [INFO] Phase: Running build_runner
2023/10/04 23:30:36 [INFO] Phase: Formatting Dart code
2023/10/04 23:30:36 [DEBUG] execute format_dart path=["/Users/collindietz/code/bug/dart/bridge_generated.dart", "/Users/collindietz/code/bug/dart/bridge_definitions.dart", "/Users/collindietz/code/bug/dart/bridge_generated.web.dart", "/Users/collindietz/code/bug/dart/bridge_generated.io.dart"] line_length=80
2023/10/04 23:30:36 [DEBUG] execute command: bin=sh args="-c \"dart\" \"format\" \"--line-length\" \"80\" \"/Users/collindietz/code/bug/dart/bridge_generated.dart\" \"/Users/collindietz/code/bug/dart/bridge_definitions.dart\" \"/Users/collindietz/code/bug/dart/bridge_generated.web.dart\" \"/Users/collindietz/code/bug/dart/bridge_generated.io.dart\"" current_dir=None cmd="sh" "-c" "\"dart\" \"format\" \"--line-length\" \"80\" \"/Users/collindietz/code/bug/dart/bridge_generated.dart\" \"/Users/collindietz/code/bug/dart/bridge_definitions.dart\" \"/Users/collindietz/code/bug/dart/bridge_generated.web.dart\" \"/Users/collindietz/code/bug/dart/bridge_generated.io.dart\""
2023/10/04 23:30:36 [DEBUG] command="sh" "-c" "\"dart\" \"format\" \"--line-length\" \"80\" \"/Users/collindietz/code/bug/dart/bridge_generated.dart\" \"/Users/collindietz/code/bug/dart/bridge_definitions.dart\" \"/Users/collindietz/code/bug/dart/bridge_generated.web.dart\" \"/Users/collindietz/code/bug/dart/bridge_generated.io.dart\"" stdout=Formatted /Users/collindietz/code/bug/dart/bridge_generated.dart
Formatted /Users/collindietz/code/bug/dart/bridge_definitions.dart
Formatted /Users/collindietz/code/bug/dart/bridge_generated.web.dart
Formatted /Users/collindietz/code/bug/dart/bridge_generated.io.dart
Formatted 4 files (4 changed) in 0.14 seconds.
 stderr=
2023/10/04 23:30:36 [INFO] Success!
2023/10/04 23:30:36 [INFO] Now go and use it :)
~/code/bug$ cd native/
~/code/bug/native::master$ cargo build
   Compiling native v0.1.0 (/Users/collindietz/code/bug/native)
error[E0277]: the trait bound `DartCObject: From<external_crate::SomeEnum>` is not satisfied
  --> src/bridge_generated.rs:26:49
   |
26 |     FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, SomeEnum, _>(
   |                                                 ^^^^^^^^ the trait `From<external_crate::SomeEnum>` is not implemented for `DartCObject`
   |
   = help: the following other types implement trait `From<T>`:
             <DartCObject as From<RustOpaque<T>>>
             <DartCObject as From<DartOpaque>>
   = note: required for `external_crate::SomeEnum` to implement `Into<DartCObject>`
   = note: required for `external_crate::SomeEnum` to implement `flutter_rust_bridge::IntoDart`
note: required by a bound in `wrap`
  --> /Users/collindietz/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge-1.82.1/src/handler.rs:51:12
   |
46 |     fn wrap<PrepareFn, TaskFn, TaskRet, D, Er>(&self, wrap_info: WrapInfo, prepare: PrepareFn)
   |        ---- required by a bound in this associated function
...
51 |         D: IntoDart,
   |            ^^^^^^^^ required by this bound in `Handler::wrap`

error[E0277]: the trait bound `external_crate::SomeEnum: IntoIntoDart<external_crate::SomeEnum>` is not satisfied
  --> src/bridge_generated.rs:26:46
   |
26 |     FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, SomeEnum, _>(
   |                                              ^ the trait `IntoIntoDart<external_crate::SomeEnum>` is not implemented for `external_crate::SomeEnum`
   |
   = help: the trait `IntoIntoDart<mirror_SomeEnum>` is implemented for `external_crate::SomeEnum`
note: required by a bound in `wrap`
  --> /Users/collindietz/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge-1.82.1/src/handler.rs:50:18
   |
46 |     fn wrap<PrepareFn, TaskFn, TaskRet, D, Er>(&self, wrap_info: WrapInfo, prepare: PrepareFn)
   |        ---- required by a bound in this associated function
...
50 |         TaskRet: IntoIntoDart<D>,
   |                  ^^^^^^^^^^^^^^^ required by this bound in `Handler::wrap`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `native` (lib) due to 2 previous errors
~/code/bug/native::master$

To Reproduce

Expected behavior

External enums should be mirror-able to flutter without needing to be stored inside of a struct

Generated binding code

bridge_generated.h

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct _Dart_Handle* Dart_Handle;

typedef struct DartCObject DartCObject;

typedef int64_t DartPort;

typedef bool (*DartPostCObjectFnType)(DartPort port_id, void *message);

typedef struct DartCObject *WireSyncReturn;

void store_dart_post_cobject(DartPostCObjectFnType ptr);

Dart_Handle get_dart_object(uintptr_t ptr);

void drop_dart_object(uintptr_t ptr);

uintptr_t new_dart_opaque(Dart_Handle handle);

intptr_t init_frb_dart_api_dl(void *obj);

void wire_some_enum(int64_t port_);

void wire_some_struct(int64_t port_);

void wire_some_other_struct(int64_t port_);

void free_WireSyncReturn(WireSyncReturn ptr);

static int64_t dummy_method_to_enforce_bundling(void) {
    int64_t dummy_var = 0;
    dummy_var ^= ((int64_t) (void*) wire_some_enum);
    dummy_var ^= ((int64_t) (void*) wire_some_struct);
    dummy_var ^= ((int64_t) (void*) wire_some_other_struct);
    dummy_var ^= ((int64_t) (void*) free_WireSyncReturn);
    dummy_var ^= ((int64_t) (void*) store_dart_post_cobject);
    dummy_var ^= ((int64_t) (void*) get_dart_object);
    dummy_var ^= ((int64_t) (void*) drop_dart_object);
    dummy_var ^= ((int64_t) (void*) new_dart_opaque);
    return dummy_var;
}

bridge_generated.dart

// AUTO GENERATED FILE, DO NOT EDIT.
// Generated by `flutter_rust_bridge`@ 1.82.1.
// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const

import "bridge_definitions.dart";
import 'dart:convert';
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
import 'package:uuid/uuid.dart';
import 'bridge_generated.io.dart'
    if (dart.library.html) 'bridge_generated.web.dart';

class NativeImpl implements Native {
  final NativePlatform _platform;
  factory NativeImpl(ExternalLibrary dylib) =>
      NativeImpl.raw(NativePlatform(dylib));

  /// Only valid on web/WASM platforms.
  factory NativeImpl.wasm(FutureOr<WasmModule> module) =>
      NativeImpl(module as ExternalLibrary);
  NativeImpl.raw(this._platform);
  Future<SomeEnum> someEnum({dynamic hint}) {
    return _platform.executeNormal(FlutterRustBridgeTask(
      callFfi: (port_) => _platform.inner.wire_some_enum(port_),
      parseSuccessData: _wire2api_some_enum,
      parseErrorData: null,
      constMeta: kSomeEnumConstMeta,
      argValues: [],
      hint: hint,
    ));
  }

  FlutterRustBridgeTaskConstMeta get kSomeEnumConstMeta =>
      const FlutterRustBridgeTaskConstMeta(
        debugName: "some_enum",
        argNames: [],
      );

  Future<SomeStruct> someStruct({dynamic hint}) {
    return _platform.executeNormal(FlutterRustBridgeTask(
      callFfi: (port_) => _platform.inner.wire_some_struct(port_),
      parseSuccessData: _wire2api_some_struct,
      parseErrorData: null,
      constMeta: kSomeStructConstMeta,
      argValues: [],
      hint: hint,
    ));
  }

  FlutterRustBridgeTaskConstMeta get kSomeStructConstMeta =>
      const FlutterRustBridgeTaskConstMeta(
        debugName: "some_struct",
        argNames: [],
      );

  Future<SomeOtherStruct> someOtherStruct({dynamic hint}) {
    return _platform.executeNormal(FlutterRustBridgeTask(
      callFfi: (port_) => _platform.inner.wire_some_other_struct(port_),
      parseSuccessData: _wire2api_some_other_struct,
      parseErrorData: null,
      constMeta: kSomeOtherStructConstMeta,
      argValues: [],
      hint: hint,
    ));
  }

  FlutterRustBridgeTaskConstMeta get kSomeOtherStructConstMeta =>
      const FlutterRustBridgeTaskConstMeta(
        debugName: "some_other_struct",
        argNames: [],
      );

  void dispose() {
    _platform.dispose();
  }
// Section: wire2api

  int _wire2api_i32(dynamic raw) {
    return raw as int;
  }

  SomeEnum _wire2api_some_enum(dynamic raw) {
    return SomeEnum.values[raw as int];
  }

  SomeOtherStruct _wire2api_some_other_struct(dynamic raw) {
    final arr = raw as List<dynamic>;
    if (arr.length != 3)
      throw Exception('unexpected arr length: expect 3 but see ${arr.length}');
    return SomeOtherStruct(
      a: _wire2api_u8(arr[0]),
      b: _wire2api_u16(arr[1]),
      c: _wire2api_some_enum(arr[2]),
    );
  }

  SomeStruct _wire2api_some_struct(dynamic raw) {
    final arr = raw as List<dynamic>;
    if (arr.length != 2)
      throw Exception('unexpected arr length: expect 2 but see ${arr.length}');
    return SomeStruct(
      a: _wire2api_u8(arr[0]),
      b: _wire2api_u16(arr[1]),
    );
  }

  int _wire2api_u16(dynamic raw) {
    return raw as int;
  }

  int _wire2api_u8(dynamic raw) {
    return raw as int;
  }
}

// Section: api2wire

// Section: finalizer

### OS

Mac OS 13.5, ARM Chip

### Version of `flutter_rust_bridge_codegen`

1.82.1

### Flutter info
Note: this is a new comp so I haven't setup all the flutter target stuff yet, but I the same issue on my previous more setup mac

```shell
~/code/bug/native::master$ flutter doctor -v
[✓] Flutter (Channel stable, 3.13.6, on macOS 13.5 22G74 darwin-arm64, locale en-US)
    • Flutter version 3.13.6 on channel stable at /Users/collindietz/flutter/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ead455963c (8 days ago), 2023-09-26 18:28:17 -0700
    • Engine revision a794cf2681
    • Dart version 3.1.3
    • DevTools version 2.25.0

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[✗] Xcode - develop for iOS and macOS
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS and macOS development.
      Download at: https://developer.apple.com/xcode/download/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
        sudo xcodebuild -runFirstLaunch
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To install see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.

[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).

[✓] VS Code (version 1.83.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (1 available)
    • macOS (desktop) • macos • darwin-arm64 • macOS 13.5 22G74 darwin-arm64

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 4 categories.

Version of clang++

Apple clang version 14.0.3 (clang-1403.0.22.14.1)

Version of ffigen

8.0.2

Additional context

Globally installed Cargo packages

cargo-expand v1.0.72:
    cargo-expand
flutter_rust_bridge_codegen v1.82.1:
    flutter_rust_bridge_codegen
fzyzcjy commented 1 year ago

https://github.com/fzyzcjy/flutter_rust_bridge/blob/b585ab532c078af5151f7160e4efc398437ac02c/frb_example/pure_dart/rust/src/api.rs#L695 shows that we can mirror a enum, but yes it is only used within a struct

#[frb(mirror(ApplicationMode))]
pub enum _ApplicationMode {
    Standalone,
    Embedded,
}

Thus I suspect this may be a missing feature. Feel free to PR! (The implementation may not be super hard because we can somehow follow existing code for struct etc)

CollinDietz commented 1 year ago

New-ish to rust and all of this, can you point me to the pieces of implementation to reference?

fzyzcjy commented 1 year ago

Sure, the first step may be https://cjycode.com/flutter_rust_bridge/contributing/design.html

stale[bot] commented 10 months 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 10 months 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.