All files / src/common_serdes one_of.ts

100% Statements 32/32
100% Branches 1/1
100% Functions 6/6
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 7019x     19x 1x 1x       19x 1x       1x 1x   1x   3x 3x   3x 3x       3x 3x   3x 1x     2x 2x   2x                   1x   1x 2x 2x     1x           1x   1x 2x 2x     1x    
import { define } from "../define";
import { OneOfFactory } from "../types";
 
export class InvalidOneOfType extends Error {
  constructor(readonly type: number) {
    super(`Invalid oneOf type (${type})`);
  }
}
 
export const oneOf: OneOfFactory = (headSd, typeToSerdes) => {
  const types = Object.keys(
    typeToSerdes
  ) as (keyof typeof typeToSerdes)[];
 
  const typeToInt = mapKeysToIndexes(types);
  const intToType = swapKeysAndValues(typeToInt);
 
  return define(
    (ctx, data) => {
      const i = typeToInt[data.type];
      headSd.ser(ctx, i);
 
      const serdes = typeToSerdes[data.type];
      serdes.ser(ctx, data.value);
    },
 
    (ctx) => {
      const i = headSd.des(ctx);
      const type = intToType[i];
 
      if (type === undefined) {
        throw new InvalidOneOfType(i);
      }
 
      const serdes = typeToSerdes[type];
      const value = serdes.des(ctx);
 
      return { type, value };
    }
  );
};
 
type Key = string | number | symbol;
 
function mapKeysToIndexes<T extends Key>(
  keys: T[]
): Record<T, number> {
  const result: Record<T, number> = {} as Record<T, number>;
 
  for (let i = 0; i < keys.length; ++i) {
    const e = keys[i];
    result[e] = i;
  }
 
  return result;
}
 
function swapKeysAndValues<K extends Key, V extends Key>(
  obj: Record<K, V>
): Record<V, K> {
  const result: Record<V, K> = {} as Record<V, K>;
 
  for (const k of Object.keys(obj) as K[]) {
    const v = obj[k];
    result[v] = k;
  }
 
  return result;
}