flutter_rust_bridge icon indicating copy to clipboard operation
flutter_rust_bridge copied to clipboard

How to use generics traits?

Open NightBlaze opened this issue 1 year ago • 3 comments

Not sure is it an issue or I do something wrong.

Demo project available here: https://github.com/NightBlaze/generics-frb

I use stateful architecture with the next structure for each screen:

Dart part:

  1. UI (screen.dart file https://github.com/NightBlaze/generics-frb/blob/main/lib/root_screen.dart ) • it's just UI without logic which calls Rust code and receive responses via stream.

Rust part:

  1. Logic (screen_name_logic.rs file https://github.com/NightBlaze/generics-frb/blob/main/rust/src/api/screens/root_screen/root_screen_logic.rs ) • it's exposes ScreenNameLogic struct without any public fields, just functions. • it implements interior mutability pattern • it holds view_model_sink: Option<StreamSink<ScreenNameViewModel>> field • it holds a state of a screen

  2. State (screen_name_state.rs file https://github.com/NightBlaze/generics-frb/blob/main/rust/src/api/screens/root_screen/root_screen_state.rs ) • it's a simple struct. • it has a pub(crate) fn render(&self) -> ScreenNameViewModel to create a view model. Technically it's Into trait but I decided to not use it.

  3. ViewModel (screen_name_view_model.rs file https://github.com/NightBlaze/generics-frb/blob/main/rust/src/api/screens/root_screen/root_screen_view_models.rs ) • it's a simple struct without any logic.

So every ScreenNameLogic has a function to render state like this one:

fn render_state(&self) {
    if let Some(sink) = self.view_model_sink.as_ref() {
        if let Err(error) = sink.add(self.state.render()) {
            debug_log(format!("[ScreenName] Fail to add view model to sink. Error: {:?}", error));
        }
        return;
    }
    debug_log("[ScreenName] Expected to be view_model_sink not null but it's null".to_string());
}

and it's a good candidate to make it generics ( https://github.com/NightBlaze/generics-frb/blob/main/rust/src/api/screens/renderer.rs )

pub(crate) trait Renderable {
    type ViewModel;

    fn render(&self) -> Self::ViewModel;
}

pub(crate) fn render<T, U>(
    sink: &Option<StreamSink<T>>,
    state: &U,
    screen_name: &str,
)
where
    T: SseEncode,
    U: Renderable<ViewModel = T>,
{
    if let Some(sink) = sink.as_ref() {
        if let Err(error) = sink.add(state.render()) {
            println!("[{}] Fail to add view model to sink. Error: {:?}", screen_name, error);
        }
        return;
    }
    println!("[{}] Expected to be sink not null but it's null", screen_name);
}

flutter_rust_bridge_codegen generate works without any errors but there is an error in frb_generated.rs

cannot find type `ViewModel` in this scope

I tried to make all pub but still have the error.

So my questions are:

  1. How to use generic traits?
  2. Will there be an error "duplication of ViewModel name" in the code when I'll implemented the Renderable trait for another struct State?

I use frb v. 2.1.0

NightBlaze avatar Jul 26 '24 11:07 NightBlaze

IMHO generics is not supported yet - thus it may not be able to be used currently. However, is good to have it implemented! Feel free to PR, alternatively I may work on it later, but since this is a nontrivial new feature, I cannot guarantee it will be done very soon.

fzyzcjy avatar Jul 26 '24 12:07 fzyzcjy

Got it. Thanks.

I'll be glad to create a PR but don't have enough proficient in Rust and Dart :(

NightBlaze avatar Jul 26 '24 17:07 NightBlaze

You are welcome and it's OK!

fzyzcjy avatar Jul 27 '24 00:07 fzyzcjy

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.

stale[bot] avatar Sep 29 '24 23:09 stale[bot]

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[bot] avatar Oct 26 '24 03:10 github-actions[bot]