// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
import { createAbortError } from "./_util.ts";
export function abortable(p, signal) {
  if (p instanceof Promise) {
    return abortablePromise(p, signal);
  } else {
    return abortableAsyncIterable(p, signal);
  }
}
/**
 * Make a {@linkcode Promise} abortable with the given signal.
 *
 * @typeParam T The type of the provided and returned promise.
 * @param p The promise to make abortable.
 * @param signal The signal to abort the promise with.
 * @returns A promise that can be aborted.
 *
 * @example Usage
 * ```ts no-eval
 * import { abortablePromise } from "@std/async/abortable";
 *
 * const request = fetch("https://example.com");
 *
 * const c = new AbortController();
 * setTimeout(() => c.abort(), 100);
 *
 * const p = abortablePromise(request, c.signal);
 *
 * // The below throws if the request didn't resolve in 100ms
 * await p;
 * ```
 */ export function abortablePromise(p, signal) {
  if (signal.aborted) {
    return Promise.reject(createAbortError(signal.reason));
  }
  const { promise, reject } = Promise.withResolvers();
  const abort = ()=>reject(createAbortError(signal.reason));
  signal.addEventListener("abort", abort, {
    once: true
  });
  return Promise.race([
    promise,
    p
  ]).finally(()=>{
    signal.removeEventListener("abort", abort);
  });
}
/**
 * Make an {@linkcode AsyncIterable} abortable with the given signal.
 *
 * @typeParam T The type of the provided and returned async iterable.
 * @param p The async iterable to make abortable.
 * @param signal The signal to abort the promise with.
 * @returns An async iterable that can be aborted.
 *
 * @example Usage
 * ```ts no-eval
 * import {
 *   abortableAsyncIterable,
 *   delay,
 * } from "@std/async";
 *
 * const p = async function* () {
 *   yield "Hello";
 *   await delay(1000);
 *   yield "World";
 * };
 * const c = new AbortController();
 * setTimeout(() => c.abort(), 100);
 *
 * // Below throws `DOMException` after 100 ms
 * // and items become `["Hello"]`
 * const items: string[] = [];
 * for await (const item of abortableAsyncIterable(p(), c.signal)) {
 *   items.push(item);
 * }
 * ```
 */ export async function* abortableAsyncIterable(p, signal) {
  if (signal.aborted) {
    throw createAbortError(signal.reason);
  }
  const { promise, reject } = Promise.withResolvers();
  const abort = ()=>reject(createAbortError(signal.reason));
  signal.addEventListener("abort", abort, {
    once: true
  });
  const it = p[Symbol.asyncIterator]();
  while(true){
    const race = Promise.race([
      promise,
      it.next()
    ]);
    race.catch(()=>{
      signal.removeEventListener("abort", abort);
    });
    const { done, value } = await race;
    if (done) {
      signal.removeEventListener("abort", abort);
      return;
    }
    yield value;
  }
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 8092 characters]