-
Notifications
You must be signed in to change notification settings - Fork 257
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
Access external library #1903
Comments
So after a bit of tinkering, I found out that you actually seem to support this in a way: https://cjycode.com/flutter_rust_bridge/guides/types/translatable/external/diff-crate I do still have issues with enums, which might be resolved by this. I will update this post once I figure out more. |
So I've experimented some more and I think I fugured out a bit more about how you handle those external types. My problem is, that I'm interested in these functions, which seems to leave me only one choice at the moment: From what I can see, I have 2 issues at the moment:
Just so you don't get the wrong impression: Nothing is worse than a forum entry with "nvm, I fixed it" at the end |
Happy to hear that flutter+rust+flutter_rust_bridge is good for you! Yes, the current way may be using the https://cjycode.com/flutter_rust_bridge/guides/types/translatable/external/diff-crate feature. However, I am also considering scanning 3rd party crates (e.g. last time someone also raised scenarios like yours when there are 3rd party crate that is controllable).
This can be done via https://cjycode.com/flutter_rust_bridge/guides/miscellaneous/methods#methods-in-external-crates (a feature added recently) |
Sorry, I can't use it according to https://cjycode.com/flutter_rust_bridge/guides/miscellaneous/methods#methods-in-external-crates using my external crate: impl MyClient {
pub async fn get_posts(&self, tags: Vec<String>, limit: usize, page: usize) -> Result<Vec<crate::model::Post>, Box<dyn std::error::Error>> {
}
pub async fn download_to_file(&self, url: String, file_path: String, progress_callback: impl Fn(usize, usize) + 'static) -> Result<(), Box<dyn std::error::Error>> {
}
pub async fn download_to_memory(&self, url: String, progress_callback: impl Fn(usize, usize) + 'static) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
}
} frb: struct MyClient{
}
#[frb(external)]
impl MyClient{
pub fn new() -> Self{}
pub async fn get_posts(&self, tags: Vec<String>, limit: usize, page: usize) -> Result<Vec<Post>, Box<dyn std::error::Error>>{ }
pub async fn download_to_file(&self, url: String, file_path: String, progress_callback: impl Fn(usize, usize)->DartFnFuture<()> + 'static) -> Result<(), Box<dyn std::error::Error>>{}
pub async fn download_to_memory(&self, url: String, progress_callback: impl Fn(usize, usize) ->DartFnFuture<()>+ 'static) -> Result<Vec<u8>, Box<dyn std::error::Error>>{}
} got dart: @sealed
class Post extends RustOpaque {
Post.dcoDecode(List<dynamic> wire) : super.dcoDecode(wire, _kStaticData);
Post.sseDecode(int ptr, int externalSizeOnNative)
: super.sseDecode(ptr, externalSizeOnNative, _kStaticData);
static final _kStaticData = RustArcStaticData(
rustArcIncrementStrongCount:
RustLib.instance.api.rust_arc_increment_strong_count_Post,
rustArcDecrementStrongCount:
RustLib.instance.api.rust_arc_decrement_strong_count_Post,
rustArcDecrementStrongCountPtr:
RustLib.instance.api.rust_arc_decrement_strong_count_PostPtr,
);
} |
I want to automatically mirror the model of the external crate |
Hi, |
In my personal opinion that's actually fine for most uses, as you're mostly working with "methods" most of the time anyway. For my use case I'll try using a compination of It would be really cool to enable reading the information automatically though. Maybe something like this? // this allows accessing the public fields of the struct,
// so the default implementation if the type was defined inside api
frb_external_mirror!(external_crate::submodule::MyStruct)
// this allows using the methods and function associated with a type
// A lot of types don't have public fields, which means this would allow to use most libraries already.
frb_external_opaque!(external_crate::submodule::MyApiHandler) That would require scanning the external crate, which sounds kind of difficult or at least like it's a pain to implement.
I think throwing an error asking to write the whole path (e.g.:
I'm not sure that is even neccesary. Usually the programmer using the bridge would have to decide I think.
I think all cases should be treated as if the person using frb doesn't have access to the crate. Conceptually a crate implies that it's usable with other code too, not just within a project, otherwise you'd just use submodules, right? I'll try working with the |
so I couldn't test if the generated code works yet, but I have no doubts it will. @normalllll Here's my example for anyone else looking for some code which demonstrates using an external library: use anyhow::Result;
use flutter_rust_bridge::frb;
// if you want to use external methods you need a *pub* use statement!!!
pub use svalin::client::{Client, FirstConnect, Init, Login};
// Once you have aquired your type with the pub use statement, you can mirror the function signatures.
#[frb(external)]
impl Client {
pub fn get_profiles() -> Result<Vec<String>> {} // as by the docs, you don't need a function body here
pub async fn first_connect(address: String) -> Result<FirstConnect> {}
}
// If you want to forward the internal structure instead, you can use mirror to tell frb the signature of your type
// Be sure to prefix your original struct name with an underscore to avoid a name conflict.
// you don't need this if you just want to access functions. this is only required if you want to read the fields of a struct
#[frb(non_opaque, mirror(FirstConnect))]
pub enum _FirstConnect {
Init(Init),
Login(Login),
}
// once again you just mirror the function signature here
#[frb(external)]
impl Init {
pub async fn init(&self) -> Result<()> {}
}
#[frb(external)]
impl Login {
pub async fn login(&self) -> Result<()> {}
} Edit: fixed missing non_opaque on enum - required when part of the enum is opaque but the enum itself shouldn't be |
Looks reasonable!
Based on discussions above, here are more brainstorms:
|
That's exactly what I meant. With this functionality it would be a breeze to use any rust crate in flutter. |
Totally agree. Maybe we can firstly try our best to derive everything automatically, and only when something does not work (e.g. very weird types), skip it and require users to manually do something (e.g. make a thin wrapper using a few lines of code) |
I'm pretty new to rust so more complex code is stilll difficult for me to work with, but let me know if I can help in any way. |
Possibly related: #1911 |
That sounds pretty much like what I'm doing right now. Basically you'd need a resolver which finds out which crate a type is from and then looks up where to find the relevant code in the Cargo.toml. That could be a local directory, git repo or something from crates.io. That sounds possible, but also like a lot of work, so maybe implementing this in small steps would be better. It would already be really cool if mirror(Type) could look up the definition by itself. That still requires a hell lot of work, but it's probably more doable. |
For my use-case, having opaque types is good enough. And mirroring the types that do not have to be opaque, while somewhat cumbersome, is fine, too. |
For future readers: Related - #1980 |
Is your feature request related to a problem? Please describe.
This might already be possible, but I didn't find out how.
I already have a rust crate which exposes a library. I would like to use this library in flutter.
I can call the library functions if I just write some wrappers in the api folder, but I would love to tell FRB to scan my already existing library.
Is that somehow possible?
While I could try to write wrappers, I'd need wrappers for every struct and function in the library, which would be quite a lot.
Describe the solution you'd like
Some way to embed my already existing library with this project. Maybe just setting a symlink from the /api dir to the could work?
Describe alternatives you've considered
I don't think I have any, as I need both headless variants of my program as well as a gui version
Additional context
Damn you, after experimenting a bit with this project I don't want to go back to any other gui framework for rust.
Everything else feels so clunky and flutter_rust_bridge is just way to easy and fun :P
The text was updated successfully, but these errors were encountered: