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]; } }