reading the first n bytes of a byte stream (in form of a AsyncIterable) feels cumbersome and error prone.
Is there a better way to implement this?
async function shift(
length: number,
stream: AsyncIterable<Uint8Array>
): Promise<[Uint8Array, AsyncIterable<Uint8Array>]> {
const prefix = new Uint8Array(length);
let offset = 0;
const iterator = stream[Symbol.asyncIterator]();
while (true) {
const { done, value } = await iterator.next();
if (done) {
throw new Error("Buffer underflow");
} else {
const chunk = value;
if (chunk.length < length - offset) {
prefix.set(chunk, offset);
offset += chunk.length;
} else {
const slice = chunk.slice(0, length - offset);
prefix.set(slice, offset);
return [prefix, prepend(chunk.slice(slice.length), stream)];
}
}
}
}
async function* prepend(
prefix: Uint8Array,
stream: AsyncIterable<Uint8Array>
) {
yield prefix;
yield* stream;
}
2
Answers
stream primitives
We’ll start by defining stream primitives –
shift
Using these stream primitives, we can write
shift
in a comfortable and safe way –Let’s create a mock
buffer
and test it –demo
Run and verify the result on the typescript playground
I think the iterator logic itself can be simplified by using a
notClosing
helper and normal iteration:Unless you want to convert the stream from an iterator of chunks into a much less efficient iterator of individual bytes, there’s nothing you can further simplify about the
offset
logic.