Skip to content

Instantly share code, notes, and snippets.

@dnys1
Last active February 12, 2022 16:45
Show Gist options
  • Save dnys1/cd3df1fe5cb649ee82c47919b9fe4549 to your computer and use it in GitHub Desktop.
Save dnys1/cd3df1fe5cb649ee82c47919b9fe4549 to your computer and use it in GitHub Desktop.
import 'dart:async';
void main() {
final stateMachine = MyStateMachine();
// Dispatch three events synchronously. Notice how they are processed.
stateMachine.dispatch(MyEvent());
stateMachine.dispatch(MyEvent());
stateMachine.dispatch(MyEvent());
}
class MyStateMachine extends StateMachine<MyEvent, MyState> {
@override
MyState get initialState => MyState(0);
@override
Stream<MyState> transformEvent(MyEvent event) async* {
yield MyState(currentState.i + 1);
await Future.delayed(const Duration(seconds: 2));
yield MyState(currentState.i + 1);
}
}
class MyState extends State {
MyState(this.i);
final int i;
@override
String toString() => '$i';
}
class MyEvent extends Event {
@override
bool meetsPrecondition(MyState currentState) {
return true;
}
}
abstract class Event {
/// Whether the event can be processed given the [currentState]
/// of the state machine.
bool meetsPrecondition(covariant State currentState);
}
abstract class State {}
abstract class StateMachine<E extends Event, S extends State> {
StateMachine() {
_eventController.stream.asyncExpand((event) {
if (!event.meetsPrecondition(_currentState)) {
print('Skipping $event');
return Stream<S>.empty();
}
return transformEvent(event);
}).listen((state) {
print('Transitioning from $_currentState to $state');
_stateController.add(state);
_currentState = state;
});
}
final StreamController<E> _eventController = StreamController.broadcast();
final StreamController<S> _stateController = StreamController.broadcast();
/// The state machine's initial state.
S get initialState;
late S _currentState = initialState;
/// The state machine's current state.
S get currentState => _currentState;
/// The stream of states.
Stream<S> get stream => _stateController.stream;
/// Dispatches an event to the state machine.
void dispatch(E event) => _eventController.add(event);
/// Transforms events into a stream of state changes.
Stream<S> transformEvent(E event);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment