rustype / typestate-rs

Proc-macro typestate DSL for Rust
https://rustype.github.io/typestate-rs/
Apache License 2.0
141 stars 11 forks source link

How to use this inside a struct for my egui app. #47

Open IAMSolaara opened 3 months ago

IAMSolaara commented 3 months ago

Hello, I'm trying to use this crate to make my egui app's page navigation.

I have this in my app:

#[typestate]
mod page_navigator {
    #[automaton]
    pub struct Page {}

    #[state]
    pub struct FirstPage;
    #[state]
    pub struct SecondPage;

    pub trait FirstPage {
        fn init() -> FirstPage;
        fn next_page(self) -> SecondPage;
    }

    pub trait SecondPage {
        fn prev_page(self) -> FirstPage;
        fn close(self);
    }
}

impl FirstPageState for Page<FirstPage> {
    fn init() -> Page<FirstPage> {
        Self { state: FirstPage }
    }

    fn next_page(self) -> Page<SecondPage> {
        Page::<SecondPage> { state: SecondPage }
    }
}

impl SecondPageState for Page<SecondPage> {
    fn prev_page(self) -> Page<FirstPage> {
        Page::<FirstPage> { state: FirstPage }
    }

    fn close(self) {
    }
}

I want to put this inside my egui app's App struct:

#[tokio::main]
async fn main() -> eframe::Result {
    eframe::run_native(
        "page_test_app",
        eframe::NativeOptions::default(),
        Box::new(|_cc| Ok(Box::new(App::init()))),
    )
}

struct App {
    current_app_page: Page<FirstPage>,
}

impl App {
    pub fn init() -> Self {
        Self {
            current_app_page: Page::init(),
        }
    }
}

and so far it compiles fine. But obviously when I want to change the page I need to reassign the current_app_page field to the new transitioned state problems arise because of the field's type:

impl eframe::App for App {
    fn update(&mut self, ctx: &eframe::egui::Context, frame: &mut eframe::Frame) {
        eframe::egui::CentralPanel::default().show(ctx, |ui| {
            if ui.button("Next Page").clicked() {
                self.current_app_page = self.current_app_page.next_page();
            }
        });
    }
}

How do I go about this?

Should I make my whole App struct generic over my PageState?

I apologize for the quality of this issue but I really don't know what would be a good way to do this.

jmg-duarte commented 3 months ago

Hey @IAMSolaara, I am grateful you took the time to experiment with the crate! No worries about the issue quality, the project was developed as my MSc thesis and I'll be the first to admit it isn't production ready, maybe someday and issues like these definitely help!

Should I make my whole App struct generic over my PageState?

The answer is yes, there's really no other way about it. I know this has really big implications but it's an implicit issue that comes from the advantages of Rust's type system.

If I may ask, how did you find this crate?