1 import { Operator } from '../Operator';
2 import { Observable } from '../Observable';
3 import { Subscriber } from '../Subscriber';
4 import { Subscription } from '../Subscription';
6 import { Observer, OperatorFunction } from '../types';
9 * Compares all values of two observables in sequence using an optional comparator function
10 * and returns an observable of a single boolean value representing whether or not the two sequences
13 * <span class="informal">Checks to see of all values emitted by both observables are equal, in order.</span>
15 * ![](sequenceEqual.png)
17 * `sequenceEqual` subscribes to two observables and buffers incoming values from each observable. Whenever either
18 * observable emits a value, the value is buffered and the buffers are shifted and compared from the bottom
19 * up; If any value pair doesn't match, the returned observable will emit `false` and complete. If one of the
20 * observables completes, the operator will wait for the other observable to complete; If the other
21 * observable emits before completing, the returned observable will emit `false` and complete. If one observable never
22 * completes or emits after the other complets, the returned observable will never complete.
25 * figure out if the Konami code matches
27 * import { from, fromEvent } from 'rxjs';
28 * import { sequenceEqual, bufferCount, mergeMap, map } from 'rxjs/operators';
30 * const codes = from([
41 * 'Enter', // no start key, clearly.
44 * const keys = fromEvent(document, 'keyup').pipe(map(e => e.code));
45 * const matches = keys.pipe(
48 * last11 => from(last11).pipe(sequenceEqual(codes)),
51 * matches.subscribe(matched => console.log('Successful cheat at Contra? ', matched));
54 * @see {@link combineLatest}
56 * @see {@link withLatestFrom}
58 * @param {Observable} compareTo The observable sequence to compare the source sequence to.
59 * @param {function} [comparator] An optional function to compare each value pair
60 * @return {Observable} An Observable of a single boolean value representing whether or not
61 * the values emitted by both observables were equal in sequence.
62 * @method sequenceEqual
65 export function sequenceEqual<T>(compareTo: Observable<T>,
66 comparator?: (a: T, b: T) => boolean): OperatorFunction<T, boolean> {
67 return (source: Observable<T>) => source.lift(new SequenceEqualOperator(compareTo, comparator));
70 export class SequenceEqualOperator<T> implements Operator<T, boolean> {
71 constructor(private compareTo: Observable<T>,
72 private comparator: (a: T, b: T) => boolean) {
75 call(subscriber: Subscriber<boolean>, source: any): any {
76 return source.subscribe(new SequenceEqualSubscriber(subscriber, this.compareTo, this.comparator));
81 * We need this JSDoc comment for affecting ESDoc.
85 export class SequenceEqualSubscriber<T, R> extends Subscriber<T> {
88 private _oneComplete = false;
90 constructor(destination: Observer<R>,
91 private compareTo: Observable<T>,
92 private comparator: (a: T, b: T) => boolean) {
94 (this.destination as Subscription).add(compareTo.subscribe(new SequenceEqualCompareToSubscriber(destination, this)));
97 protected _next(value: T): void {
98 if (this._oneComplete && this._b.length === 0) {
106 public _complete(): void {
107 if (this._oneComplete) {
108 this.emit(this._a.length === 0 && this._b.length === 0);
110 this._oneComplete = true;
116 const { _a, _b, comparator } = this;
117 while (_a.length > 0 && _b.length > 0) {
120 let areEqual = false;
122 areEqual = comparator ? comparator(a, b) : a === b;
124 this.destination.error(e);
132 emit(value: boolean) {
133 const { destination } = this;
134 destination.next(value);
135 destination.complete();
139 if (this._oneComplete && this._a.length === 0) {
148 if (this._oneComplete) {
149 this.emit(this._a.length === 0 && this._b.length === 0);
151 this._oneComplete = true;
156 class SequenceEqualCompareToSubscriber<T, R> extends Subscriber<T> {
157 constructor(destination: Observer<R>, private parent: SequenceEqualSubscriber<T, R>) {
161 protected _next(value: T): void {
162 this.parent.nextB(value);
165 protected _error(err: any): void {
166 this.parent.error(err);
170 protected _complete(): void {
171 this.parent.completeB();