Code coverage report for src/Subject.ts

Statements: 100% (124 / 124)      Branches: 100% (30 / 30)      Functions: 100% (23 / 23)      Lines: 100% (119 / 119)      Ignored: none     

All files » src/ » Subject.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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202    1 1 1 1 1   1 1 1   1 1 1 1 1 1   2803       1 129     1 2         2802 2802   2802 2802   2802   1 915 915 915     1 2063 2 2061 43 43 2018 43 43 1975 1     1974   1974     1 735     1 1     1 1746 1746     1 5764 22     5742 5742 5742   5742 3 5739 26       1 353 17     336 336   336 3     333 333     1 1430 69     1361   1361 26     1335 1335     1 5690 5690 5690   5690 4654       1 333 333 333     333 333   333 324     333     1 1315 1315 1315     1315 1315   1315 982     1315   1   1 917 917     1 920 920     1 6     1 1     1 1     1 6     1 1     1 1   1
import {Operator} from './Operator';
import {Observer} from './Observer';
import {Observable} from './Observable';
import {Subscriber} from './Subscriber';
import {Subscription} from './Subscription';
import {SubjectSubscription} from './subject/SubjectSubscription';
import {rxSubscriber} from './symbol/rxSubscriber';
 
const subscriptionAdd = Subscription.prototype.add;
const subscriptionRemove = Subscription.prototype.remove;
const subscriptionUnsubscribe = Subscription.prototype.unsubscribe;
 
const subscriberNext = Subscriber.prototype.next;
const subscriberError = Subscriber.prototype.error;
const subscriberComplete = Subscriber.prototype.complete;
const _subscriberNext = Subscriber.prototype._next;
const _subscriberError = Subscriber.prototype._error;
const _subscriberComplete = Subscriber.prototype._complete;
 
export class Subject<T> extends Observable<T> implements Observer<T>, Subscription<T> {
  _subscriptions: Subscription<T>[];
  _unsubscribe: () => void;
 
  [rxSubscriber]() {
    return this;
  }
 
  static create<T>(source: Observable<T>, destination: Observer<T>): Subject<T> {
    return new BidirectionalSubject(source, destination);
  }
 
  protected destination: Observer<T>;
 
  observers: Observer<T>[] = [];
  isUnsubscribed: boolean = false;
 
  dispatching: boolean = false;
  errorSignal: boolean = false;
  errorInstance: any;
  completeSignal: boolean = false;
 
  lift<T, R>(operator: Operator<T, R>): Observable<T> {
    const subject = new BidirectionalSubject(this, this.destination || this);
    subject.operator = operator;
    return subject;
  }
 
  _subscribe(subscriber: Subscriber<any>): Subscription<T> {
    if (subscriber.isUnsubscribed) {
      return;
    } else if (this.errorSignal) {
      subscriber.error(this.errorInstance);
      return;
    } else if (this.completeSignal) {
      subscriber.complete();
      return;
    } else if (this.isUnsubscribed) {
      throw new Error('Cannot subscribe to a disposed Subject.');
    }
 
    this.observers.push(subscriber);
 
    return new SubjectSubscription(this, subscriber);
  }
 
  add(subscription?) {
    subscriptionAdd.call(this, subscription);
  }
 
  remove(subscription?) {
    subscriptionRemove.call(this, subscription);
  }
 
  unsubscribe() {
    this.observers = void 0;
    subscriptionUnsubscribe.call(this);
  }
 
  next(value: T): void {
    if (this.isUnsubscribed) {
      return;
    }
 
    this.dispatching = true;
    this._next(value);
    this.dispatching = false;
 
    if (this.errorSignal) {
      this.error(this.errorInstance);
    } else if (this.completeSignal) {
      this.complete();
    }
  }
 
  error(err?: any): void {
    if (this.isUnsubscribed || this.completeSignal) {
      return;
    }
 
    this.errorSignal = true;
    this.errorInstance = err;
 
    if (this.dispatching) {
      return;
    }
 
    this._error(err);
    this.unsubscribe();
  }
 
  complete(): void {
    if (this.isUnsubscribed || this.errorSignal) {
      return;
    }
 
    this.completeSignal = true;
 
    if (this.dispatching) {
      return;
    }
 
    this._complete();
    this.unsubscribe();
  }
 
  _next(value: T): void {
    let index = -1;
    const observers = this.observers.slice(0);
    const len = observers.length;
 
    while (++index < len) {
      observers[index].next(value);
    }
  }
 
  _error(err: any): void {
    let index = -1;
    const observers = this.observers;
    const len = observers.length;
 
    // optimization -- block next, complete, and unsubscribe while dispatching
    this.observers = void 0;
    this.isUnsubscribed = true;
 
    while (++index < len) {
      observers[index].error(err);
    }
 
    this.isUnsubscribed = false;
  }
 
  _complete(): void {
    let index = -1;
    const observers = this.observers;
    const len = observers.length;
 
    // optimization -- block next, complete, and unsubscribe while dispatching
    this.observers = void 0; // optimization
    this.isUnsubscribed = true;
 
    while (++index < len) {
      observers[index].complete();
    }
 
    this.isUnsubscribed = false;
  }
}
 
class BidirectionalSubject<T> extends Subject<T> {
  constructor(public source: Observable<any>, protected destination: Observer<any>) {
    super();
  }
 
  _subscribe(subscriber: Subscriber<T>): Subscription<T> {
    const operator = this.operator;
    return this.source._subscribe.call(this.source, operator ? operator.call(subscriber) : subscriber);
  }
 
  next(value?: T): void {
    subscriberNext.call(this, value);
  }
 
  error(err?: any): void {
    subscriberError.call(this, err);
  }
 
  complete(): void {
    subscriberComplete.call(this);
  }
 
  _next(value: T): void {
    _subscriberNext.call(this, value);
  }
 
  _error(err: any): void {
    _subscriberError.call(this, err);
  }
 
  _complete(): void {
    _subscriberComplete.call(this);
  }
}