
com.github.davidmoten.rx.Transformers Maven / Gradle / Ivy
package com.github.davidmoten.rx;
import java.nio.charset.CharsetDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import com.github.davidmoten.rx.StateMachine.Completion;
import com.github.davidmoten.rx.StateMachine.Transition;
import com.github.davidmoten.rx.buffertofile.DataSerializer;
import com.github.davidmoten.rx.buffertofile.DataSerializers;
import com.github.davidmoten.rx.buffertofile.Options;
import com.github.davidmoten.rx.internal.operators.OnSubscribeDoOnEmpty;
import com.github.davidmoten.rx.internal.operators.OperatorBufferPredicateBoundary;
import com.github.davidmoten.rx.internal.operators.OperatorBufferToFile;
import com.github.davidmoten.rx.internal.operators.OperatorDoOnNth;
import com.github.davidmoten.rx.internal.operators.OperatorFromTransformer;
import com.github.davidmoten.rx.internal.operators.TransformerOnTerminateResume;
import com.github.davidmoten.rx.internal.operators.OperatorSampleFirst;
import com.github.davidmoten.rx.internal.operators.OperatorWindowMinMax;
import com.github.davidmoten.rx.internal.operators.OperatorWindowMinMax.Metric;
import com.github.davidmoten.rx.internal.operators.OrderedMerge;
import com.github.davidmoten.rx.internal.operators.TransformerDecode;
import com.github.davidmoten.rx.internal.operators.TransformerDelayFinalUnsubscribe;
import com.github.davidmoten.rx.internal.operators.TransformerLimitSubscribers;
import com.github.davidmoten.rx.internal.operators.TransformerOnBackpressureBufferRequestLimiting;
import com.github.davidmoten.rx.internal.operators.TransformerStateMachine;
import com.github.davidmoten.rx.internal.operators.TransformerStringSplit;
import com.github.davidmoten.rx.util.BackpressureStrategy;
import com.github.davidmoten.rx.util.MapWithIndex;
import com.github.davidmoten.rx.util.MapWithIndex.Indexed;
import com.github.davidmoten.rx.util.Pair;
import com.github.davidmoten.util.Optional;
import rx.Notification;
import rx.Observable;
import rx.Observable.Operator;
import rx.Observable.Transformer;
import rx.Observer;
import rx.Scheduler;
import rx.Scheduler.Worker;
import rx.Subscriber;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Action2;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.functions.Func3;
import rx.internal.util.RxRingBuffer;
import rx.observables.GroupedObservable;
import rx.schedulers.Schedulers;
public final class Transformers {
static final int DEFAULT_INITIAL_BATCH = 1;
public static Operator toOperator(
Func1 super Observable, ? extends Observable> function) {
return OperatorFromTransformer.toOperator(function);
}
public static Transformer collectStats() {
return new Transformer() {
@Override
public Observable call(Observable o) {
return o.scan(Statistics.create(), Functions.collectStats());
}
};
}
public static Transformer> collectStats(
final Func1 super T, ? extends R> function) {
return new Transformer>() {
@Override
public Observable> call(Observable source) {
return source.scan(Pair.create((T) null, Statistics.create()),
new Func2, T, Pair>() {
@Override
public Pair call(Pair pair, T t) {
return Pair.create(t, pair.b().add(function.call(t)));
}
}).skip(1);
}
};
}
public static > Transformer sort() {
return new Transformer() {
@Override
public Observable call(Observable o) {
return o.toSortedList().flatMapIterable(Functions.> identity());
}
};
}
public static Transformer sort(final Comparator super T> comparator) {
return new Transformer() {
@Override
public Observable call(Observable o) {
return o.toSortedList(Functions.toFunc2(comparator))
.flatMapIterable(Functions.> identity());
}
};
}
public static Transformer> toSet() {
return new Transformer>() {
@Override
public Observable> call(Observable o) {
return o.collect(new Func0>() {
@Override
public Set call() {
return new HashSet();
}
}, new Action2, T>() {
@Override
public void call(Set set, T t) {
set.add(t);
}
});
}
};
}
/**
*
* Returns a {@link Transformer} that wraps stream emissions with their
* corresponding zero based index numbers (0,1,2,3,..) in instances of
* {@link Indexed}.
*
* Example usage:
*
*
*
* {@code
* Observable
* .just("a","b","c)
* .mapWithIndex(Transformers.mapWithIndex())
* .map(x -> x.index() + "->" + x.value())
* .forEach(System.out::println);
* }
*
*
*
*
*
* @param
* generic type of the stream being supplemented with an index
* @return transformer that supplements each stream emission with its index
* (zero-based position) in the stream.
*/
public static Transformer> mapWithIndex() {
return MapWithIndex.instance();
}
/**
*
* Returns a {@link Transformer} that allows processing of the source stream
* to be defined in a state machine where transitions of the state machine
* may also emit items to downstream that are buffered if necessary when
* backpressure is requested. flatMap
is part of the processing
* chain so the source may experience requests for more items than are
* strictly required by the endpoint subscriber.
*
*
*
*
* @param initialStateFactory
* the factory to create the initial state of the state machine.
* @param transition
* defines state transitions and consequent emissions to
* downstream when an item arrives from upstream. The
* {@link Subscriber} is called with the emissions to downstream.
* You can optionally call {@link Subscriber#isUnsubscribed()} to
* check if you can stop emitting from the transition. If you do
* wish to terminate the Observable then call
* {@link Subscriber#unsubscribe()} and return anything (say
* {@code null} from the transition (as the next state which will
* not be used). You can also complete the Observable by calling
* {@link Subscriber#onCompleted} or {@link Subscriber#onError}
* from within the transition and return anything from the
* transition (will not be used). The transition should run
* synchronously so that completion of a call to the transition
* should also signify all emissions from that transition have
* been made.
* @param completion
* defines activity that should happen based on the final state
* just before downstream onCompleted()
is called.
* For example any buffered emissions in state could be emitted
* at this point. Don't call observer.onCompleted()
* as it is called for you after the action completes if and only
* if you return true from this function.
* @param backpressureStrategy
* is applied to the emissions from one call of transition and
* should enforce backpressure.
* @param
* the class representing the state of the state machine
* @param
* the input observable type
* @param
* the output observable type
* @throws NullPointerException
* if {@code initialStateFactory} or {@code transition},or
* {@code completionAction} is null
* @return a backpressure supporting transformer that implements the state
* machine specified by the parameters
*/
public static Transformer stateMachine(
Func0 initialStateFactory,
Func3 super State, ? super In, ? super Subscriber, ? extends State> transition,
Func2 super State, ? super Subscriber, Boolean> completion,
BackpressureStrategy backpressureStrategy) {
return TransformerStateMachine. create(initialStateFactory, transition,
completion, backpressureStrategy, DEFAULT_INITIAL_BATCH);
}
public static Transformer stateMachine(
Func0 initialStateFactory,
Func3 super State, ? super In, ? super Subscriber, ? extends State> transition,
Func2 super State, ? super Subscriber, Boolean> completion,
BackpressureStrategy backpressureStrategy, int initialRequest) {
return TransformerStateMachine. create(initialStateFactory, transition,
completion, backpressureStrategy, initialRequest);
}
/**
*
* Returns a {@link Transformer} that allows processing of the source stream
* to be defined in a state machine where transitions of the state machine
* may also emit items to downstream that are buffered if necessary when
* backpressure is requested. flatMap
is part of the processing
* chain so the source may experience requests for more items than are
* strictly required by the endpoint subscriber. The backpressure strategy
* used for emissions from the transition into the flatMap is
* {@link BackpressureStrategy#BUFFER} which corresponds to
* {@link Observable#onBackpressureBuffer}.
*
*
*
*
* @param initialStateFactory
* the factory to create the initial state of the state machine.
* @param transition
* defines state transitions and consequent emissions to
* downstream when an item arrives from upstream. The
* {@link Subscriber} is called with the emissions to downstream.
* You can optionally call {@link Subscriber#isUnsubscribed()} to
* check if you can stop emitting from the transition. If you do
* wish to terminate the Observable then call
* {@link Subscriber#unsubscribe()} and return anything (say
* {@code null} from the transition (as the next state which will
* not be used). You can also complete the Observable by calling
* {@link Subscriber#onCompleted} or {@link Subscriber#onError}
* from within the transition and return anything from the
* transition (will not be used). The transition should run
* synchronously so that completion of a call to the transition
* should also signify all emissions from that transition have
* been made.
* @param completion
* defines activity that should happen based on the final state
* just before downstream onCompleted()
is called.
* For example any buffered emissions in state could be emitted
* at this point. Don't call observer.onCompleted()
* as it is called for you after the action completes if and only
* if you return true from this function.
* @param
* the class representing the state of the state machine
* @param
* the input observable type
* @param
* the output observable type
* @throws NullPointerException
* if {@code initialStateFactory} or {@code transition},or
* {@code completion} is null
* @return a backpressure supporting transformer that implements the state
* machine specified by the parameters
*/
public static Transformer stateMachine(
Func0 extends State> initialStateFactory,
Func3 super State, ? super In, ? super Subscriber, ? extends State> transition,
Func2 super State, ? super Subscriber, Boolean> completion) {
return TransformerStateMachine. create(initialStateFactory, transition,
completion, BackpressureStrategy.BUFFER, DEFAULT_INITIAL_BATCH);
}
public static StateMachine.Builder stateMachine() {
return StateMachine.builder();
}
/**
*
* Returns the source {@link Observable} merged with the other
* observable using the given {@link Comparator} for order. A precondition
* is that the source and other are already ordered. This transformer
* supports backpressure and its inputs must also support backpressure.
*
*
*
*
* @param other
* the other already ordered observable
* @param comparator
* the ordering to use
* @param
* the generic type of the objects being compared
* @return merged and ordered observable
*/
public static final Transformer orderedMergeWith(final Observable other,
final Comparator super T> comparator) {
@SuppressWarnings("unchecked")
Collection> collection = Arrays.asList(other);
return orderedMergeWith(collection, comparator);
}
/**
*
* Returns the source {@link Observable} merged with all of the other
* observables using the given {@link Comparator} for order. A precondition
* is that the source and other are already ordered. This transformer
* supports backpressure and its inputs must also support backpressure.
*
*
*
*
* @param others
* a collection of already ordered observables to merge with
* @param comparator
* the ordering to use
* @param
* the generic type of the objects being compared
* @return merged and ordered observable
*/
public static final Transformer orderedMergeWith(
final Collection> others, final Comparator super T> comparator) {
return new Transformer() {
@Override
public Observable call(Observable source) {
List> collection = new ArrayList>();
collection.add(source);
collection.addAll(others);
return OrderedMerge. create(collection, comparator, false);
}
};
}
/**
* Returns a {@link Transformer} that returns an {@link Observable} that is
* a buffering of the source Observable into lists of sequential items that
* are equal.
*
*
* For example, the stream
* {@code Observable.just(1, 1, 2, 2, 1).compose(toListUntilChanged())}
* would emit {@code [1,1], [2], [1]}.
*
* @param
* the generic type of the source Observable
* @return transformer as above
*/
public static Transformer> toListUntilChanged() {
Func2, T, Boolean> equal = HolderEquals.instance();
return toListWhile(equal);
}
private static class HolderEquals {
private static final Func2, Object, Boolean> INSTANCE = new Func2, Object, Boolean>() {
@Override
public Boolean call(Collection