<commit_before>//---------------------------------------------------------------------
//
// This source file is part of the Folktale project.
//
// See LICENCE for licence information.
// See CONTRIBUTORS for the list of contributors to the project.
//
//---------------------------------------------------------------------

// --[ Dependencies ]--------------------------------------------------
const define = require('folktale/helpers/define');
const thunk  = require('folktale/helpers/thunk');

const Future = thunk(_ => require('./_future'));
const { Pending, Cancelled, Rejected, Resolved } = require('./_execution-state');


// --[ Helpers ]-------------------------------------------------------

/*~
 * Moves a deferred to a resolved state.
 * ---
 * type: |
 *   ('a: Deferred 'f 's, ExecutionState 'f 's) => Void :: mutates 'a
 */
const moveToState = (deferred, newState) => {
  if (!Pending.hasInstance(deferred._state)) {
    const description = newState.matchWith({
      Resolved:  _ => 'resolved',
      Rejected:  _ => 'rejected',
      Cancelled: _ => 'cancelled'
    });
    throw new Error(`Only pending deferreds can be ${description}, this deferred is already ${description}.`);
  }

  deferred._state = newState;

  const listeners = deferred._listeners;
  for (let i = 0; i < listeners.length; ++i) {
    newState.matchWith({
      Resolved: ({ value })  => listeners[i].onResolved(value),
      Rejected: ({ reason }) => listeners[i].onRejected(reason),
      Cancelled: _           => listeners[i].onCancelled()
    });
  }
  deferred._listeners = [];
};


// --[ Implementation ]------------------------------------------------
/*~
 * Deferreds allow creating containers for eventual values.
 */
function Deferred() {
  define(this, '_state', Pending());
  define(this, '_listeners', []);
}


