All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.reactfx.StateMachine Maven / Gradle / Ivy

There is a newer version: 1.11
Show newest version
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 f); StatefulStreamBuilder emit(BiFunction> f); StatefulStreamBuilder transmit(BiFunction>> f); } public interface StatefulStreamBuilderOn { StatefulStreamBuilder transition(BiFunction f); StatefulStreamBuilder emit(BiFunction> f); StatefulStreamBuilder transmit(BiFunction>> 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 f) { TransitionBuilder transition = new TransitionBuilder<>(input, f); return new ObservableStateBuilderImpl<>(initialState, cons(transition, transitions)); } @Override public StatefulStreamBuilder emit( BiFunction> f) { EmissionBuilder emission = new EmissionBuilder<>(input, f); return new StatefulStreamBuilderImpl<>(initialState, transitions, cons(emission, nil()), nil()); } @Override public StatefulStreamBuilder transmit( BiFunction>> 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 f) { TransitionBuilder transition = new TransitionBuilder<>(input, f); return new StatefulStreamBuilderImpl<>(initialState, cons(transition, transitions), emissions, transmissions); } @Override public StatefulStreamBuilder emit( BiFunction> f) { EmissionBuilder emission = new EmissionBuilder<>(input, f); return new StatefulStreamBuilderImpl<>(initialState, transitions, cons(emission, emissions), transmissions); } @Override public StatefulStreamBuilder transmit( BiFunction>> 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 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 f) { super(input, f); } } class EmissionBuilder extends InputHandlerBuilder> { public EmissionBuilder(EventStream input, BiFunction> f) { super(input, f); } } class TransmissionBuilder extends InputHandlerBuilder>> { public TransmissionBuilder(EventStream input, BiFunction>> f) { super(input, f); } }