byte-rw
Version:
Byte reader/writer for buffers and streams in typescript/javascript
89 lines (77 loc) • 2.86 kB
text/typescript
import { DataViewChunk } from "../dataview/dataview-chunk.js"
import { DataViewByteReaderAsyncChunked } from "../dataview/index.js"
import { copy } from "../utils/copy.js"
export class StreamByteReader extends DataViewByteReaderAsyncChunked {
private readonly reader
private readonly isByob: boolean
constructor(
public readonly stream: ReadableStream,
littleEndian = true,
defaultChunkSize = 4096
) {
super(littleEndian, defaultChunkSize)
try {
this.reader = stream.getReader({ mode: "byob" })
this.isByob = true
}
catch {
this.reader = stream.getReader()
this.isByob = false
}
}
protected async fill(minReadLength: number): Promise<number> {
if (minReadLength === 0)
return 0
let chunk = this.currentChunk
let i_chunk = 0
while (chunk.view.byteLength - chunk.bytesWritten === 0)
chunk = this.pendingChunks[i_chunk++]
let filled = 0
while (minReadLength > 0) {
const availableLength = chunk.view.byteLength - chunk.bytesWritten
const toRead = Math.min(availableLength, minReadLength)
const view = this.isByob ? new DataView(
chunk.view.buffer,
chunk.view.byteOffset + chunk.bytesWritten,
toRead
) : undefined!
const read = await this.reader.read(view)
if (read.done) {
this._isComplete = true
break
}
const readView = read.value as ArrayBufferView
filled += readView.byteLength
const toCopy = Math.min(availableLength, readView.byteLength)
if (!this.isByob) {
copy(
{
buffer: readView.buffer,
byteOffset: readView.byteOffset,
byteLength: toCopy
},
{
buffer: chunk.view.buffer,
byteOffset: chunk.view.byteOffset + chunk.bytesWritten,
byteLength: toCopy
}
)
}
chunk.bytesWritten += toCopy
const toSave = readView.byteLength - toCopy
if (toSave > 0) {
console.assert(!this.isByob)
this.pendChunk({
view: {
buffer: readView.buffer,
byteOffset: readView.byteOffset + toCopy,
byteLength: readView.byteLength - toCopy
},
bytesWritten: toSave
})
}
minReadLength -= readView.byteLength
}
return filled
}
}