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

org.reactfx.EventStream Maven / Gradle / Ivy

There is a newer version: 1.11
Show newest version
package org.reactfx;

import static org.reactfx.EventStreams.*;
import static org.reactfx.util.Tuples.*;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import javafx.application.Platform;
import javafx.beans.binding.Binding;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WritableValue;
import javafx.concurrent.Task;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.stage.Window;

import org.reactfx.util.AccumulatorSize;
import org.reactfx.util.Either;
import org.reactfx.util.Experimental;
import org.reactfx.util.FxTimer;
import org.reactfx.util.NotificationAccumulator;
import org.reactfx.util.Timer;
import org.reactfx.util.Tuple2;
import org.reactfx.value.Val;

/**
 * Stream of values (events).
 *
 * @param  type of values emitted by this stream.
 */
public interface EventStream extends Observable> {

    /**
     * Get notified every time this event stream emits a value.
     * @param subscriber handles emitted events.
     * @return subscription that can be used to stop observing this event
     * stream.
     */
    default Subscription subscribe(Consumer subscriber) {
        return observe(subscriber);
    }

    /**
     * Subscribes to this event stream for at most {@code n} events.
     * The subscriber is automatically removed after handling {@code n} events.
     * @param n limit on how many events may be handled by {@code subscriber}.
     * Must be positive.
     * @param subscriber handles emitted events.
     * @return {@linkplain Subscription} that may be used to unsubscribe before
     * reaching {@code n} events handled by {@code subscriber}.
     */
    default Subscription subscribeFor(int n, Consumer subscriber) {
        return new LimitedInvocationSubscriber<>(n, subscriber).subscribeTo(this);
    }

    /**
     * Shorthand for {@code subscribeFor(1, subscriber)}.
     */
    default Subscription subscribeForOne(Consumer subscriber) {
        return subscribeFor(1, subscriber);
    }

