UNPKG

@metaplex-foundation/umi-serializers

Version:

A comprehensive set of serializers for the Umi framework

87 lines (84 loc) 2.88 kB
import { BaseSerializerOptions, mergeBytes, Serializer, } from '@metaplex-foundation/umi-serializers-core'; import { u32 } from '@metaplex-foundation/umi-serializers-numbers'; import { ArrayLikeSerializerSize } from './arrayLikeSerializerSize'; import { InvalidNumberOfItemsError } from './errors'; import { getResolvedSize, getSizeDescription, getSizeFromChildren, getSizePrefix, } from './utils'; /** * Defines the options for `Map` serializers. * @category Serializers */ export type MapSerializerOptions = BaseSerializerOptions & { /** * The size of the map. * @defaultValue `u32()` */ size?: ArrayLikeSerializerSize; }; /** * Creates a serializer for a map. * * @param key - The serializer to use for the map's keys. * @param value - The serializer to use for the map's values. * @param options - A set of options for the serializer. * @category Serializers */ export function map<TK, TV, UK extends TK = TK, UV extends TV = TV>( key: Serializer<TK, UK>, value: Serializer<TV, UV>, options: MapSerializerOptions = {} ): Serializer<Map<TK, TV>, Map<UK, UV>> { const size = options.size ?? u32(); return { description: options.description ?? `map(${key.description}, ${value.description}; ${getSizeDescription( size )})`, fixedSize: getSizeFromChildren(size, [key.fixedSize, value.fixedSize]), maxSize: getSizeFromChildren(size, [key.maxSize, value.maxSize]), serialize: (map: Map<TK, TV>) => { if (typeof size === 'number' && map.size !== size) { throw new InvalidNumberOfItemsError('map', size, map.size); } const itemBytes = Array.from(map, ([k, v]) => mergeBytes([key.serialize(k), value.serialize(v)]) ); return mergeBytes([getSizePrefix(size, map.size), ...itemBytes]); }, deserialize: (bytes: Uint8Array, offset = 0) => { const map: Map<UK, UV> = new Map(); if (typeof size === 'object' && bytes.slice(offset).length === 0) { return [map, offset]; } if (size === 'remainder') { while (offset < bytes.length) { const [deserializedKey, kOffset] = key.deserialize(bytes, offset); offset = kOffset; const [deserializedValue, vOffset] = value.deserialize(bytes, offset); offset = vOffset; map.set(deserializedKey, deserializedValue); } return [map, offset]; } const [resolvedSize, newOffset] = getResolvedSize(size, bytes, offset); offset = newOffset; for (let i = 0; i < resolvedSize; i += 1) { const [deserializedKey, kOffset] = key.deserialize(bytes, offset); offset = kOffset; const [deserializedValue, vOffset] = value.deserialize(bytes, offset); offset = vOffset; map.set(deserializedKey, deserializedValue); } return [map, offset]; }, }; }