/**
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rx.internal.operators;
import static rx.Observable.concat;
import static rx.Observable.just;
import static rx.Observable.zip;
import rx.Observable;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.internal.util.UtilityFunctions;
/**
* Returns an {@link Observable} that emits a single {@code Boolean} value that indicates whether two source
* {@code Observable}s emit sequences of items that are equivalent to each other.
*/
public final class OperatorSequenceEqual {
private OperatorSequenceEqual() {
throw new IllegalStateException("No instances!");
}
/** NotificationLite doesn't work as zip uses it. */
private static final Object LOCAL_ONCOMPLETED = new Object();
static <T> Observable<Object> materializeLite(Observable<T> source) {
return concat(
source.map(new Func1<T, Object>() {
@Override
public Object call(T t1) {
return t1;
}
}), just(LOCAL_ONCOMPLETED));
}
/**
* Tests whether two {@code Observable} sequences are identical, emitting {@code true} if both sequences
* complete without differing, and {@code false} if the two sequences diverge at any point.
*
* @param first
* the first of the two {@code Observable}s to compare
* @param second
* the second of the two {@code Observable}s to compare
* @param equality
* a function that tests emissions from each {@code Observable} for equality
* @return an {@code Observable} that emits {@code true} if {@code first} and {@code second} complete
* after emitting equal sequences of items, {@code false} if at any point in their sequences the
* two {@code Observable}s emit a non-equal item.
*/
public static <T> Observable<Boolean> sequenceEqual(
Observable<? extends T> first, Observable<? extends T> second,
final Func2<? super T, ? super T, Boolean> equality) {
Observable<Object> firstObservable = materializeLite(first);
Observable<Object> secondObservable = materializeLite(second);
return zip(firstObservable, secondObservable,
new Func2<Object, Object, Boolean>() {
@Override
@SuppressWarnings("unchecked")
public Boolean call(Object t1, Object t2) {
boolean c1 = t1 == LOCAL_ONCOMPLETED;
boolean c2 = t2 == LOCAL_ONCOMPLETED;
if (c1 && c2) {
return true;
}
if (c1 || c2) {
return false;
}
// Now t1 and t2 must be 'onNext'.
return equality.call((T)t1, (T)t2);
}
}).all(UtilityFunctions.<Boolean> identity());
}
}