preserves/implementations/javascript/packages/core/src/iolist.ts

68 lines
1.7 KiB
TypeScript

import { Bytes, BytesLike, underlying } from "./bytes";
export type IOList = number | BytesLike | IOList[] | false | CountedIOList;
class CountedIOList {
value: IOList;
length: number;
constructor(i: IOList) {
this.value = i;
this.length = iolistLength(i);
}
}
export function pushByte(i: IOList, b: number): IOList {
if (Array.isArray(i)) {
i.push(b);
return i;
} else {
return [i, b];
}
}
export function append(i: IOList, j: IOList): IOList {
if (i === false) return j;
if (j === false) return i;
return [i, j];
}
export function iolistLength(i: IOList, acc = 0): number {
if (typeof(i) === 'number') return acc + 1;
if (i === false) return acc;
if (Array.isArray(i)) return i.reduce<number>((acc, j) => iolistLength(j, acc), acc);
if (i instanceof CountedIOList) return acc + i.length;
return acc + i.length;
}
export function countIOList(i: IOList): CountedIOList {
if (i instanceof CountedIOList) return i;
return new CountedIOList(i);
}
export function ioListBytes(i: IOList): Bytes {
if (i instanceof Bytes) return i;
const buffer = new Bytes(iolistLength(i));
function fill(i: IOList, offset: number): number {
while (i instanceof CountedIOList) i = i.value;
if (typeof(i) === 'number') {
buffer._view[offset] = i;
return offset + 1;
}
if (i === false) {
return offset;
}
if (Array.isArray(i)) {
i.forEach(j => offset = fill(j, offset));
return offset;
}
const bs = underlying(i);
buffer._view.set(bs, offset);
return offset + bs.length;
}
fill(i, 0);
return buffer;
}