pump = async (writer, reader, primer) => {
  /** @param {Promise<IteratorResult<TRead, TReadReturn>>} promise */
  const tick = promise =>
    E.when(
      promise,
      result => {
        if (result.done) {
          return writer.return(result.value);
        } else {
          // Behold: mutual recursion.
          // eslint-disable-next-line no-use-before-define
          return tock(writer.next(result.value));
        }
      },
      (/** @type {Error} */ error) => {
        return writer.throw(error);
      },
    );
  /** @param {Promise<IteratorResult<TWrite, TWriteReturn>>} promise */
  const tock = promise =>
    E.when(
      promise,
      result => {
        if (result.done) {
          return reader.return(result.value);
        } else {
          return tick(reader.next(result.value));
        }
      },
      (/** @type {Error} */ error) => {
        return reader.throw(error);
      },
    );
  await tick(reader.next(primer));
  return undefined;
}
@template TRead
@template TWrite
@template TReadReturn
@template TWriteReturn
@param {import('./types.js').Stream<TWrite, TRead, TWriteReturn, TReadReturn>} writer
@param {import('./types.js').Stream<TRead, TWrite, TReadReturn, TWriteReturn>} reader
@param {TWrite} primer