DeFiCh/jellyfish

View on GitHub
packages/jellyfish-buffer/src/CompactSize.ts

Summary

Maintainability
A
25 mins
Test Coverage
import { SmartBuffer } from 'smart-buffer'

/**
 * @param {number} num to write as VarUInt (1-9 bytes)
 * @param {SmartBuffer} buffer to write to
 */
export function writeCompactSize (num: number, buffer: SmartBuffer): void {
  validateUInt53(num)

  // 8 bit (1 byte)
  if (num < 0xfd) {
    buffer.writeUInt8(num)
    return
  }

  // 16 bit (1 + 2 bytes)
  if (num <= 0xffff) {
    buffer.writeUInt8(0xfd)
    buffer.writeUInt16LE(num)
    return
  }

  // 32 bit (1 + 4 bytes)
  if (num <= 0xffffffff) {
    buffer.writeUInt8(0xfe)
    buffer.writeUInt32LE(num)
    return
  }

  // 64 bit (1 + 8 bytes)
  buffer.writeUInt8(0xff)
  buffer.writeUInt32LE(num >>> 0)
  buffer.writeUInt32LE((num / 0x100000000) | 0)
}

/**
 * Read VarUInt as number
 * @param {SmartBuffer} buffer to read VarUInt from (1-9 bytes)
 * @throws RangeError 'out of Number.MAX_SAFE_INTEGER range' when it's out of MAX_SAFE_INTEGER
 */
export function readCompactSize (buffer: SmartBuffer): number {
  const first = buffer.readUInt8()
  switch (first) {
    case 0xfd: // 16 bit (1 + 2 bytes)
      return buffer.readUInt16LE()
    case 0xfe: // 32 bit (1 + 4 bytes)
      return buffer.readUInt32LE()
    case 0xff: { // 64 bit (1 + 8 bytes)
      const lo = buffer.readUInt32LE()
      const hi = buffer.readUInt32LE()
      const num = (hi * 0x0100000000) + lo
      validateUInt53(num)
      return num
    }
    default: // 8 bit (1 byte)
      return first
  }
}

/**
 * @param {number} num to get total number bytes (1-9 bytes)
 */
export function byteLength (num: number): number {
  validateUInt53(num)
  return num < 0xfd ? 1 : num <= 0xffff ? 3 : num <= 0xffffffff ? 5 : 9
}

/**
 * @param {number} num to validate
 * @throws RangeError 'out of Number.MAX_SAFE_INTEGER range' when it's out of MAX_SAFE_INTEGER
 */
function validateUInt53 (num: number): void {
  if (num < 0 || num > Number.MAX_SAFE_INTEGER || num % 1 !== 0) {
    throw new RangeError('out of Number.MAX_SAFE_INTEGER range')
  }
}