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.26k stars 300 forks source link

3rd party types can't be constructed #2103

Closed virtualritz closed 4 months ago

virtualritz commented 4 months ago

Describe the bug

TLDR; There must be an automatic way to translate methods for 3rd party types used in a public API translated by frb.

Many struct-based types have only private members. They require a method being called to constcut them or a builder being created that will spit them out. When these options are not available on the Dart side, the type can't be constructed.

Specifically, I'm using PathBuf in my public API.

How do I construct a PathBuf on the Dart side?

It seems only stuff that is marked with #[frb(...)] gets translated. But PathBuf is part of a 3rd party crate (std) so I can't impl on it because of Rust's orphan rules.

I also don't want to create a wrapper struct MyPathBuf(PathBuf) because the amounf of boilerplate this approach entails (and the naming mess) for any 3rd party type is nuts. I.e. it would make using frb as labor-intensive, as the old way, via a manual FFI.

See also #310. But PathBuf is just one of a gazillion types I may want to use.

virtualritz commented 4 months ago

On that note: it seems 3rd party trait impls also do not get translated.

I have a std::convert::TryFrom impl:

impl TryFrom<String> for FileInfo {
    type Error = anyhow::Error;

    #[frb(sync)]
    fn try_from(string: String) -> Result<Self> {
        let path_buf = PathBuf::from(string);
        Ok(Self {
            metadata: Metadata::try_from(path_buf.clone())?,
            path: path_buf,
        })
    }
}

But there is no tryFrom() generated on the Dart side. What am I missing?

fzyzcjy commented 4 months ago

How do I conctruct a PathBuf on the Dart side?

There are several ways (possibly I should add sth into doc):

  1. Use https://cjycode.com/flutter_rust_bridge/guides/third-party/automatic/override-methods. i.e. #[ext] pub impl PathLib { fn new() -> ... }. That essentially creates a trait an an impl.
  2. For this specific one, https://cjycode.com/flutter_rust_bridge/guides/types/translatable/custom may be interesting, e.g. you may want String on dart side.

On that note: it seems 3rd party trait impls also do not get translated.

IIRC I chose to disable it originally because, for example, the following scenario:

What do you think? I guess maybe we either can find out some way to solve things like that, or maybe we can provide an attribute like #[frb(unignore)] to force something to be scanned.

virtualritz commented 4 months ago

It would really be helpful to have a way to tell frb to reflect all methods of a type (or crate) to the Dart side.

The approach you suggested again means I have to write a ton of boilerplate. Look at the number of methods on e.g. BigDecimal (#2106). I don't want to type them all in rust/third-party/bigdecimal/mod.rs.

No difference if I go for wrapping those methods as you suggest in the Override Methods guide.

One of the reasons to use frb over the old approach with a hand-crafted FFI and PODs is the promise of easy-peasy type interchange between the languanges.

But as far as Rust goes this need to include easy-peasy exposition of methods because many types are opaque and if they're 3rd party types, this can't be changed. So member access and construction is handled exclusively through methods. Exposing these methods on the Dart side with a single attribute or the like should be possible.

What do you think? I guess maybe we either can find out some way to solve things like that, or maybe we can provide an attribute like #[frb(unignore)] to force something to be scanned.

Why would the #[frb(sync)] (or any frb attribute) on a trait method not be enough to tell frb to reflect that trait impl on the Dart side? Why would a new atrribute be needed?

fzyzcjy commented 4 months ago

It would really be helpful to have a way to tell frb to reflect all methods of a type (or crate) to the Dart side. I don't want to type them all in rust/third-party/bigdecimal/mod.rs. Exposing these methods on the Dart side with a single attribute or the like should be possible.

That's what https://cjycode.com/flutter_rust_bridge/guides/third-party aims to solve! We should not type them manually and it should be one-click.

The approach you suggested again means I have to write a ton of boilerplate. Look at the number of methods on e.g. BigDecimal (https://github.com/fzyzcjy/flutter_rust_bridge/issues/2106). I don't want to type them all in rust/third-party/bigdecimal/mod.rs.

No, I suggested the manual way because it is PathBuf. For example:

Why would the #[frb(sync)] (or any frb attribute) on a trait method not be enough to tell frb to reflect that trait impl on the Dart side? Why would a new atrribute be needed?

Nice suggestion! So the rule may be:

github-actions[bot] commented 4 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.