Code coverage report for src/subject/ReplaySubject.ts

Statements: 100% (52 / 52)      Branches: 90% (18 / 20)      Functions: 100% (8 / 8)      Lines: 100% (47 / 47)      Ignored: none     

All files » src/subject/ » ReplaySubject.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 841   1     1   1 91         132 161   91 91 91 91     1 196 196 196 196     1 119 119   119 4     119 119 119 85   119     1 315     1 315 315 315   315 315         315 266 255   11     315 109     315 116     315   1   1 196   1  
import {Subject} from '../Subject';
import {Scheduler} from '../Scheduler';
import {queue} from '../scheduler/queue';
import {Subscriber} from '../Subscriber';
import {Subscription} from '../Subscription';
import {ObserveOnSubscriber} from '../operator/observeOn';
 
export class ReplaySubject<T> extends Subject<T> {
  private events: ReplayEvent<T>[] = [];
  private scheduler: Scheduler;
  private bufferSize: number;
  private windowSize: number;
 
  constructor(bufferSize: number = Number.POSITIVE_INFINITY,
              windowSize: number = Number.POSITIVE_INFINITY,
              scheduler?: Scheduler) {
    super();
    this.scheduler = scheduler;
    this.bufferSize = bufferSize < 1 ? 1 : bufferSize;
    this.windowSize = windowSize < 1 ? 1 : windowSize;
  }
 
  protected _next(value: T): void {
    const now = this._getNow();
    this.events.push(new ReplayEvent(now, value));
    this._trimBufferThenGetEvents(now);
    super._next(value);
  }
 
  protected _subscribe(subscriber: Subscriber<T>): Subscription | Function | void {
    const events = this._trimBufferThenGetEvents(this._getNow());
    const scheduler = this.scheduler;
 
    if (scheduler) {
      subscriber.add(subscriber = new ObserveOnSubscriber<T>(subscriber, scheduler));
    }
 
    let index = -1;
    const len = events.length;
    while (++index < len && !subscriber.isUnsubscribed) {
      subscriber.next(events[index].value);
    }
    return super._subscribe(subscriber);
  }
 
  private _getNow(): number {
    return (this.scheduler || queue).now();
  }
 
  private _trimBufferThenGetEvents(now: number): ReplayEvent<T>[] {
    const bufferSize = this.bufferSize;
    const windowSize = this.windowSize;
    const events = this.events;
 
    let eventsCount = events.length;
    let spliceCount = 0;
 
    // Trim events that fall out of the time window.
    // Start at the front of the list. Break early once
    // we encounter an event that falls within the window.
    while (spliceCount < eventsCount) {
      if ((now - events[spliceCount].time) < windowSize) {
        break;
      }
      spliceCount += 1;
    }
 
    if (eventsCount > bufferSize) {
      spliceCount = Math.max(spliceCount, eventsCount - bufferSize);
    }
 
    if (spliceCount > 0) {
      events.splice(0, spliceCount);
    }
 
    return events;
  }
}
 
class ReplayEvent<T> {
  constructor(public time: number, public value: T) {
  }
}