    /**
     * Starts pushing all events emitted by this stream to the given event sink.
     * 

{@code stream.feedTo(sink)} is equivalent to * {@code sink.feedFrom(stream)} * @param sink event sink to which this event stream's events will be pushed * @return subscription that can be used to stop delivering this stream's * events to {@code sink}. * @see EventSink#feedFrom(EventStream) */ default Subscription feedTo(EventSink sink) { return subscribe(sink::push); } /** * Starts setting all events emitted by this stream as the value of the * given writable value. This is a shortcut for * {@code subscribe(dest::setValue)}. */ default Subscription feedTo(WritableValue dest) { return subscribe(dest::setValue); } /** * If this stream is a compound stream lazily subscribed to its inputs, * that is, subscribed to inputs only when it itself has some subscribers, * {@code pin}ning this stream causes it to stay subscribed until the * pinning is revoked by calling {@code unsubscribe()} on the returned * subscription. * *

Equivalent to {@code subscribe(x -> {})}. * @return subscription used to cancel the pinning */ default Subscription pin() { return subscribe(x -> {}); } /** * Returns an event stream that immediately emits its event when something * subscribes to it. If the stream has no event to emit, it defaults to * emitting the default event. Once this stream emits an event, the returned * stream will emit this stream's most recent event. Useful when one doesn't * know whether an EventStream will emit its event immediately but needs it * to emit an event immediately. Such a case can arise as shown in the * following example: *

     * {@code
     * EventStream controlPresses = EventStreams
     *     .eventsOf(scene, KeyEvent.KEY_PRESSED)
     *     .filter(key -> key.getCode().is(KeyCode.CONTROL))
     *     .map(key -> key.isControlDown());
     *
     * EventSource other;
     * EventStream> combo = EventStreams.combine(controlPresses, other);
     *
     * // This will not run until user presses the control key at least once.
     * combo.subscribe(tuple2 -> System.out.println("Combo emitted an event."));
     *
     * EventStream controlDown = controlPresses.withDefaultEvent(false);
     * EventStream> betterCombo = EventStreams.combine(controlDown, other);
     * betterCombo.subscribe(tuple2 -> System.out.println("Better Combo emitted an event immediately upon program start."));
     * }
     * 
* * @param defaultEvent the event this event stream will emit if something subscribes to this stream and this stream does not have an event. */ default EventStream withDefaultEvent(T defaultEvent) { return new DefaultEventStream<>(this, defaultEvent); } /** * Returns an event stream that emits the same(*) events as this * stream, but before emitting each event performs the given side * effect. This is useful for debugging. The side effect is not allowed to * cause recursive event emission from this stream: if it does, * {@linkplain IllegalStateException} will be thrown. * *

(*) The returned stream is lazily bound, so it only emits events and * performs side effects when it has at least one subscriber. */ default EventStream hook(Consumer sideEffect) { return new HookStream<>(this, sideEffect); } /** * Returns a new event stream that emits events emitted from this stream * that satisfy the given predicate. */ default EventStream filter(Predicate predicate) { return new FilterStream<>(this, predicate); } /** * Filters this event stream by the runtime type of the values. * {@code filter(SomeClass.class)} is equivalent to * {@code filter(x -> x instanceof SomeClass).map(x -> (SomeClass) x)}. */ default EventStream filter(Class subtype) { return filterMap(subtype::isInstance, subtype::cast); } /** * Returns a new event stream that emits repetitive events only once. For example, given *

     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.distinct();
     *     }
     * 
*

Returns B. When A emits an event, B only emits that event if it's different from * the previous event emitted by A.

*
     *        Time --->
     *        A :-3--3---3-4---4---4---5-4-5--5--5->
     *        B :-3--------4-----------5-4-5------->
     * 
*/ default EventStream distinct() { return new DistinctStream<>(this); } /** * Returns an event stream that emits the given constant value every time * this stream emits a value. For example, given *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.supply(5);
     *     }
     * 
*

Returns B. When A emits an event, B emits the supplied value.

*
     *        Time --->
     *        A :-3--0--6--4-1--1---5-4-5--8--2->
     *        B :-5--5--5--5-5--5---5-5-5--5--5->
     * 
*/ default EventStream supply(U value) { return map(x -> value); } /** * Returns an event stream that emits a value obtained from the given * supplier every time this event stream emits a value. *
     *     {@code
     *     EventStream A = ...;
     *     SimpleIntegerProperty intProp = ...;
     *     EventStream B = A.supply(intProp::get);
     *     }
     * 
*

Returns B. When A emits an event, B emits the supplier's value.

*
     *        Time --->
     *        A :----a----b------c----d----e---->
     *  intProp :-3--------6---------9---------->
     *        B :----3----3------6----9----9---->
     * 
*/ default EventStream supply(Supplier f) { return map(x -> f.get()); } /** * Similar to {@link #supply(Supplier)}, but the returned stream is a * {@link CompletionStageStream}, which can be used to await the results * of asynchronous computation. */ default CompletionStageStream supplyCompletionStage(Supplier> f) { return mapToCompletionStage(x -> f.get()); } /** * Similar to {@link #supply(Supplier)}, but the returned stream is a * {@link CompletionStageStream}, which can be used to await the results * of asynchronous computation. */ default TaskStream supplyTask(Supplier> f) { return mapToTask(x -> f.get()); } /** * Returns a new event stream that applies the given function to every * value emitted from this stream and emits the result. For example, given *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.map(intValue -> intValue * 2);
     *     }
     * 
*

Returns B. When A emits an event, the event is mapped by the function (in this case, it multiples * A's emitted value by two) and B emits this mapped event.

*
     *        Time --->
     *        A :-3---1--4--5--2--0---3--7--->
     *        B :-6---2--8--10-4--0---6--14-->
     * 
*/ default EventStream map(Function f) { return new MappedStream<>(this, f); } /** * Returns a new event stream that emits events emitted by this stream * cast to the given type. * {@code cast(SomeClass.class)} is equivalent to * {@code map(x -> (SomeClass) x)}. */ default EventStream cast(Class subtype) { return map(subtype::cast); } /** * Returns a new event stream that, for event {@code e} emitted from this * stream, emits {@code left(e)} if {@code e} passes the given test, and * emits {@code right(e)} if {@code e} does not pass the test. */ default EventStream> splitBy(Predicate test) { return map(t -> test.test(t) ? Either.left(t) : Either.right(t)); } /** * Returns two event streams, the first one emitting events of this stream * that satisfy the given {@code test} and the second one emitting events * of this stream that do not satisfy the test. */ default Tuple2, EventStream> fork(Predicate test) { return t(filter(test), filter(test.negate())); } /** * Similar to {@link #map(Function)}, but the returned stream is a * {@link CompletionStageStream}, which can be used to await the results * of asynchronous computation. */ default CompletionStageStream mapToCompletionStage(Function> f) { return new MappedToCompletionStageStream<>(this, f); } /** * Similar to {@link #map(Function)}, but the returned stream is a * {@link TaskStream}, which can be used to await the results of * asynchronous computation. */ default TaskStream mapToTask(Function> f) { return new MappedToTaskStream<>(this, f); } /** * A more efficient equivalent to * {@code filter(predicate).map(f)}. */ default EventStream filterMap( Predicate predicate, Function f) { return new FilterMapStream<>(this, predicate, f); } /** * Equivalent to *
     * {@code
     * map(f)
     *     .filter(Optional::isPresent)
     *     .map(Optional::get)
     * }
     * 
* with more efficient implementation. */ default EventStream filterMap(Function> f) { return new FlatMapOptStream(this, f); } /** * Returns a new event stream that, for each event x emitted from * this stream, obtains the event stream f(x) and keeps emitting its * events until the next event is emitted from this stream. * For example, given *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = ...;
     *     EventStream C = ...;
     *     EventStream D = A.flatMap(intValue -> {
     *         intValue < 4
     *             ? B
     *             : C
     *     })
     *     }
     * 
*

Returns D. When A emits an event that is less than 4, D will emit B's events. * Otherwise, D will emit C's events. When A emits a new event, the stream whose events * D will emit is re-determined. *

     *        Time --->
     *        A :-3---1--4--5--2--0---3--5--------->
     *        B :--4-7---8--7----4-----34---5--56-->
     *        C :----6---6----5---8----9---2---5--->
     *   Stream :-BBBBBBBCCCCCCBBBBBBBBBBCCCCCCCCC->
     *        D :--4-7---6----5--4-----34--2---5--->
     * 
*/ default EventStream flatMap(Function> f) { return new FlatMapStream<>(this, f); } /** * Returns a new {@linkplain EventStream} that only observes this * {@linkplain EventStream} when {@code condition} is {@code true}. * More precisely, the returned {@linkplain EventStream} observes * {@code condition} whenever it itself has at least one subscriber and * observes {@code this} {@linkplain EventStream} whenever it itself has * at least one subscriber and the value of {@code condition} is * {@code true}. When {@code condition} is {@code true}, the returned * {@linkplain EventStream} emits the same events as this * {@linkplain EventStream}. When {@code condition} is {@code false}, the * returned {@linkplain EventStream} emits no events. */ default EventStream conditionOn(ObservableValue condition) { return valuesOf(condition).flatMap(c -> c ? this : never()); } /** * Equivalent to {@link #conditionOn(ObservableValue)} where the condition * is that {@code node} is showing: it is part of a scene graph * ({@link Node#sceneProperty()} is not {@code null}), its scene is part of * a window ({@link Scene#windowProperty()} is not {@code null}) and the * window is showing ({@link Window#showingProperty()} is {@code true}). */ default EventStream conditionOnShowing(Node node) { return conditionOn(Val.showingProperty(node)); } /** * Returns an event stream that emits all the events emitted from either * this stream or the {@code right} stream. An event t emitted from * this stream is emitted as {@code Either.left(t)}. An event u * emitted from the {@code right} stream is emitted as * {@code Either.right(u)}. * * @see EventStreams#merge(EventStream...) */ default EventStream> or(EventStream right) { EventStream left = this; return new EventStreamBase>() { @Override protected Subscription observeInputs() { return Subscription.multi( left.subscribe(l -> emit(Either.left(l))), right.subscribe(r -> emit(Either.right(r)))); } }; } /** * Returns an event stream that emits lists of {@code n} latest events * emitted from this stream. * For example, given *
     * {@code
     * EventStream stream = ...;
     * EventStream> latest3 = stream.latestN(3);
     * }
     *
     *     Time --->
     *     stream  :--1--2-----3--4--5-----6--->
     *     latest3 :--a--b-----c--d--e-----f--->
     * 
* then lastest3's values are *
    *
  • a = [1]
  • *
  • b = [1,2]
  • *
  • c = [1,2,3]
  • *
  • d = [2,3,4]
  • *
  • e = [3,4,5]
  • *
  • f = [4,5,6]
  • *
*/ default EventStream> latestN(int n) { return new LatestNStream<>(this, n); } /** * Returns a new event stream that, when an event arrives from the * {@code impulse} stream, emits the most recent event emitted by this * stream. Each event is emitted at most once. * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = ...;
     *     EventStream C = A.emitOn(B);}
     * 
*

Returns C. When B emits an event, C emits A's most recent event. * No, does not emit the most recent event multiple times. *

     *     Time --->
     *     A :-a-------b-----c----------d------->
     *     B :----i------------i--i--i-----i---->
     *     C :----a------------c-----------d---->
     * 
* *

Relationship to other EventStreams:

*
    *
  • * This stream does NOT emit A's most recent event multiple * times whereas {@link #emitOnEach(EventStream)} does. *
  • *
  • * This stream ONLY emits A's events whereas {@link #emitBothOnEach(EventStream)} * emits both A and B's events as an event (a {@link Tuple2}) *
  • *
  • * This stream does NOT emit A's event when A emits an event * whereas {@link #repeatOn(EventStream)} does. *
  • *
*/ default EventStream emitOn(EventStream impulse) { return new EmitOnStream<>(this, impulse); } /** * Returns a new event stream that, when an event arrives from the * {@code impulse} stream, emits the most recent event emitted by this * stream. The same event may be emitted more than once. * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = ...;
     *     EventStream C = A.emitOnEach(B);}
     * 
*

Returns C. When B emits an event, C emits A's most recent event. * Yes, does emit the most recent event multiple times. *

     *     Time --->
     *     A :-a-------b-----c----------d------->
     *     B :----i------------i--i--i-----i---->
     *     C :----a------------c--c--c-----d---->
     * 
* *

Relationship to other EventStreams:

*
    *
  • * This stream DOES emit A's most recent event multiple * times whereas {@link #emitOn(EventStream)} does not. *
  • *
  • * This stream ONLY emits A's events whereas {@link #emitBothOnEach(EventStream)} * emits both A and B's events as an event. *
  • *
  • * This stream does not emit A's events when A emits an event * whereas {@link #repeatOn(EventStream)} does. *
  • *
*/ default EventStream emitOnEach(EventStream impulse) { return new EmitOnEachStream<>(this, impulse); } /** * Similar to {@link #emitOnEach(EventStream)}, but also includes the * impulse in the emitted value. * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = ...;
     *     EventStream C = A.emitBothOnEach(B);}
     * 
*

Returns C. When B emits an event, C emits A and B's most recent events.. * Only emits an event when both A and B have emitted at least one new event. *

     *     Time --->
     *     A :-a-------b---c------------------d------->
     *     B :----1-----------2-----3-----4----------->
     *     C :---[a,1]------[c,2]-----------[d,4]----->
     * 
* *

Relationship to other EventStreams:

*
    *
  • * This stream emits both A and B's events whereas {@link #emitOn(EventStream)}, * {@link #emitOnEach(EventStream)}, and {@link #repeatOn(EventStream)} * only emit A's event under specific circumstances. *
  • *
*/ default EventStream> emitBothOnEach(EventStream impulse) { return new EmitBothOnEachStream<>(this, impulse); } /** * Returns a new event stream that emits all the events emitted from this * stream and in addition to that re-emits the most recent event on every * event emitted from {@code impulse}. * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = ...;
     *     EventStream C = A.repeatOn(B);}
     * 
*

Returns C. When A emits an event, C also emits that event. When B * emits an event, C emits that most recent event that A emitted. *

     *     Time --->
     *     A :-a-------b---c------------------d------->
     *     B :----i-----------i-----i-----i----------->
     *     C :-a--a----b---c--c-----c-----c---d------->
     * 
* *

Relationship to other EventStreams:

*
    *
  • * This stream emits A's events when A emits an event and * it emits A's most recent event multiple times whereas * {@link #emitOn(EventStream)} doesn't. *
  • *
  • * This stream also emits A's most recent event whereas * {@link #emitOnEach(EventStream)} doesn't. *
  • *
  • * This stream only emits A's events whereas {@link #emitBothOnEach(EventStream)} * emits both A and B's events as an event. *
  • *
*/ default EventStream repeatOn(EventStream impulse) { return new RepeatOnStream<>(this, impulse); } /** * Returns a suspendable event stream that, when suspended, suppresses * any events emitted by this event stream. */ default SuspendableEventStream suppressible() { return new SuppressibleEventStream<>(this); } /** * Shortcut for {@code suppressible().suspendedWhen(condition)}. */ default EventStream suppressWhen(ObservableValue condition) { return suppressible().suspendedWhen(condition); } /** * Returns a suspendable event stream that, when suspended, stores the * events emitted by this event stream and emits them when the returned * stream's emission is resumed. * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.pausable();
     *     }
     * 
*

Returns B. When A emits an event and B is not suspended, B also emits that event. * When B is suspended and A emits events, those events are stored in B. Once * B is unsuspended, B emits those events. *

     *     Time --->
     *     A :-a--b----c---d-----e------------f------->
     *     B :-a--b--|---Suspended----|cde----f------->
     * 
*/ default SuspendableEventStream pausable() { return new PausableEventStream<>(this); } /** * Shortcut for {@code pausable().suspendedWhen(condition)}. */ default EventStream pauseWhen(ObservableValue condition) { return pausable().suspendedWhen(condition); } /** * Returns a suspendable event stream that, when suspended, forgets all but * the latest event emitted by this event stream. The remembered event, if * any, is emitted from the returned stream upon resume. * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.forgetful();
     *     }
     * 
*

Returns B. When B is not suspended and A emits an event, B emits that event. * When B is suspended and A emits an event, B does not emit that event, nor does * it store that event for later emission. Those events are "forgotten." *

     *     Time --->
     *     A :-a--b----c---d-----e------------f------->
     *     B :-a--b--|---Suspended----|-------f------->
     * 
*/ default SuspendableEventStream forgetful() { return new ForgetfulEventStream<>(this); } /** * Shortcut for {@code forgetful().suspendedWhen(condition)}. */ default EventStream retainLatestWhen(ObservableValue condition) { return forgetful().suspendedWhen(condition); } /** * Returns a suspendable event stream that, when suspended, reduces incoming * events by the given {@code reduction} function into one. The reduced * event is emitted from the returned stream upon resume. * * For example, *
     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.reducible(lastStored_A_Event, mostRecent_A_EventEmitted -> {
     *         lastStored_A_Event <= 4
     *             ? mostRecent_A_EventEmitted
     *             : lastStored_A_Event;
     *     });
     *     }
     * 
*

Returns B. When B is not suspended and A emits an event, B emits that event. * When B is suspended and A emits events (En) where {@code n} is the number of the event, * B applies reduction(En-1, En). When B is no longer suspended, it emits {@code result} *

*
     *     Time --->
     *     A      :-1--2----4--1--5-----7------------6------->
     *     B      :-1--2--|---Suspended---|5---------6------->
     *     result :-------|-a--b--c-----d-|------------------>
     * 
* then result's values are: *
    *
  • a = 4 [reduction(2, 4) == 4]
  • *
  • b = 5 [reduction(4, 1) == 1]
  • *
  • c = 5 [reduction(1, 5) == 5]
  • *
  • d = 5 [reduction(5, 7) == 5]
  • *
* *

Note that {@link #forgetful()} is equivalent to * {@code reducible((a, b) -> b)}. */ default SuspendableEventStream reducible(BinaryOperator reduction) { return new ReducibleEventStream<>(this, reduction); } /** * Shortcut for {@code reducible(reduction).suspendedWhen(condition)}. */ default EventStream reduceWhen( ObservableValue condition, BinaryOperator reduction) { return reducible(reduction).suspendedWhen(condition); } /** * Returns a suspendable event stream that, when suspended, accumulates * incoming events to a cumulative value of type {@code A}. When the * returned stream is resumed, the accumulated value is deconstructed into * a sequence of events that are emitted from the returned stream. * *

Note that {@link #suppressible()} is equivalent to *

     * {@code
     * accumulative(
     *     t -> (Void) null,                        // use null as accumulator
     *     (a, t) -> a,                             // keep null as accumulator
     *     a -> AccumulatorSize.ZERO,               // no events to be emitted from accumulator
     *     a -> throw new NoSuchElementException(), // head is never called on empty accumulator
     *     a -> throw new NoSuchElementException()) // tail is never called on empty accumulator
     * }
     * 
* *

Note that {@code reducible(reduction)} is equivalent to *

     * {@code
     * accumulative(
     *     t -> t,                                // the event itself is the accumulator
     *     reduction,
     *     t -> AccumulatorSize.ONE,              // one event to be emitted
     *     t -> t,                                // head of a single value is the value itself
     *     t -> throw new NoSuchElementException) // tail is never called on accumulator of size one
     * }
     * 
* * @param initialTransformation Used to convert the first event after * suspension to the cumulative value. * @param accumulation Used to accumulate further incoming events to the * cumulative value. * @param size determines how many events can be emitted from the current * cumulative value. * @param head produces the first event off the cumulative value. * @param tail returns a cumulative value that produces the same events * as the given cumulative value, except the event returned by {@code head}. * May be destructive for the given cumulative value. * @param type of the cumulative value */ default SuspendableEventStream accumulative( Function initialTransformation, BiFunction accumulation, Function size, Function head, Function tail) { return new AccumulativeEventStream<>( this, initialTransformation, accumulation, size, head, tail); } /** * Shortcut for *
     * {@code
     * accumulative(initialTransformation, accumulation, size, head, tail)
     *     .suspendedWhen(condition)}
     * 
*/ default
EventStream accumulateWhen( ObservableValue condition, Function initialTransformation, BiFunction accumulation, Function size, Function head, Function tail) { return accumulative(initialTransformation, accumulation, size, head, tail) .suspendedWhen(condition); } /** * A variation on * {@link #accumulative(Function, BiFunction, Function, Function, Function)} * to use when it is more convenient to provide a unit element of the * accumulation than to transform the initial event to a cumulative * value. It is equivalent to * {@code accumulative(t -> accumulation.apply(unit.get(), t), accumulation, size, head, tail)}, * i.e. the initial transformation is achieved by accumulating the initial * event to the unit element. * *

Note that {@link #pausable()} is equivalent to *

     * {@code
     * accumulative(
     *     LinkedList::new,                     // the unit element is an empty queue
     *     (q, t) -> { q.addLast(t); return q; },  // accumulation is addition to the queue
     *     q -> AccumulatorSize.fromInt(q.size()), // size is the size of the queue
     *     Deque::getFirst,                        // head is the first element of the queue
     *     q -> { q.removeFirst(); return q; })    // tail removes the first element from the queue
     * }
     * 
* * @param unit Function that supplies unit element of the accumulation. * @param accumulation Used to accumulate further incoming events to the * cumulative value. * @param size determines how many events can be emitted from the current * cumulative value. * @param head produces the first event off the cumulative value. * @param tail returns a cumulative value that produces the same events * as the given cumulative value, except the event returned by {@code head}. * May be destructive for the given cumulative value. * @param
type of the cumulative value */ default SuspendableEventStream accumulative( Supplier unit, BiFunction accumulation, Function size, Function head, Function tail) { Function initialTransformation = t -> accumulation.apply(unit.get(), t); return accumulative( initialTransformation, accumulation, size, head, tail); } /** * Shortcut for *
     * {@code
     * accumulative(unit, accumulation, size, head, tail)
     *     .suspendedWhen(condition)}
     * 
*/ default
EventStream accumulateWhen( ObservableValue condition, Supplier unit, BiFunction accumulation, Function size, Function head, Function tail) { return accumulative(unit, accumulation, size, head, tail) .suspendedWhen(condition); } /** * Returns an event stream that, when an event arrives from this stream, * transforms it into a cumulative value using the * {@code initialTransformation} function. Any further events that arrive * from this stream are accumulated to the cumulative value using the * {@code accumulation} function. When an event arrives from the * {@code ticks} stream, the accumulated value is deconstructed into a * sequence of events using the {@code deconstruction} function and the * events are emitted from the returned stream. * *

Note that {@code reduceBetween(ticks, reduction)} is equivalent to * {@code accumulateBetween(ticks, t -> t, reduction, Collections::singletonList)}. */ default EventStream accumulateBetween( EventStream ticks, Function initialTransformation, BiFunction accumulation, Function> deconstruction) { return new AccumulateBetweenStream<>( this, ticks, initialTransformation, accumulation, deconstruction); } /** * A variation on * {@link #accumulateBetween(EventStream, Function, BiFunction, Function)} * to use when it is more convenient to provide a unit element of the * accumulation than to transform the initial event to a cumulative * value. It is equivalent to * {@code accumulateBetween(ticks, t -> accumulation.apply(unit.get(), t), accumulation, deconstruction)}, * i.e. the initial transformation is achieved by accumulating the initial * event to the unit element. * *

Note that {@code queueBetween(ticks)} is equivalent to * {@code accumulateBetween(ticks, ArrayList::new, (l, t) -> { l.add(t); return l; }, l -> l)}, * i.e. the unit element is an empty list, accumulation is addition to the * list and deconstruction of the accumulated value is a no-op, since the * accumulated value is already a list of events. */ default EventStream accumulateBetween( EventStream ticks, Supplier unit, BiFunction accumulation, Function> deconstruction) { Function initialTransformation = t -> accumulation.apply(unit.get(), t); return accumulateBetween( ticks, initialTransformation, accumulation, deconstruction); } /** * Returns an event stream that, when an event arrives from this stream, * stores it for emission. Any further events that arrive from this stream * are reduced into the stored event using the {@code reduction} function. * The stored event is emitted from the returned stream when a tick * arrives from the {@code ticks} stream. * *

Note that {@code retainLatestBetween(ticks)} is equivalent to * {@code reduceBetween(ticks, (a, b) -> b)}. */ default EventStream reduceBetween( EventStream ticks, BinaryOperator reduction) { return accumulateBetween( ticks, Function.identity(), reduction, Collections::singletonList); } /** * Returns an event stream that, when an event arrives from this stream, * enqueues it for emission. Queued events are emitted from the returned * stream when a tick arrives from the {@code ticks} stream. */ default EventStream queueBetween(EventStream ticks) { return accumulateBetween( ticks, (Supplier>) ArrayList::new, (l, t) -> { l.add(t); return l; }, Function.identity()); } /** * Equivalent to {@link #emitOn(EventStream)}. */ default EventStream retainLatestBetween(EventStream ticks) { return emitOn(ticks); } /** * Version of {@link #accumulateUntilLater(Function, BiFunction, Function)} * for event streams that don't live on the JavaFX application thread. * @param eventThreadExecutor executor that executes actions on the thread * from which this event stream is accessed. */ default EventStream accumulateUntilLater( Function initialTransformation, BiFunction accumulation, Function> deconstruction, Executor eventThreadExecutor) { return new AccumulateUntilLaterStream<>( this, initialTransformation, accumulation, deconstruction, eventThreadExecutor); } /** * Returns an event stream that, when an event is emitted from this stream, * transforms the event to a cumulative value using the * {@code initialTransformation} function and schedules emission using * {@link Platform#runLater(Runnable)}, if not already scheduled. Any new * event that arrives from this stream before the scheduled emission is * executed is accumulated to the stored cumulative value using the given * {@code accumulation} function. When the scheduled emission is finally * executed, the accumulated value is deconstructed into a sequence of * events using the {@code deconstruction} function and the events are * emitted from the returned stream. * *

Note that {@code reduceUntilLater(reduction)} is equivalent to * {@code accumulateUntilLater(t -> t, reduction, t -> Collections::singletonList)}. * * @param type of the cumulative value (accumulator) */ default EventStream accumulateUntilLater( Function initialTransformation, BiFunction accumulation, Function> deconstruction) { return accumulateUntilLater( initialTransformation, accumulation, deconstruction, Platform::runLater); } /** * Version of {@link #accumulateUntilLater(Supplier, BiFunction, Function)} * for event streams that don't live on the JavaFX application thread. * @param eventThreadExecutor executor that executes actions on the thread * from which this event stream is accessed. */ default EventStream accumulateUntilLater( Supplier unit, BiFunction accumulation, Function> deconstruction, Executor eventThreadExecutor) { return accumulateUntilLater( t -> accumulation.apply(unit.get(), t), accumulation, deconstruction, eventThreadExecutor); } /** * A variation on * {@link #accumulateUntilLater(Function, BiFunction, Function)} * to use when it is more convenient to provide a unit element of the * accumulation than to transform the initial event to a cumulative * value. It is equivalent to * {@code accumulateUntilLater(t -> accumulation.apply(unit.get(), t), accumulation, deconstruction)}, * i.e. the initial transformation is achieved by accumulating the initial * event to the unit element. * *

Note that {@link #queueUntilLater()} is equivalent to * {@code accumulateUntilLater(ArrayList::new, (l, t) -> { l.add(t); return l; }, l -> l)}, * i.e. the unit element is an empty list, accumulation is addition to the * list and deconstruction of the accumulated value is a no-op, since the * accumulated value is already a list of events. * * @param type of the cumulative value (accumulator) */ default EventStream accumulateUntilLater( Supplier unit, BiFunction accumulation, Function> deconstruction) { return accumulateUntilLater( unit, accumulation, deconstruction, Platform::runLater); } /** * Version of {@link #reduceUntilLater(BinaryOperator)} for event streams * that don't live on the JavaFX application thread. * @param eventThreadExecutor executor that executes actions on the thread * from which this event stream is accessed. */ default EventStream reduceUntilLater( BinaryOperator reduction, Executor eventThreadExecutor) { return accumulateUntilLater( Function.identity(), reduction, Collections::singletonList, eventThreadExecutor); } /** * Returns an event stream that, when an event is emitted from this stream, * stores the event for emission and schedules emission using * {@link Platform#runLater(Runnable)}, if not already scheduled. Any new * event that arrives from this stream before the scheduled emission is * executed is accumulated into the stored event using the given * {@code reduction} function. When the scheduled emission is finally * executed, the stored event is emitted from the returned stream. * *

Note that {@link #retainLatestUntilLater()} is equivalent to * {@code reduceUntilLater((a, b) -> b)}. */ default EventStream reduceUntilLater(BinaryOperator reduction) { return reduceUntilLater(reduction, Platform::runLater); } /** * Version of {@link #retainLatestUntilLater()} for event streams that * don't live on the JavaFX application thread. * @param eventThreadExecutor executor that executes actions on the thread * from which this event stream is accessed. */ default EventStream retainLatestUntilLater(Executor eventThreadExecutor) { return reduceUntilLater((a, b) -> b, eventThreadExecutor); } /** * Returns an event stream that, when an event is emitted from this stream, * stores the event for emission and schedules emission using * {@link Platform#runLater(Runnable)}, if not already scheduled. If a new * event arrives from this stream before the scheduled emission is executed, * the stored event is overwritten by the new event and only the new event is * emitted when the scheduled emission is finally executed. */ default EventStream retainLatestUntilLater() { return retainLatestUntilLater(Platform::runLater); } /** * Version of {@link #queueUntilLater()} for event streams that don't live * on the JavaFX application thread. * @param eventThreadExecutor executor that executes actions on the thread * from which this event stream is accessed. */ default EventStream queueUntilLater(Executor eventThreadExecutor) { return accumulateUntilLater( (Supplier>) ArrayList::new, (l, t) -> { l.add(t); return l; }, l -> l, eventThreadExecutor); } /** * Returns an event stream that, when an event is emitted from this stream, * enqueues the event for emission and schedules emission using * {@link Platform#runLater(Runnable)}, if not already scheduled. Any events * that arrive from this stream before a scheduled emission is executed are * enqueued as well and emitted (in order) when the scheduled emission is * finally executed. */ default EventStream queueUntilLater() { return queueUntilLater(Platform::runLater); } /** * Returns a binding that holds the most recent event emitted from this * stream. The returned binding stays subscribed to this stream until its * {@code dispose()} method is called. * @param initialValue used as the returned binding's value until this * stream emits the first value. * @return binding reflecting the most recently emitted value. */ default Binding toBinding(T initialValue) { return new StreamBinding<>(this, initialValue); } /** * Returns an event stream that accumulates events emitted from this event * stream and emits the accumulated value every time this stream emits a * value. * @param reduction function to reduce two events into one. */ default EventStream accumulate(BinaryOperator reduction) { return accumulate(reduction, Function.identity()); } /** * Returns an event stream that accumulates events emitted from this event * stream and emits the accumulated value every time this stream emits a * value. For example, given *

     *     {@code
     *     EventStream A = ...;
     *     EventStream B = A.accumulate(
     *          // Unit
     *          "Cheese",
     *          // reduction
     *          (lastStored_A_Event, mostRecent_A_EventEmitted) -> {
     *             lastStored_A_Event.length() > mostRecent_A_EventEmitted
     *                ? lastStored_A_Event.subString(0, mostRecent_A_EventEmitted.length())
     *                : mostRecent_A_EventEmitted
     *          }
     *     );
     *     }
     * 
* Returns B. When A emits an event, B emits the result of * applying the reduction function on those events. When A emits its first * event, B supplies Unit as the 'lastStored_A_Event'. *
     *     Time --->
     *     A :-"Cake"--"Sugar"--"Oil"--"French Toast"---"Cookie"----->
     *     B :--1---------2--------3------4--------------5------------>
     * 
* where "#" is: *
    *
  • 1 = "Chee" ("Cheese" (6) > "Cake" (4) == true; "Cheese".subString(0, 4) == "Chee")
  • *
  • 2 = "Sugar" ("Chee" (4) > "Sugar" (5) == false; "Sugar")
  • *
  • 3 = "Sug" ("Sugar" (5) > "Oil" (3) == true); "Sugar".subString(0, 3) == "Sug")
  • *
  • 4 = "French Toast" ("Sug" (3) > "French Toast" (12) == false; "French Toast")
  • *
  • 5 = "French" ("French Toast" (12) > "Cookies" (6) == true; "French Toast".subString(0, 6) == "French")
  • *
* @param unit initial value of the accumulated value. * @param reduction function to add an event to the accumulated value. */ default EventStream accumulate( U unit, BiFunction reduction) { return accumulate(reduction, t -> reduction.apply(unit, t)); } /** * Returns an event stream that accumulates events emitted from this event * stream and emits the accumulated value every time this stream emits a * value. For example, given *
     *     {@code
     *     // assumes that A only emits String events that are 1 char long.
     *     EventStream A = ...;
     *     EventStream B = A.accumulate(
     *          // reduction
     *          (lastStored_A_Event, mostRecent_A_EventEmitted) -> {
     *             mostRecent_A_EventEmitted.isVowel()
     *                ? lastStored_A_Event + mostRecent_A_EventEmitted
     *                : mostRecent_A_EventEmitted
     *          },
     *          // initial transformation
     *          first_A_EvenEmitted ->
     *             first_A_EventEmitted.isConsonant()
     *                ? first_A_EventEmitted
     *                : "M"
     *     );
     *     }
     * 
* Returns B. The first time A emits an event, B emits the result of * applying the initial transformation function to that event. For every * event emitted after that, B emits the result of applying the reduction * function on those events. *
     *     Time --->
     *     A :-D--O---E---L---K---I--U---T----->
     *     B :-1--2---3---4---5---6--7---8----->
     * 
* where "#" is: *
    *
  • 1 = "D" ("D" is a consonant)
  • *
  • 2 = "DO" ("O" is a vowel)
  • *
  • 3 = "DOE" ("E" is a vowel)
  • *
  • 4 = "DOE" ("L" is a consonant)
  • *
  • 5 = "DOE" ("K" is a consonant)
  • *
  • 6 = "DOEI" ("I" is a vowel)
  • *
  • 7 = "DOEIU" ("U" is a vowle)
  • *
  • 8 = "DOEIU" ("T" is a consonant)
  • *
* * @param reduction function to add an event to the accumulated value. * @param initialTransformation function to transform the first event from * this stream to an event that can be emitted from the returned stream. * Subsequent events emitted from this stream are accumulated to the value * returned from this function. */ default EventStream accumulate( BiFunction reduction, Function initialTransformation) { return new AccumulatingStream<>(this, initialTransformation, reduction); } /** * Returns an event stream that accumulates events emitted from this event * stream in close temporal succession. After an event is emitted from this * stream, the returned stream waits for up to {@code timeout} for the next * event from this stream. If the next event arrives within timeout, it is * accumulated to the current event by the {@code reduction} function and * the timeout is reset. When the timeout expires, the accumulated event is * emitted from the returned stream. * *

Note: This function can be used only when this stream and * the returned stream are used from the JavaFX application thread. If * you are using the event streams on a different thread, use * {@link #reduceSuccessions(BinaryOperator, Duration, ScheduledExecutorService, Executor)} * instead.

* * @param reduction function to reduce two events into one. * @param timeout the maximum time difference between two subsequent * events that can still be accumulated. */ default AwaitingEventStream reduceSuccessions( BinaryOperator reduction, Duration timeout) { return reduceSuccessions(Function.identity(), reduction, timeout); } /** * A more general version of * {@link #reduceSuccessions(BinaryOperator, Duration)} * that allows the accumulated event to be of different type. * *

Note: This function can be used only when this stream and * the returned stream are used from the JavaFX application thread. If * you are using the event streams on a different thread, use * {@link #reduceSuccessions(Function, BiFunction, Duration, ScheduledExecutorService, Executor)} * instead.

* * @param initialTransformation function to transform a single event * from this stream to an event that can be emitted from the returned * stream. * @param reduction function to add an event to the accumulated value. * @param timeout the maximum time difference between two subsequent * events that can still be accumulated. * @param type of events emitted from the returned stream. */ default AwaitingEventStream reduceSuccessions( Function initialTransformation, BiFunction reduction, Duration timeout) { Function timerFactory = action -> FxTimer.create(timeout, action); return new SuccessionReducingStream( this, initialTransformation, reduction, timerFactory); } /** * A convenient method that can be used when it is more convenient to * supply an identity of the type {@code U} than to transform an event * of type {@code T} to an event of type {@code U}. * This method is equivalent to * {@code reduceSuccessions(t -> reduction.apply(identitySupplier.get(), t), reduction, timeout)}. * *

Note: This function can be used only when this stream and * the returned stream are used from the JavaFX application thread. If * you are using the event streams on a different thread, use * {@link #reduceSuccessions(Supplier, BiFunction, Duration, ScheduledExecutorService, Executor)} * instead.

* * @param unitSupplier function that provides the unit element * (i.e. initial value for accumulation) of type {@code U} * @param reduction function to add an event to the accumulated value. * @param timeout the maximum time difference between two subsequent * events that can still be accumulated. * * @see #reduceSuccessions(Function, BiFunction, Duration) */ default AwaitingEventStream reduceSuccessions( Supplier unitSupplier, BiFunction reduction, Duration timeout) { Function map = t -> reduction.apply(unitSupplier.get(), t); return reduceSuccessions(map, reduction, timeout); } /** * An analog to * {@link #reduceSuccessions(BinaryOperator, Duration)} * to use outside of JavaFX application thread. * * @param reduction function to reduce two events into one. * @param timeout the maximum time difference between two subsequent * events that can still be accumulated. * @param scheduler used to schedule timeout expiration * @param eventThreadExecutor executor that executes actions on the * thread on which this stream's events are emitted. The returned stream * will use this executor to emit events. */ default AwaitingEventStream reduceSuccessions( BinaryOperator reduction, Duration timeout, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { return reduceSuccessions( Function.identity(), reduction, timeout, scheduler, eventThreadExecutor); } /** * An analog to * {@link #reduceSuccessions(Function, BiFunction, Duration)} * to use outside of JavaFX application thread. * * @param initialTransformation function to transform a single event * from this stream to an event that can be emitted from the returned * stream. * @param reduction function to accumulate an event to the stored value * @param timeout the maximum time difference between two subsequent * events that can still be accumulated. * @param scheduler used to schedule timeout expiration * @param eventThreadExecutor executor that executes actions on the * thread on which this stream's events are emitted. The returned stream * will use this executor to emit events. */ default AwaitingEventStream reduceSuccessions( Function initialTransformation, BiFunction reduction, Duration timeout, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { Function timerFactory = action -> ScheduledExecutorServiceTimer.create( timeout, action, scheduler, eventThreadExecutor); return new SuccessionReducingStream( this, initialTransformation, reduction, timerFactory); } /** * An analog to * {@link #reduceSuccessions(Supplier, BiFunction, Duration)} * to use outside of JavaFX application thread. * * @param unitSupplier function that provides the unit element * @param reduction function to accumulate an event to the stored value * @param timeout the maximum time difference between two subsequent * events that can still be accumulated. * @param scheduler used to schedule timeout expiration * @param eventThreadExecutor executor that executes actions on the * thread on which this stream's events are emitted. The returned stream * will use this executor to emit events. */ default AwaitingEventStream reduceSuccessions( Supplier unitSupplier, BiFunction reduction, Duration timeout, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { Function map = t -> reduction.apply(unitSupplier.get(), t); return reduceSuccessions( map, reduction, timeout, scheduler, eventThreadExecutor); } /** * Returns an event stream that, when events are emitted from this stream * in close temporal succession, emits only the last event of the * succession. What is considered a close temporal succession is * defined by {@code timeout}: time gap between two successive events must * be at most {@code timeout}. * *

This method is a shortcut for * {@code reduceSuccessions((a, b) -> b, timeout)}.

* *

Note: This function can be used only when this stream and * the returned stream are used from the JavaFX application thread. If * you are using the event streams on a different thread, use * {@link #successionEnds(Duration, ScheduledExecutorService, Executor)} * instead.

* * @param timeout the maximum time difference between two subsequent events * in a close succession. */ default AwaitingEventStream successionEnds(Duration timeout) { return reduceSuccessions((a, b) -> b, timeout); } /** * An analog to {@link #successionEnds(Duration)} to use outside of JavaFX * application thread. * @param timeout the maximum time difference between two subsequent events * in a close succession. * @param scheduler used to schedule timeout expiration * @param eventThreadExecutor executor that executes actions on the * thread on which this stream's events are emitted. The returned stream * will use this executor to emit events. */ default AwaitingEventStream successionEnds( Duration timeout, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { return reduceSuccessions((a, b) -> b, timeout, scheduler, eventThreadExecutor); } /** * Returns an event stream that emits the first event emitted from this * stream and then, if the next event arrives within the given duration * since the last emitted event, it is converted to an accumulator value * using {@code initialTransformation}. Any further events that still * arrive within {@code duration} are accumulated to the accumulator value * using the given reduction function. After {@code duration} has passed * since the last emitted event, the accumulator value is deconstructed * into a series of events using the given {@code deconstruction} function * and these events are emitted, the accumulator value is cleared and any * events that arrive within {@code duration} are accumulated, and so on. */ default
AwaitingEventStream thenAccumulateFor( Duration duration, Function initialTransformation, BiFunction reduction, Function> deconstruction) { return new ThenAccumulateForStream<>( this, initialTransformation, reduction, deconstruction, action -> FxTimer.create(duration, action)); } default AwaitingEventStream thenAccumulateFor( Duration duration, Function initialTransformation, BiFunction reduction, Function> deconstruction, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { Function timerFactory = action -> ScheduledExecutorServiceTimer.create( duration, action, scheduler, eventThreadExecutor); return new ThenAccumulateForStream<>( this, initialTransformation, reduction, deconstruction, timerFactory); } /** * A variant of * {@link #thenAccumulateFor(Duration, Function, BiFunction, Function)} * for cases when it is more convenient to provide a unit element for * accumulation than the initial transformation. */ default AwaitingEventStream thenAccumulateFor( Duration duration, Supplier unit, BiFunction reduction, Function> deconstruction) { Function initialTransformation = t -> reduction.apply(unit.get(), t); return thenAccumulateFor( duration, initialTransformation, reduction, deconstruction); } default AwaitingEventStream thenAccumulateFor( Duration duration, Supplier unit, BiFunction reduction, Function> deconstruction, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { Function initialTransformation = t -> reduction.apply(unit.get(), t); return thenAccumulateFor( duration, initialTransformation, reduction, deconstruction, scheduler, eventThreadExecutor); } /** * Returns an event stream that emits the first event emitted from this * stream and then reduces all following events that arrive within the * given duration into a single event using the given reduction function. * The resulting event, if any, is emitted after {@code duration} has * passed. Then again, any events that arrive within {@code duration} are * reduced into a single event, that is emitted after {@code duration} has * passed, and so on. */ default AwaitingEventStream thenReduceFor( Duration duration, BinaryOperator reduction) { return thenAccumulateFor( duration, Function.identity(), reduction, Collections::singletonList); } default AwaitingEventStream thenReduceFor( Duration duration, BinaryOperator reduction, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { return thenAccumulateFor( duration, Function.identity(), reduction, Collections::singletonList, scheduler, eventThreadExecutor); } /** * Returns an event stream that emits the first event emitted from this * stream and then remembers, but does not emit, the latest event emitted * from this stream. The remembered event is emitted after the given * duration from the last emitted event. This repeats after each emitted * event. */ default AwaitingEventStream thenRetainLatestFor(Duration duration) { return thenReduceFor(duration, (a, b) -> b); } default AwaitingEventStream thenRetainLatestFor( Duration duration, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { return thenReduceFor( duration, (a, b) -> b, scheduler, eventThreadExecutor); } /** * Returns an event stream that emits the first event emitted from this * stream and then ignores the following events for the given duration. * The first event that arrives after the given duration is emitted and * following events are ignored for the given duration again, and so on. */ default AwaitingEventStream thenIgnoreFor(Duration duration) { return thenAccumulateFor( duration, t -> Collections.emptyList(), (l, t) -> l, Function.>identity()); } default AwaitingEventStream thenIgnoreFor( Duration duration, ScheduledExecutorService scheduler, Executor eventThreadExecutor) { return thenAccumulateFor( duration, t -> Collections.emptyList(), (l, t) -> l, Function.>identity(), scheduler, eventThreadExecutor); } default EventStream onRecurseAccumulate( Function initialTransformation, BiFunction reduction, Function size, Function head, Function tail) { return new RecursiveStream( this, NotificationAccumulator.accumulativeStreamNotifications( size, head, tail, initialTransformation, reduction)); } default EventStream onRecurseAccumulate( Supplier unit, BiFunction reduction, Function size, Function head, Function tail) { Function initialTransformation = t -> reduction.apply(unit.get(), t); return onRecurseAccumulate( initialTransformation, reduction, size, head, tail); } default EventStream onRecurseReduce(BinaryOperator reduction) { return new RecursiveStream( this, NotificationAccumulator.reducingStreamNotifications(reduction)); } default EventStream onRecurseQueue() { return new RecursiveStream( this, NotificationAccumulator.queuingStreamNotifications()); } default EventStream onRecurseRetainLatest() { return new RecursiveStream(this, NotificationAccumulator.retainLatestStreamNotifications()); } /** * Transfers events from one thread to another. * Any event stream can only be accessed from a single thread. * This method allows to transfer events from one thread to another. * Any event emitted by this EventStream will be emitted by the returned * stream on a different thread. * @param sourceThreadExecutor executor that executes tasks on the thread * from which this EventStream is accessed. * @param targetThreadExecutor executor that executes tasks on the thread * from which the returned EventStream will be accessed. * @return Event stream that emits the same events as this EventStream, * but uses {@code targetThreadExecutor} to emit the events. */ default EventStream threadBridge( Executor sourceThreadExecutor, Executor targetThreadExecutor) { return new ThreadBridge(this, sourceThreadExecutor, targetThreadExecutor); } /** * Transfers events from the JavaFX application thread to another thread. * Equivalent to * {@code threadBridge(Platform::runLater, targetThreadExecutor)}. * @param targetThreadExecutor executor that executes tasks on the thread * from which the returned EventStream will be accessed. * @return Event stream that emits the same events as this EventStream, * but uses {@code targetThreadExecutor} to emit the events. * @see #threadBridge(Executor, Executor) */ default EventStream threadBridgeFromFx(Executor targetThreadExecutor) { return threadBridge(Platform::runLater, targetThreadExecutor); } /** * Transfers events to the JavaFX application thread. * Equivalent to * {@code threadBridge(sourceThreadExecutor, Platform::runLater)}. * @param sourceThreadExecutor executor that executes tasks on the thread * from which this EventStream is accessed. * @return Event stream that emits the same events as this EventStream, * but emits them on the JavaFX application thread. * @see #threadBridge(Executor, Executor) */ default EventStream threadBridgeToFx(Executor sourceThreadExecutor) { return threadBridge(sourceThreadExecutor, Platform::runLater); } /** * Returns a clone of this event stream guarded by the given guardians. * The returned event stream emits the same events as this event stream. * In addition to that, the emission of each event is guarded by the given * guardians: before the emission, guards are acquired in the given order; * after the emission, previously acquired guards are released in reverse * order. * @deprecated Use {@link #suspenderOf(Suspendable)} instead. */ @Deprecated default EventStream guardedBy(Guardian... guardians) { return suspenderOf(Guardian.combine(guardians)::guard); } /** * Returns an event stream that emits the same events as this event stream, * but before each emission, suspends the given {@linkplain Suspendable} * and unsuspends it after the emission has completed. * *

Experimental. The method itself is not experimental, * but the return type {@linkplain SuspenderStream} is. You may want to * assign the result to a variable of type {@code EventStream} to remain * source compatible if the experimenal {@linkplain SuspenderStream} is * removed in the future. */ @Experimental default SuspenderStream suspenderOf(S suspendable) { return new SuspenderStreamImpl<>(this, suspendable); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy