JSFiddle - React, Tailwind, and code Playground

by Yaroslav Samardak

TypeScript

import { Parser } from "binary-parser"
import { Buffer } from "buffer"

type FieldDef = {
  id: string
  type: 'int16' | 'uint16' | 'int32' | 'uint32'
}

type ComposeOp = {
  id: string
  op: 'compose'
  mode: 'bitwise'
  inputs: string[]
  width: number
  signed: boolean
}

type Schema = {
  fields: FieldDef[]        // порядок = порядок в бинаре
  operations: ComposeOp[]
  output: string[]
}

const TYPE_WIDTH: Record<string, number> = {
  int8: 8,
  uint8: 8,
  int16: 16,
  uint16: 16,
  int32: 32,
  uint32: 32
}

function composeBitwise(
  inputs: string[],
  ctx: any,
  fieldById: Record<string, FieldDef>,
  totalWidth: number,
  signed: boolean
): number {
  let result = 0
  let shift = totalWidth

  for (const id of inputs) {
    const field = fieldById[id]
    if (!field) {
      throw new Error(`Unknown field "${id}" in compose`)
    }

    const width = TYPE_WIDTH[field.type]
    const value = ctx[id]

    shift -= width
    result |= (value & ((1 << width) - 1)) << shift
  }

  if (signed) {
    const signBit = 1 << (totalWidth - 1)
    if (result & signBit) {
      result -= 1 << totalWidth
    }
  }

  return result
}

function buildFormatter(schema: Schema) {
  const fieldById = Object.fromEntries(
    schema.fields.map(f => [f.id, f])
  )

  return function formatter(raw: any) {
    const ctx: any = { ...raw }

    for (const op of schema.operations) {
      if (op.op === 'compose' && op.mode === 'bitwise') {
        ctx[op.id] = composeBitwise(
          op.inputs,
          ctx,
          fieldById,
          op.width,
          op.signed
        )
      }
    }

    const result: any = {}
    for (const key of schema.output) {
      result[key] = ctx[key]
    }

    return result
  }
}

function buildParser(schema: Schema): Parser {
  let parser = new Parser()

  for (const field of schema.fields) {
    parser = (parser as...