import { assertByteArrayHasEnoughBytesForCodec, assertByteArrayIsNotEmptyForCodec, createDecoder, createEncoder, FixedSizeDecoder, FixedSizeEncoder, Offset, toArrayBuffer, } from '@solana/codecs-core'; import { assertNumberIsBetweenForCodec } from './assertions'; import { Endian, NumberCodecConfig } from './common'; type NumberFactorySharedInput = { config?: NumberCodecConfig; name: string; size: TSize; }; type NumberFactoryEncoderInput = NumberFactorySharedInput & { range?: [bigint | number, bigint | number]; set: (view: DataView, value: TFrom, littleEndian?: boolean) => void; }; type NumberFactoryDecoderInput = NumberFactorySharedInput & { get: (view: DataView, littleEndian?: boolean) => TTo; }; function isLittleEndian(config?: NumberCodecConfig): boolean { return config?.endian === Endian.Big ? false : true; } export function numberEncoderFactory( input: NumberFactoryEncoderInput, ): FixedSizeEncoder { return createEncoder({ fixedSize: input.size, write(value: TFrom, bytes: Uint8Array, offset: Offset): Offset { if (input.range) { assertNumberIsBetweenForCodec(input.name, input.range[0], input.range[1], value); } const arrayBuffer = new ArrayBuffer(input.size); input.set(new DataView(arrayBuffer), value, isLittleEndian(input.config)); bytes.set(new Uint8Array(arrayBuffer), offset); return offset + input.size; }, }); } export function numberDecoderFactory( input: NumberFactoryDecoderInput, ): FixedSizeDecoder { return createDecoder({ fixedSize: input.size, read(bytes, offset = 0): [TTo, number] { assertByteArrayIsNotEmptyForCodec(input.name, bytes, offset); assertByteArrayHasEnoughBytesForCodec(input.name, input.size, bytes, offset); const view = new DataView(toArrayBuffer(bytes, offset, input.size)); return [input.get(view, isLittleEndian(input.config)), offset + input.size]; }, }); }