Files
suaveplan/packages/foundation/bitpacker/bitpacker-strategies/src/strategies/enum/enum.ts
2026-05-27 23:47:53 +01:00

64 lines
1.8 KiB
TypeScript

import type {
BitPackerSchema,
PackingContext,
PackingStrategy,
} from "@suaveplan/bitpacker";
import {
BITPACKER_CODES,
BitpackerError,
isEnumSchema,
} from "@suaveplan/bitpacker";
function bitsRequired(maxValue: number): number {
if (maxValue <= 0) return 0;
return Math.floor(Math.log2(maxValue)) + 1;
}
export class EnumPackingStrategy implements PackingStrategy {
canHandle(schema: BitPackerSchema): boolean {
return isEnumSchema(schema);
}
pack(
data: unknown,
schema: BitPackerSchema,
context: PackingContext
): void {
const { _enum: values } = schema as { _enum: readonly string[] };
if (typeof data !== "string") {
throw new BitpackerError(
BITPACKER_CODES.INVALID_SCHEMA,
`Enum value must be a string, got ${typeof data}`,
{ context: { data, values } }
);
}
const index = values.indexOf(data);
if (index === -1) {
throw new BitpackerError(
BITPACKER_CODES.VALUE_OUT_OF_RANGE,
`Enum value "${data}" not in [${values.join(", ")}]`,
{ context: { data, values } }
);
}
context.writer.writeUint(index, bitsRequired(values.length - 1));
}
unpack(schema: BitPackerSchema, context: PackingContext): unknown {
const { _enum: values } = schema as { _enum: readonly string[] };
const index = context.reader.readUint(bitsRequired(values.length - 1));
if (index >= values.length) {
throw new BitpackerError(
BITPACKER_CODES.UNDERFLOW,
`Enum index ${index} out of range (max ${values.length - 1})`,
{ context: { index, values } }
);
}
return values[index];
}
}