70 lines
2.1 KiB
TypeScript
70 lines
2.1 KiB
TypeScript
/**
|
|
* Minimal LEB128 encoder utilities used by the hand-encoded WASM fixture
|
|
* builder. WebAssembly's binary format uses LEB128 for unsigned 32-bit
|
|
* indices / lengths and signed LEB128 for `i32.const` / `i64.const`
|
|
* literals. Both encoders are bounded by their bit-width and emit the
|
|
* minimal number of bytes.
|
|
*/
|
|
|
|
/** Encode `value` as unsigned LEB128. */
|
|
export function encodeU32(value: number): Uint8Array {
|
|
if (value < 0 || !Number.isFinite(value)) {
|
|
throw new RangeError(`encodeU32: invalid value ${value}`);
|
|
}
|
|
const out: number[] = [];
|
|
let v = value >>> 0;
|
|
do {
|
|
let byte = v & 0x7f;
|
|
v >>>= 7;
|
|
if (v !== 0) byte |= 0x80;
|
|
out.push(byte);
|
|
} while (v !== 0);
|
|
return new Uint8Array(out);
|
|
}
|
|
|
|
/** Encode `value` as signed LEB128 (32-bit). */
|
|
export function encodeI32(value: number): Uint8Array {
|
|
const out: number[] = [];
|
|
let v = value | 0;
|
|
while (true) {
|
|
const byte = v & 0x7f;
|
|
v >>= 7;
|
|
const signBit = (byte & 0x40) !== 0;
|
|
if ((v === 0 && !signBit) || (v === -1 && signBit)) {
|
|
out.push(byte);
|
|
break;
|
|
}
|
|
out.push(byte | 0x80);
|
|
}
|
|
return new Uint8Array(out);
|
|
}
|
|
|
|
/** Encode a name as length-prefixed UTF-8 bytes. */
|
|
export function encodeName(name: string): Uint8Array {
|
|
const bytes = new TextEncoder().encode(name);
|
|
return concat(encodeU32(bytes.length), bytes);
|
|
}
|
|
|
|
/** Concatenate any number of byte arrays. */
|
|
export function concat(...parts: Uint8Array[]): Uint8Array {
|
|
let total = 0;
|
|
for (const p of parts) total += p.length;
|
|
const out = new Uint8Array(total);
|
|
let offset = 0;
|
|
for (const p of parts) {
|
|
out.set(p, offset);
|
|
offset += p.length;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/** Wrap raw payload bytes in a WASM section frame: id + length + payload. */
|
|
export function section(id: number, payload: Uint8Array): Uint8Array {
|
|
return concat(new Uint8Array([id]), encodeU32(payload.length), payload);
|
|
}
|
|
|
|
/** Encode a count-prefixed vector of pre-encoded items. */
|
|
export function vec(items: readonly Uint8Array[]): Uint8Array {
|
|
return concat(encodeU32(items.length), concat(...items));
|
|
}
|