/**
* An {@link ObservableOperator} that enables the switch-case behavior in Rx-Java, it uses
* a table look up technique to simulate a switch-case behavior
*
* you must supply a {@link Map} that holds functions that will be executed if the emitted
* item matches the key they are mapped to
*
* if multiple emitted items matches several keys, all there functions will be executed and
* will emit there results, if you want the first match to disable the rest of the checks,
* you can use {@link SwitchCaseBreak} instead
*
* sample code :
*
* {@code List list = Arrays.asList(1, 2, 3, 4);}
* {@code Map> caseBlocks = new HashMap<>(2);}
* {@code caseBlocks.put(2, (i) -> "TWO SELECTED");}
* {@code caseBlocks.put(3, (i) -> "THREE SELECTED");}
*
* {@code Observable.fromIterable(list)}
* {@code .lift(new SwitchCase<>(caseBlocks))}
* {@code .subscribe(System.out::println);}
*
* // result :
* TWO SELECTED
* THREE SELECTED
*
* @param the type of the items that will be passed to the {@code switch} statement
* @param the type of the items that will be returned from the {@code case} block execution
*/
public class SwitchCase implements ObservableOperator {
final Map> caseBlocks = new LinkedHashMap<>();
/**
* create a {@link SwitchCase} operator, if any {@link Function} returned {@code null}, the
* whole operation will crash
*
* @param caseBlocks the map that holds {@link Function} that are the case-blocks in this
* switch-case
*/
public SwitchCase(@NonNull Map> caseBlocks) {
if (caseBlocks != null) {
this.caseBlocks.putAll(caseBlocks);
}
}
@Override
public Observer super T> apply(final Observer super R> observer) throws Exception {
return createResultObserver(observer);
}
private Observer createResultObserver(final Observer super R> observer) {
return new Observer() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull T switchOn) {
Function block = Maybe.just(caseBlocks)
.filter(map -> map.containsKey(switchOn))
.map(map -> map.get(switchOn))
.blockingGet();
if (block == null) {
return;
}
try {
invokeOnNext(observer, block.apply(switchOn));
} catch (Throwable e) {
onError(e);
}
}
@Override
public void onError(@NonNull Throwable e) {
observer.onError(e);
}
@Override
public void onComplete() {
observer.onComplete();
}
};
}
void invokeOnNext(Observer super R> observer, R onNextValue) {
observer.onNext(onNextValue);
}
}