Frame v0.7.1
This release adds a bunch of new functionality to the Rust runtime interface. As before, runtime support can be enabled by configuring Framec with codegen.rust.features.runtime_support=true.
Live rendering of state machines to smcat
Framec already supported rendering state machines can now be rendered to smcat. However, now this can be done for live state machines via the runtime interface. The advantage of doing this at runtime is that we can modify the visualization to reflect things like the currently active state and the last transition.
The rendering interface includes a lot of configurability in the styling of generated smcat visualizations. Two built-in styles are provided: a SimpleStyle that embeds simple styling info directly in the smcat file (e.g. highlighting the active state by thick red lines), and a CssStyle that generates an smcat file where each element is annotated by CSS classes that can be styled in a separate CSS file.
For more details, see the code and documentation at frame_runtime::smcat.
New callback interface for events
Frame events include interface method calls and state enter/exit events--basically, anything that can be handled in Frame by defining a corresponding handler associated with a state.
You can now register callbacks to be notified of Frame events. Callbacks can be registered via two methods, both associated with the EventMonitor obtainable via the runtime interface from a state machine instance:
add_event_sent_callback-- Adds a callback that will be invoked whenever an event is sent.add_event_handled_callback-- Adds a callback that will be invoked whenever an event has been completely handled.
The sent callbacks will be invoked for events in the more intuitive order. For example, if calling method m triggers a transition from state A to state B, then the callbacks will be invoked for events "m" (the method call), "A:<" (old state exit event), and "B:>" (new state enter event), in that order. However, because the handler for m will not have terminated yet until the transition is complete, the event "m" received by the callback will not yet contain the return value of m (since it hasn't been computed yet).
The handled callbacks will be invoked when the handlers for each event have completed. So, for the scenario above, the callbacks will be invoked in the order "A:<", "B:>", "m", since the handler for m doesn't terminate until after the transition. However, in this case, the event "m" received by the callback will contain the return value.
In all cases, the events received by the callback are references wrapped in Rc<..>, so they can be freely saved. The return value for an event received via a sent callback will be updated when the handler terminates, so if this event is saved, it's return value will be accessible later.
Most clients will probably want to be notified of events in the more intuitive order provided by add_event_sent_callback. However, add_event_handled_callback is provided in case the return value is needed at the time the callback is invoked.
Configurable event and transition history
The runtime interface (again via the EventMonitor) now maintains a history of recent events and transitions. The histories can be obtained via get_event_history and get_transition_history.
The length of history maintained can be configured via set_event_history_capacity and set_transition_history_capacity, which take values of type Option<usize>. A None value indicates an unbounded history, while Some(n) indicates a history bounded to size n. The history feature can be disabled by setting the capacity to Some(0).
By default, the history capacities are set to Some(0) (disabled) for the event history and Some(1) (maintain the last transition only) for the transition history. This minimizes memory impact if these features are not needed.
The default values can be configured via the new Framec configuration options codegen.rust.runtime.event_history_capacity and codegen.rust.runtime.transition_history_capacity, configurable via YAML or the attribute system, as usual. As with the built-in defaults, these can be overridden at runtime using the set_ methods listed above.
Events in the event history are listed in the order the events were sent. The history stores Rc<..> references to each event, which will be updated as the event is handled. In particular, the return value of an event (if any) will be set once the event has been fully handled.
Smaller changes
The runtime interface now provides the following additional features:
- A method to get the initial state from a state machine.
- A method to get all top-level states from a machine.
- A unique ID is associated with each transition to enable disambiguating between multiple transitions between the same two states.
- A convenience method to get the last transition from the transition history.