"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _errors = require("./errors");

// Like an EventEmitter, but for only a single "event". This provides type-safety
// for the values emitted. Rather than passing predetermined strings (which can
// be misspelled), create an instance of ValueEmitter for every logical "event"
// to be dispatched, and type it according to the type of value emitted.
class ValueEmitter {
  // An array of listeners. One might think a Set would be better for O(1) removal,
  // but splicing a JS array gets pretty close, and copying the array (as is done
  // in emit) is far faster than a Set copy: https://github.com/atom/event-kit/pull/39
  _listeners = [];
  _disposed = false;

  addListener(listener) {
    if (this._disposed) {
      throw new _errors.AlreadyDisposedError('Cannot add a listener since this ValueEmitter has been disposed');
    }

    this._listeners.push(listener); // Close over a reference to this emitter in the disposable below, rather
    // than referencing `this` directly. This allows us to set it to null after
    // slicing out the listener.
    // This prevents anyone holding onto the disposable after disposal from
    // unintentionally retaining a reference to this emitter.


    let emitter = this;
    return {
      dispose() {
        if (emitter == null) {
          return;
        }

        if (emitter._disposed) {
          emitter = null;
          return;
        }

        let listeners = emitter._listeners;
        let listenerIndex = listeners.indexOf(listener);

        if (listenerIndex > -1) {
          listeners.splice(listenerIndex, 1);
        }

        emitter = null;
      }

    };
  }

  emit(value) {
    if (this._disposed) {
      throw new _errors.AlreadyDisposedError('Cannot emit since this ValueEmitter has been disposed');
    } // Iterate over a copy of listeners. This prevents the following cases:
    // * When a listener callback can itself register a new listener and be
    //   emitted as part of this iteration.
    // * When a listener callback disposes of this emitter mid-emit, preventing
    //   other listeners from receiving the event.


    let listeners = this._listeners.slice();

    for (let i = 0; i < listeners.length; i++) {
      listeners[i](value);
    }
  }

  dispose() {
    if (this._disposed) {
      return;
    }

    this._listeners = [];
    this._disposed = true;
  }

}

exports.default = ValueEmitter;