UNPKG

it-byte-stream

Version:

Read and write arbitrary bytes over a duplex stream

96 lines 3.08 kB
/** * @packageDocumentation * * This module makes it easy to send and receive bytes over streams. * * @example * * ```typescript * import { byteStream } from 'it-byte-stream' * * const stream = byteStream(duplex) * * // read the next chunk * const bytes = await stream.read() * * // read the next five bytes * const fiveBytes = await stream.read(5) * * // write bytes into the stream * await stream.write(Uint8Array.from([0, 1, 2, 3, 4])) * ``` */ import { queuelessPushable } from 'it-queueless-pushable'; import { raceSignal } from 'race-signal'; import { Uint8ArrayList } from 'uint8arraylist'; import { UnexpectedEOFError } from './errors.js'; export function byteStream(duplex, opts) { const write = queuelessPushable(); duplex.sink(write).catch(async (err) => { await write.end(err); }); duplex.sink = async (source) => { for await (const buf of source) { await write.push(buf); } await write.end(); }; let source = duplex.source; if (duplex.source[Symbol.iterator] != null) { source = duplex.source[Symbol.iterator](); } else if (duplex.source[Symbol.asyncIterator] != null) { source = duplex.source[Symbol.asyncIterator](); } const readBuffer = new Uint8ArrayList(); const W = { read: async (options) => { options?.signal?.throwIfAborted(); if (options?.bytes == null) { // just read whatever arrives const { done, value } = await raceSignal(source.next(), options?.signal); if (done === true) { return null; } return value; } while (readBuffer.byteLength < options.bytes) { const { value, done } = await raceSignal(source.next(), options?.signal); if (done === true) { throw new UnexpectedEOFError('unexpected end of input'); } readBuffer.append(value); } const buf = readBuffer.sublist(0, options.bytes); readBuffer.consume(options.bytes); return buf; }, write: async (data, options) => { options?.signal?.throwIfAborted(); // just write if (data instanceof Uint8Array) { await write.push(data, options); } else { await write.push(data.subarray(), options); } }, unwrap: () => { if (readBuffer.byteLength > 0) { const originalStream = duplex.source; duplex.source = (async function* () { if (opts?.yieldBytes === false) { yield readBuffer; } else { yield* readBuffer; } yield* originalStream; }()); } return duplex; } }; return W; } //# sourceMappingURL=index.js.map