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

Custom errors fail to generate code

MatthewLM opened this issue · comments

Describe the bug

Code generation for custom errors with an enum does not work as described here: https://cjycode.com/flutter_rust_bridge/v1/feature/lang_exceptions.html

Steps to reproduce

Cargo.toml:

[package]
name = "native-test"
version = "1.0.0"
edition = "2021"

[lib]
crate-type = ["staticlib", "cdylib"]

[build-dependencies]
flutter_rust_bridge_codegen = "1.82.*"

[dependencies]
flutter_rust_bridge = "1.82.*"

[workspace]

build.rs:

use lib_flutter_rust_bridge_codegen::{
  config_parse, frb_codegen, get_symbols_if_no_duplicates, RawOpts,
};

const RUST_INPUT: &str = "src/api.rs";
const DART_OUTPUT: &str = "../testlib/lib/src/rust_bindings/rust_ffi.g.dart";

fn main() {
  // Tell Cargo that if the input Rust code changes, rerun this build script
  println!("cargo:rerun-if-changed={}", RUST_INPUT);

  // Options for frb_codegen
  let raw_opts = RawOpts {
    rust_input: vec![RUST_INPUT.to_string()],
    dart_output: vec![DART_OUTPUT.to_string()],
    inline_rust: true,
    wasm: false,
    ..Default::default()
  };

  // Generate Rust & Dart ffi bridges
  let configs = config_parse(raw_opts);
  let all_symbols = get_symbols_if_no_duplicates(&configs).unwrap();
  for config in configs.iter() {
    frb_codegen(config, &all_symbols).unwrap();
  }

}

api.rs:

pub enum CustomError {
    Error0(String),
    Error1(u32),
}

pub fn return_err_custom_error() -> Result<u32, CustomError> {
    Err(CustomError::Error1(3))
}

Logs

error: failed to run custom build command for `native-test v1.0.0 (/native-test)`
Caused by:
  process didn't exit successfully: `/native-test/target/debug/build/native-test-068ef4a2d3c191c3/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-changed=src/api.rs
  the path is "/tmp/.tmp1Nei0l.h"
  --- stderr
  thread 'main' panicked at build.rs:25:39:
  called `Result::unwrap()` on an `Err` value: Failed to run build_runner for /native-test/../testlib:
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

2024/03/19 15:38:11 [ERROR] panicked at /.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-1.82.6/src/commands.rs:316:17:
cargo expand returned empty output
thread 'main' panicked at /.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-1.82.6/src/commands.rs:316:17:
cargo expand returned empty output

Expected behavior

No response

Generated binding code

No response

OS

Linux Debian 12

Version of flutter_rust_bridge_codegen

1.82.6

Flutter info

No response

Version of clang++

Debian clang version 14.0.6

Additional context

No response

Hi, since cargo expand returned empty output, could you please manually run cargo expand and see what it outputs? In addition, try RUST_LOG=debug flutter_rust_bridge_codegen your_args and see whether there are more outputs about this.

Btw, I wonder whether it works for v2. (But anyway this should also work for v1)