Deferred.prototype = {
  // ---[ State and configuration ]------------------------------------
  /*~
   * The current state of the deferred.
   * 
   * ---
   * isRequired: true
   * category: State and configuration
   * type: |
   *   get (Deferred 'f 's) => ExecutionState 'f 's
   */
  get _state() {
    throw new TypeError('Deferred.prototype is abstract and does not implement ._state.');
  },

  /*~
   * A list of functions to notify of state transitions in this deferred.
   * 
   * ---
   * isRequired: true
   * category: State and configuration
   * type: |
   *   get (Deferred 'f 's) => Array (DeferredListener 'f 's)
   */
  get _listeners() {
    throw new TypeError('Deferred.prototype is abstract and does not implement ._listeners');
  },


  // ---[ Resolving a deferred ]---------------------------------------
  /*~
   * Resolves a deferred with a successful value.
   * 
   * ---
   * category: Resolving a deferred
   * type: |
   *   ('a: Deferred 'f 's).('s) => Void :: mutates 'a
   */
  resolve(value) {
    moveToState(this, Resolved(value));
  },

  /*~
   * Resolves a deferred with a failure.
   * 
   * ---
   * category: Resolving a deferred
   * type: |
   *   ('a: Deferred 'f 's).('f) => Void :: mutates 'a
   */
  reject(reason) {
    moveToState(this, Rejected(reason));
  },

  /*~
   * Resolves a deferred with a cancellation.
   * 
   * ---
   * category: Resolving a deferred
   * type: |
   *   ('a: Deferred 'f 's).() => Void :: mutates 'a
   */
  cancel() {
    moveToState(this, Cancelled());
  },


  // ---[ Reacting to events in a deferred ]---------------------------
  /*~
   * Attaches a listener to be notified when the deferred resovles.
   * 
   * ---
   * category: Reacting to events in a deferred
   * type: |
   *   ('a: Deferred 'f 's).(DeferredListener 'f 's) => Void
   */
  listen(pattern) {
    this._state.matchWith({
      Pending:   _            => this._listeners.push(pattern),
      Cancelled: _            => pattern.onCancelled(), 
      Resolved:  ({ value })  => pattern.onResolved(value),
      Rejected:  ({ reason }) => pattern.onRejected(reason)
    });
  },


  // ---[ Working with deferred values ]-------------------------------
  /*~
   * Returns the eventual value of a deferred as a promise.
   * 
   * ---
   * category: Working with deferred values
   * type: |
   *   (Deferred 'f 's).() => Promise 'f 's
   */
  promise() {
    return new Promise((reject, resolve) => {<commit_msg>(fix future) Fixes order of arguments in promise constructor<commit_after>//---------------------------------------------------------------------
//
// This source file is part of the Folktale project.
//
// See LICENCE for licence information.
// See CONTRIBUTORS for the list of contributors to the project.
//
//---------------------------------------------------------------------

// --[ Dependencies ]--------------------------------------------------
const define = require('folktale/helpers/define');
const thunk  = require('folktale/helpers/thunk');

const Future = thunk(_ => require('./_future'));
const { Pending, Cancelled, Rejected, Resolved } = require('./_execution-state');


// --[ Helpers ]-------------------------------------------------------

/*~
 * Moves a deferred to a resolved state.
 * ---
 * type: |
 *   ('a: Deferred 'f 's, ExecutionState 'f 's) => Void :: mutates 'a
 */
const moveToState = (deferred, newState) => {
  if (!Pending.hasInstance(deferred._state)) {
    const description = newState.matchWith({
      Resolved:  _ => 'resolved',
      Rejected:  _ => 'rejected',
      Cancelled: _ => 'cancelled'
    });
    throw new Error(`Only pending deferreds can be ${description}, this deferred is already ${description}.`);
  }

  deferred._state = newState;

  const listeners = deferred._listeners;
  for (let i = 0; i < listeners.length; ++i) {
    newState.matchWith({
      Resolved: ({ value })  => listeners[i].onResolved(value),
      Rejected: ({ reason }) => listeners[i].onRejected(reason),
      Cancelled: _           => listeners[i].onCancelled()
    });
  }
  deferred._listeners = [];
};


// --[ Implementation ]------------------------------------------------
/*~
 * Deferreds allow creating containers for eventual values.
 */
function Deferred() {
  define(this, '_state', Pending());
  define(this, '_listeners', []);
}


Deferred.prototype = {
  // ---[ State and configuration ]------------------------------------
  /*~
   * The current state of the deferred.
   * 
   * ---
   * isRequired: true
   * category: State and configuration
   * type: |
   *   get (Deferred 'f 's) => ExecutionState 'f 's
   */
  get _state() {
    throw new TypeError('Deferred.prototype is abstract and does not implement ._state.');
  },

  /*~
   * A list of functions to notify of state transitions in this deferred.
   * 
   * ---
   * isRequired: true
   * category: State and configuration
   * type: |
   *   get (Deferred 'f 's) => Array (DeferredListener 'f 's)
   */
  get _listeners() {
    throw new TypeError('Deferred.prototype is abstract and does not implement ._listeners');
  },


  // ---[ Resolving a deferred ]---------------------------------------
  /*~
   * Resolves a deferred with a successful value.
   * 
   * ---
   * category: Resolving a deferred
   * type: |
   *   ('a: Deferred 'f 's).('s) => Void :: mutates 'a
   */
  resolve(value) {
    moveToState(this, Resolved(value));
  },

  /*~
   * Resolves a deferred with a failure.
   * 
   * ---
   * category: Resolving a deferred
   * type: |
   *   ('a: Deferred 'f 's).('f) => Void :: mutates 'a
   */
  reject(reason) {
    moveToState(this, Rejected(reason));
  },

  /*~
   * Resolves a deferred with a cancellation.
   * 
   * ---
   * category: Resolving a deferred
   * type: |
   *   ('a: Deferred 'f 's).() => Void :: mutates 'a
   */
  cancel() {
    moveToState(this, Cancelled());
  },


  // ---[ Reacting to events in a deferred ]---------------------------
  /*~
   * Attaches a listener to be notified when the deferred resovles.
   * 
   * ---
   * category: Reacting to events in a deferred
   * type: |
   *   ('a: Deferred 'f 's).(DeferredListener 'f 's) => Void
   */
  listen(pattern) {
    this._state.matchWith({
      Pending:   _            => this._listeners.push(pattern),
      Cancelled: _            => pattern.onCancelled(), 
      Resolved:  ({ value })  => pattern.onResolved(value),
      Rejected:  ({ reason }) => pattern.onRejected(reason)
    });
  },


  // ---[ Working with deferred values ]-------------------------------
  /*~
   * Returns the eventual value of a deferred as a promise.
   * 
   * ---
   * category: Working with deferred values
   * type: |
   *   (Deferred 'f 's).() => Promise 'f 's
   */
  promise() {
    return new Promise((resolve, reject) => {
{'fraction_non_alphanumeric': 0.24203821656050956, 'fraction_numerical': 0.00023161551823972206, 'mean_word_length': 1.8305473615208128, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5080730', 'n_tokens_mistral': 2621, 'n_tokens_neox': 2506, 'n_words': 692}