mdeloof / statig

Hierarchical state machines for designing event-driven systems
https://crates.io/crates/statig
MIT License
560 stars 18 forks source link

Allow generics to be used in the state machine #7

Closed k3d3 closed 1 year ago

k3d3 commented 1 year ago

I'm trying to add an FnMut to a state machine via:

pub struct Thing<F>
where
    F: FnMut(Signal)
{
    emit: F
}

#[state_machine(initial = "State::init()")]
impl<F> Thing<F>
where
    F: FnMut(Signal),
{

in order to allow a state machine to emit a signal as it handles transitions. Unfortunately, adding generics like that to the state machine appears to cause a proc macro panic that just says error: custom attribute panicked with message: expected function call expression

When I run RUSTFLAGS="-Z proc-macro-backtrace" cargo +nightly check, I get the following lines in the backtrace:

  16:     0x7fe276683569 - core::panicking::panic_display::hbb06a95bf5a75324
  17:     0x7fe27663a60c - syn::parse_quote::parse::h36c31769ce163720
  18:     0x7fe27667b8bb - statig_macro::lower::lower_state::h72f60dda88bc84b7
  19:     0x7fe27664e470 - statig_macro::lower::lower::{{closure}}::hafaf3d3de1282b22
  20:     0x7fe27666c0ab - core::iter::adapters::map::map_fold::{{closure}}::h2a21cabf95abed4d
  21:     0x7fe27665e579 - core::iter::traits::iterator::Iterator::fold::ha24dab897807eb32
  22:     0x7fe27666abc2 - <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold::h97d4d2d660189e34
  23:     0x7fe27666b79f - core::iter::traits::iterator::Iterator::for_each::h78d7f095ca550b39
  24:     0x7fe276636e9a - <hashbrown::map::HashMap<K,V,S,A> as core::iter::traits::collect::Extend<(K,V)>>::extend::h407fb9dd206eee45
  25:     0x7fe27665d7d5 - <std::collections::hash::map::HashMap<K,V,S> as core::iter::traits::collect::FromIterator<(K,V)>>::from_iter::h0325534979972350
  26:     0x7fe27666b47c - core::iter::traits::iterator::Iterator::collect::hb88b7d1cd8683440
  27:     0x7fe2766784a6 - statig_macro::lower::lower::he8b7b3aa35a21378
  28:     0x7fe27663eaef - statig_macro::state_machine::{{closure}}::h25adf5f267d5cf6b
  29:     0x7fe27666e706 - <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::haed139dfc15334ae
  30:     0x7fe27665ec9d - std::panicking::try::do_call::haa01aefa55582a9c
  31:     0x7fe27665f0bb - __rust_try
  32:     0x7fe27665e7de - std::panicking::try::h239dda7bdbd68854
  33:     0x7fe276681fed - std::panic::catch_unwind::h2aef9b4fc512d321
  34:     0x7fe276674b70 - proc_macro_error::entry_point::h249af567a823643d
  35:     0x7fe27666898b - statig_macro::state_machine::hfdbd09263af6b545
  36:     0x7fe276656824 - core::ops::function::Fn::call::h98bd3f42fef67228

Unfortunately for some reason I can't seem to get line numbers for the lines that occur within statig_macro, however I tried to narrow down the line causing the issue, and it appears to be this line in lower.rs, in the lower_state function:

let handler_call =
        parse_quote!(#shared_storage_type::#state_handler_name(#(#handler_inputs),*));

Unfortunately I'm not very good with proc macros, so I'm not sure how to further debug this, but hopefully this is helpful?

Alternatively, perhaps I just screwed something up. In any case, let me know if there's anything else I can do to help diagnose this.

Thanks!

mdeloof commented 1 year ago

Hi!

For the moment the proc macro does not support using generics. It's something that is on my to-do list but I haven't gotten around to it yet. For now if you want to use generics you will have to manually write the state machine as in the no_macro examples.

In the mean time I'll see if I can add an error message to the proc macro when it encounters generics so it is at least clear to the user it's not supported.

I'll also keep this issue open as I agree that generics should be supported eventually.

matthewgapp commented 1 year ago

Leaving a comment here as I'd love to use generics with macros, too. I see that you've added a working example on the master branch so looks like it's coming soon 👀

mdeloof commented 1 year ago

Yes, I've been working on it and it will be part of the 0.3 update. What's there seems to working pretty well, but I still have some refactoring to do and add additional tests.

mdeloof commented 1 year ago

Added in 5b910ce.

As generics and the associated bounds can get quite complicated it's possible that there are edge case that the macro doesn't yet handle. If you encounter such a situation feel free to open an issue and I'll take a look ;).

k3d3 commented 1 year ago

This is perfect. Thank you!