var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
const exhaustive = (v) => v;
class Loadable_ {
  constructor(tag, data, error = void 0) {
    __publicField(this, "_tag");
    __publicField(this, "data");
    __publicField(this, "error");
    this._tag = tag;
    this.data = data;
    this.error = error;
  }
  /**
   * The map() function creates a new Loadable with the result of calling
   * the provided function on the contained value in the passed Loadable.
   *
   * If the passed Loadable is NotLoaded then the return value is NotLoaded
   */
  map(fn) {
    switch (this._tag) {
      case "Loaded":
        return new Loadable_("Loaded", fn(this.data));
      case "NotLoaded":
        return NotLoaded;
      case "Failed":
        return new Loadable_("Failed", void 0, this.error);
      default:
        return exhaustive(this._tag);
    }
  }
  static map(l, fn) {
    return l.map(fn);
  }
  /**
   * The flatMap() function creates a new Loadable with the result of calling
   * the provided function on the contained value in the passed Loadable and then
   * flattening the result.
   *
   * If any of the passed or returned Loadables is NotLoaded, the result is NotLoaded.
   */
  flatMap(fn) {
    switch (this._tag) {
      case "Loaded":
        return fn(this.data);
      case "NotLoaded":
        return NotLoaded;
      case "Failed":
        return new Loadable_("Failed", void 0, this.error);
      default:
        return exhaustive(this._tag);
    }
  }
  static flatMap(l, fn) {
    return l.flatMap(fn);
  }
  /**
   * Performs a side-effecting function if the passed Loadable is Loaded.
   */
  forEach(fn) {
    switch (this._tag) {
      case "Loaded": {
        fn(this.data);
        return;
      }
      case "NotLoaded":
        return;
      case "Failed":
        return;
      default:
        exhaustive(this._tag);
    }
  }
  static forEach(l, fn) {
    return l.forEach(fn);
  }
  /**
   * If the passed Loadable is Loaded this returns the data, otherwise
   * it returns the default value.
   */
  getOrElse(def) {
    switch (this._tag) {
      case "Loaded":
        return this.data;
      case "NotLoaded":
        return def;
      case "Failed":
        return def;
      default:
        return exhaustive(this._tag);
    }
  }
  static getOrElse(def, l) {
    return l.getOrElse(def);
  }
  /**
   * Allows you to match out the cases in the Loadable with named
   * arguments.
   */
  match(cases) {
    switch (this._tag) {
      case "Loaded":
        return "Loaded" in cases ? cases.Loaded(this.data) : cases._();
      case "NotLoaded":
        return "NotLoaded" in cases ? cases.NotLoaded() : cases._();
      case "Failed":
        return "Failed" in cases ? cases.Failed(this.error) : cases._();
      default:
        return exhaustive(this._tag);
    }
  }
  static match(l, cases) {
    return l.match(cases);
  }
  /** Like `match` but without argument names */
  quickMatch(nl, fd, f) {
    switch (this._tag) {
      case "Loaded":
        return f(this.data);
      case "NotLoaded":
        return nl;
      case "Failed":
        return fd;
      default:
        return exhaustive(this._tag);
    }
  }
  static quickMatch(l, nl, fd, f) {
    return l.quickMatch(nl, fd, f);
  }
  static all(ls) {
    const res = [];
    let isLoading = false;
    for (const l of ls) {
      if (l._tag === "NotLoaded") {
        isLoading = true;
      } else if (l._tag === "Failed") {
        return new Loadable_("Failed", void 0, l.error);
      } else {
        res.push(l.data);
      }
    }
    if (isLoading) {
      return NotLoaded;
    }
    return new Loadable_("Loaded", res);
  }
  /**
   * Filters an array of Loadables to remove NotLoaded values and returns array of data.
   * Can also optionally accept a conditional function.
   */
  static filterNotLoaded(a, conditionFn = () => true) {
    return a.flatMap((l) => l.isLoaded ? conditionFn(l.data) ? [l.data] : [] : []);
  }
  /** Allows you to use Loadables with React's Suspense component */
  waitFor() {
    switch (this._tag) {
      case "Loaded":
        return this.data;
      case "NotLoaded":
        throw Promise.resolve(void 0);
      case "Failed":
        throw this.error;
      default:
        return exhaustive(this._tag);
    }
  }
  static waitFor(l) {
    return l.waitFor();
  }
  get isLoaded() {
    return this._tag === "Loaded";
  }
  static isLoaded(l) {
    return l.isLoaded;
  }
  get isNotLoaded() {
    return this._tag === "NotLoaded";
  }
  static isNotLoaded(l) {
    return l.isNotLoaded;
  }
  get isFailed() {
    return this._tag === "Failed";
  }
  static isFailed(l) {
    return l.isFailed;
  }
  /** Returns true if the passed object is a Loadable */
  static isLoadable(l) {
    return ["Loaded", "NotLoaded", "Failed"].includes(l == null ? void 0 : l._tag);
  }
  /** If passed a Loadable, returns unchanged. Otherwise, wraps argument in Loaded */
  static ensureLoadable(l) {
    return this.isLoadable(l) ? l : Loaded(l);
  }
}
const Loaded = (data) => new Loadable_("Loaded", data);
const NotLoaded = new Loadable_("NotLoaded", void 0);
const Failed = (error) => new Loadable_("Failed", void 0, error);
const Loadable = Loadable_;
export {
  Failed,
  Loadable,
  Loaded,
  NotLoaded
};
