| 7 | import { tryCancel } from "./try-close.js"; |
| 8 | |
| 9 | export class BufferedReadableStream implements AsyncExactReadable { |
| 10 | #buffered: Uint8Array | undefined; |
| 11 | // PERF: `subarray` is slow |
| 12 | // don't use it until absolutely necessary |
| 13 | #bufferedOffset = 0; |
| 14 | #bufferedLength = 0; |
| 15 | |
| 16 | #position = 0; |
| 17 | get position() { |
| 18 | return this.#position; |
| 19 | } |
| 20 | |
| 21 | protected readonly stream: ReadableStream<Uint8Array>; |
| 22 | protected readonly reader: ReadableStreamDefaultReader<Uint8Array>; |
| 23 | |
| 24 | constructor(stream: ReadableStream<Uint8Array>) { |
| 25 | this.stream = stream; |
| 26 | this.reader = stream.getReader(); |
| 27 | } |
| 28 | |
| 29 | #readBuffered(length: number) { |
| 30 | if (!this.#buffered) { |
| 31 | return undefined; |
| 32 | } |
| 33 | |
| 34 | const value = this.#buffered.subarray( |
| 35 | this.#bufferedOffset, |
| 36 | this.#bufferedOffset + length, |
| 37 | ); |
| 38 | |
| 39 | // PERF: Synchronous path for reading from internal buffer |
| 40 | if (this.#bufferedLength > length) { |
| 41 | this.#position += length; |
| 42 | this.#bufferedOffset += length; |
| 43 | this.#bufferedLength -= length; |
| 44 | return value; |
| 45 | } |
| 46 | |
| 47 | this.#position += this.#bufferedLength; |
| 48 | this.#buffered = undefined; |
| 49 | this.#bufferedOffset = 0; |
| 50 | this.#bufferedLength = 0; |
| 51 | return value; |
| 52 | } |
| 53 | |
| 54 | async #readSource(length: number): Promise<Uint8Array> { |
| 55 | const { done, value } = await this.reader.read(); |
| 56 | if (done) { |
| 57 | throw new ExactReadableEndedError(); |
| 58 | } |
| 59 | |
| 60 | if (value.length > length) { |
| 61 | this.#buffered = value; |
| 62 | this.#bufferedOffset = length; |
| 63 | this.#bufferedLength = value.length - length; |
| 64 | this.#position += length; |
| 65 | return value.subarray(0, length); |
| 66 | } |
nothing calls this directly
no test coverage detected