org.reactfx.StateMachine Maven / Gradle / Ivy
Show all versions of reactfx Show documentation
package org.reactfx;
import static org.reactfx.util.LL.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import javafx.beans.binding.Binding;
import org.reactfx.StateMachine.InitialState;
import org.reactfx.StateMachine.ObservableStateBuilder;
import org.reactfx.StateMachine.ObservableStateBuilderOn;
import org.reactfx.StateMachine.StatefulStreamBuilder;
import org.reactfx.StateMachine.StatefulStreamBuilderOn;
import org.reactfx.util.LL;
import org.reactfx.util.Tuple2;
public class StateMachine {
public interface InitialState {
ObservableStateBuilderOn on(EventStream input);
}
public interface ObservableStateBuilder {
ObservableStateBuilderOn on(EventStream input);
/**
* Returns an event stream that emits the current state of the state
* machine every time it changes.
*/
EventStream toStateStream();
/**
* Returns a binding that reflects the current state of the state
* machine. Disposing the returned binding (by calling its
* {@code dispose()} method) causes the state machine to unsubscribe
* from the event streams that alter its state and allows the state
* machine to be garbage collected.
*/
Binding toObservableState();
}
public interface StatefulStreamBuilder {
StatefulStreamBuilderOn on(EventStream input);
/**
* Returns an event stream that emits a value when one of the state
* machine's input streams causes the state machine to emit a value.
*
* The returned event stream is lazily bound, meaning the
* associated state machine is subscribed to its inputs only when the
* returned stream has at least one subscriber. No state transitions
* take place unless there is a subscriber to the returned stream. If
* you need to keep the state machine alive even when temporarily not
* subscribed to the returned stream, you can pin the returned
* stream.
*/
EventStream toEventStream();
}
public interface ObservableStateBuilderOn {
ObservableStateBuilder transition(BiFunction super S, ? super I, ? extends S> f);
StatefulStreamBuilder emit(BiFunction super S, ? super I, Optional> f);
StatefulStreamBuilder transmit(BiFunction super S, ? super I, Tuple2>> f);
}
public interface StatefulStreamBuilderOn {
StatefulStreamBuilder transition(BiFunction super S, ? super I, ? extends S> f);
StatefulStreamBuilder emit(BiFunction super S, ? super I, Optional> f);
StatefulStreamBuilder transmit(BiFunction super S, ? super I, Tuple2>> f);
}
public static InitialState init(S initialState) {
return new InitialStateImpl<>(initialState);
}
}
class InitialStateImpl implements InitialState {
private final S initialState;
public InitialStateImpl(S initialState) {
this.initialState = initialState;
}
@Override
public ObservableStateBuilderOn on(EventStream input) {
return new ObservableStateBuilderOnImpl<>(initialState, nil(), input);
}
}
class ObservableStateBuilderImpl implements ObservableStateBuilder {
private final S initialState;
private final LL> transitions;
ObservableStateBuilderImpl(S initialState, LL> transitions) {
this.initialState = initialState;
this.transitions = transitions;
}
@Override
public ObservableStateBuilderOn on(EventStream input) {
return new ObservableStateBuilderOnImpl<>(initialState, transitions, input);
}
@Override
public EventStream toStateStream() {
return new StateStream<>(initialState, transitions);
}
@Override
public Binding toObservableState() {
return toStateStream().toBinding(initialState);
}
}
class StateStream extends EventStreamBase {
private final InputHandler[] inputHandlers;
private S state;
public StateStream(S initialState, LL> transitions) {
inputHandlers = transitions.stream()
.map(t -> t.build(this::handleTransition))
.toArray(n -> new InputHandler[n]);
state = initialState;
}
@Override
protected Subscription observeInputs() {
return Subscription.multi(
InputHandler::subscribeToInput,
inputHandlers);
}
private void handleTransition(Function transition) {
state = transition.apply(state);
emit(state);
}
}
class StatefulStreamBuilderImpl implements StatefulStreamBuilder {
private final S initialState;
private final LL> transitions;
private final LL> emissions;
private final LL> transmissions;
StatefulStreamBuilderImpl(
S initialState,
LL> transitions,
LL> emissions,
LL> transmissions) {
this.initialState = initialState;
this.transitions = transitions;
this.emissions = emissions;
this.transmissions = transmissions;
}
@Override
public StatefulStreamBuilderOn on(EventStream input) {
return new StatefulStreamBuilderOnImpl<>(initialState, transitions, emissions, transmissions, input);
}
@Override
public EventStream toEventStream() {
return new StatefulStream<>(initialState, transitions, emissions, transmissions);
}
}
class StatefulStream extends EventStreamBase {
private final List inputHandlers;
private S state;
StatefulStream(
S initialState,
LL> transitions,
LL> emissions,
LL> transmissions) {
state = initialState;
this.inputHandlers = new ArrayList<>(transitions.size() + emissions.size() + transmissions.size());
for(TransitionBuilder tb: transitions) {
inputHandlers.add(tb.build(this::handleTransition));
}
for(EmissionBuilder eb: emissions) {
inputHandlers.add(eb.build(this::handleEmission));
}
for(TransmissionBuilder tb: transmissions) {
inputHandlers.add(tb.build(this::handleTransmission));
}
}
@Override
protected Subscription observeInputs() {
return Subscription.multi(
InputHandler::subscribeToInput,
inputHandlers);
}
private void handleTransition(Function transition) {
state = transition.apply(state);
}
private void handleEmission(Function> emission) {
emission.apply(state).ifPresent(this::emit);
}
private void handleTransmission(Function>> transmission) {
Tuple2> pair = transmission.apply(state);
state = pair._1;
pair._2.ifPresent(this::emit);
}
}
class ObservableStateBuilderOnImpl implements ObservableStateBuilderOn {
private final S initialState;
private final LL> transitions;
private final EventStream input;
ObservableStateBuilderOnImpl(
S initialState,
LL> transitions,
EventStream input) {
this.initialState = initialState;
this.transitions = transitions;
this.input = input;
}
@Override
public ObservableStateBuilder transition(
BiFunction super S, ? super I, ? extends S> f) {
TransitionBuilder transition = new TransitionBuilder<>(input, f);
return new ObservableStateBuilderImpl<>(initialState, cons(transition, transitions));
}
@Override
public StatefulStreamBuilder emit(
BiFunction super S, ? super I, Optional> f) {
EmissionBuilder emission = new EmissionBuilder<>(input, f);
return new StatefulStreamBuilderImpl<>(initialState, transitions, cons(emission, nil()), nil());
}
@Override
public StatefulStreamBuilder transmit(
BiFunction super S, ? super I, Tuple2>> f) {
TransmissionBuilder transmission = new TransmissionBuilder<>(input, f);
return new StatefulStreamBuilderImpl<>(initialState, transitions, nil(), cons(transmission, nil()));
}
}
class StatefulStreamBuilderOnImpl implements StatefulStreamBuilderOn {
private final S initialState;
private final LL> transitions;
private final LL> emissions;
private final LL> transmissions;
private final EventStream input;
StatefulStreamBuilderOnImpl(
S initialState,
LL> transitions,
LL> emissions,
LL> transmissions,
EventStream input) {
this.initialState = initialState;
this.transitions = transitions;
this.emissions = emissions;
this.transmissions = transmissions;
this.input = input;
}
@Override
public StatefulStreamBuilder transition(
BiFunction super S, ? super I, ? extends S> f) {
TransitionBuilder transition = new TransitionBuilder<>(input, f);
return new StatefulStreamBuilderImpl<>(initialState, cons(transition, transitions), emissions, transmissions);
}
@Override
public StatefulStreamBuilder emit(
BiFunction super S, ? super I, Optional> f) {
EmissionBuilder emission = new EmissionBuilder<>(input, f);
return new StatefulStreamBuilderImpl<>(initialState, transitions, cons(emission, emissions), transmissions);
}
@Override
public StatefulStreamBuilder transmit(
BiFunction super S, ? super I, Tuple2>> f) {
TransmissionBuilder transmission = new TransmissionBuilder<>(input, f);
return new StatefulStreamBuilderImpl<>(initialState, transitions, emissions, cons(transmission, transmissions));
}
}
interface InputHandler {
Subscription subscribeToInput();
}
class InputHandlerBuilder {
private final Function<
Consumer>,
InputHandler> inputSubscriberProvider;
public InputHandlerBuilder(EventStream input,
BiFunction super S, ? super I, ? extends TGT> f) {
this.inputSubscriberProvider = publisher -> {
return () -> input.subscribe(i -> publisher.accept(s -> f.apply(s, i)));
};
}
public InputHandler build(Consumer> c) {
return inputSubscriberProvider.apply(c);
}
}
class TransitionBuilder extends InputHandlerBuilder {
public TransitionBuilder(EventStream input,
BiFunction super S, ? super I, ? extends S> f) {
super(input, f);
}
}
class EmissionBuilder extends InputHandlerBuilder> {
public EmissionBuilder(EventStream input,
BiFunction super S, ? super I, ? extends Optional> f) {
super(input, f);
}
}
class TransmissionBuilder extends InputHandlerBuilder>> {
public TransmissionBuilder(EventStream input,
BiFunction super S, ? super I, ? extends Tuple2>> f) {
super(input, f);
}
}