Initial Commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import type {
|
||||
BitPackerSchema,
|
||||
PackingContext,
|
||||
PackingStrategy,
|
||||
} from "@suaveplan/bitpacker";
|
||||
import { BITPACKER_CODES, BitpackerError } from "@suaveplan/bitpacker";
|
||||
|
||||
/**
|
||||
* Variable-length integer encoding (similar to protobuf varint).
|
||||
* Schema token: `"varint"` for unsigned, `"-varint"` for signed (zigzag).
|
||||
*/
|
||||
export class VarIntPackingStrategy implements PackingStrategy {
|
||||
canHandle(schema: BitPackerSchema): boolean {
|
||||
return schema === "varint" || schema === "-varint";
|
||||
}
|
||||
|
||||
pack(
|
||||
data: unknown,
|
||||
schema: BitPackerSchema,
|
||||
context: PackingContext
|
||||
): void {
|
||||
if (typeof data !== "number" || !Number.isInteger(data)) {
|
||||
throw new BitpackerError(
|
||||
BITPACKER_CODES.INVALID_SCHEMA,
|
||||
`Expected integer for varint schema, got ${typeof data}`,
|
||||
{ context: { schema, data } }
|
||||
);
|
||||
}
|
||||
|
||||
const signed = schema === "-varint";
|
||||
let value = signed ? this.#zigzagEncode(data) : data;
|
||||
|
||||
if (value < 0) {
|
||||
throw new BitpackerError(
|
||||
BITPACKER_CODES.INVALID_SCHEMA,
|
||||
`Unsigned varint cannot be negative: ${value}`,
|
||||
{ context: { value } }
|
||||
);
|
||||
}
|
||||
|
||||
do {
|
||||
let byte = value & 0x7f;
|
||||
value >>>= 7;
|
||||
if (value !== 0) byte |= 0x80;
|
||||
context.writer.writeUint(byte, 8);
|
||||
} while (value !== 0);
|
||||
}
|
||||
|
||||
unpack(schema: BitPackerSchema, context: PackingContext): unknown {
|
||||
const signed = schema === "-varint";
|
||||
let value = 0;
|
||||
let shift = 0;
|
||||
let byte: number;
|
||||
|
||||
do {
|
||||
byte = context.reader.readUint(8);
|
||||
value |= (byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
} while ((byte & 0x80) !== 0);
|
||||
|
||||
return signed ? this.#zigzagDecode(value) : value;
|
||||
}
|
||||
|
||||
#zigzagEncode(n: number): number {
|
||||
return (n << 1) ^ (n >> 31);
|
||||
}
|
||||
|
||||
#zigzagDecode(n: number): number {
|
||||
return (n >>> 1) ^ -(n & 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user