@fzyzcjy For cargo expand (after disabling/renaming build.rs) I get the following:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
mod api {
    pub enum CustomError {
        Error0(String),
        Error1(u32),
    }
    pub fn return_err_custom_error() -> Result<u32, CustomError> {
        Err(CustomError::Error1(3))
    }
}
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_return_err_custom_error_impl(port_: MessagePort) {
        FLUTTER_RUST_BRIDGE_HANDLER
            .wrap::<
                _,
                _,
                _,
                u32,
                _,
            >(
                WrapInfo {
                    debug_name: "return_err_custom_error",
                    port: Some(port_),
                    mode: FfiCallMode::Normal,
                },
                move || move |task_callback| return_err_custom_error(),
            )
    }
    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 CustomError {
        fn into_dart(self) -> support::DartAbi {
            match self {
                Self::Error0(field0) => {
                    <[_]>::into_vec(
                        #[rustc_box]
                        ::alloc::boxed::Box::new([
                            0.into_dart(),
                            field0.into_into_dart().into_dart(),
                        ]),
                    )
                }
                Self::Error1(field0) => {
                    <[_]>::into_vec(
                        #[rustc_box]
                        ::alloc::boxed::Box::new([
                            1.into_dart(),
                            field0.into_into_dart().into_dart(),
                        ]),
                    )
                }
            }
                .into_dart()
        }
    }
    impl support::IntoDartExceptPrimitive for CustomError {}
    impl rust2dart::IntoIntoDart<CustomError> for CustomError {
        fn into_into_dart(self) -> Self {
            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"))]
    mod io {
        use super::*;
        #[no_mangle]
        pub extern "C" fn wire_return_err_custom_error(port_: i64) {
            wire_return_err_custom_error_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 self::io::*;
}

The full output of RUST_LOG=debug flutter_rust_bridge_codegen (with some paths changed for confidentiality):

2024/03/20 13:40:09 [DEBUG] configs=[Opts { rust_input_path: "/home/user/native-test/src/api.rs", dart_output_path: "/home/user/native-test/../libtest/lib/src/rust_bindings/rust_ffi.g.dart", dart_decl_output_path: None, c_output_path: ["/tmp/.tmpP5EDx5.h"], rust_crate_dir: "/home/user/native-test", rust_output_path: "/home/user/native-test/src/bridge_generated.rs", class_name: "FrostyRust", 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: "/home/user/native-test/Cargo.toml", dart_root: Some("/home/user/native-test/../libtest"), build_runner: true, block_index: BlockIndex(0), skip_deps_check: false, wasm_enabled: false, inline_rust: false, bridge_in_method: true, extra_headers: "", dart3: true, keep_going: false }]
2024/03/20 13:40:09 [INFO] Running cargo expand in '/home/user/native-test'
2024/03/20 13:40:09 [DEBUG] execute command: bin=cargo args="expand --theme=none --ugly" current_dir=Some("/home/user/native-test") cmd=cd "/home/user/native-test" && "cargo" "expand" "--theme=none" "--ugly"
2024/03/20 13:40:11 [WARN] command=cd "/home/user/native-test" && "cargo" "expand" "--theme=none" "--ugly" stdout= stderr=   Compiling native_test v1.0.0 (/home/user/native-test)
error: failed to run custom build command for `native_test v1.0.0 (/home/user/native-test)`
Caused by:
  process didn't exit successfully: `/home/user/native-test/target/debug/build/native_test-7cb4e83b02959147/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-changed=src/api.rs
  the path is "/tmp/.tmp46Vplx.h"
  --- stderr
  thread 'main' panicked at build.rs:25:39:
  called `Result::unwrap()` on an `Err` value: Failed to run build_runner for /home/user/native-test/../libtest:
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

2024/03/20 13:40:11 [ERROR] panicked at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-1.82.6/src/commands.rs:316:17:
cargo expand returned empty output
thread 'main' panicked at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-1.82.6/src/commands.rs:316:17:
cargo expand returned empty output
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I haven't tried v2 yet. I can take a look and try it out.

@fzyzcjy I installed v2 and made relevant adjustments and code generation works for the custom errors. The formatting of the generated rust_ffi.g.dart is horrible though with stuff like:

@freezed
                 class CustomError with _$CustomError implements FrbException {
                     const factory CustomError.error0(  String field0,) = CustomError_Error0;
 const factory CustomError.error1(  int field0,) = CustomError_Error1;
                }

Is this a fix that can be made for v1? When is v2 likely to become stable?

Thank you.

The formatting of the generated rust_ffi.g.dart is horrible though with stuff like:

That looks like a bug! Could you please create another issue?

Is this a fix that can be made for v1? When is v2 likely to become stable?

It is already quite stable IMHO (e.g. go through the issue tracker and see how many real bugs except for how-to-install etc). I make it still beta because, quoting README.md: I want to keep it in beta for a while (though CI has all passed), to allow publishing API breaking changes, and hear your thoughts and suggestions about it! That said, it almost will not have breaking changes from now on, and the probability of having a breaking change that requires more than a few minutes to migrate is even smaller.

I created another issue here: #1828

I can start migration to v2 if that is the best thing to do. If it isn't going to be fixed for v1 then this issue can be closed.

Thank you.

I will take a look at that issue. Yes, I personally suggest to migrate to v2. You are welcome!

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.