readVarInt function

VarIntReadResult? readVarInt(
  1. Uint8List array,
  2. int offset
)

Reads a QUIC Variable-Length Integer from a byte array starting at a given offset.

Returns a VarIntReadResult containing the decoded value and its byte length, or null if the buffer is too short.

Implementation

VarIntReadResult? readVarInt(Uint8List array, int offset) {
  if (offset >= array.length) return null;

  final first = array[offset];
  final prefix = first >> 6;

  // 1-byte encoding (00xxxxxx)
  if (prefix == 0) {
    return VarIntReadResult(
      value: first & 0x3f, // Mask the two prefix bits
      byteLength: 1,
    );
  }

  // 2-byte encoding (01xxxxxx)
  if (prefix == 0x01) {
    if (offset + 1 >= array.length) return null;

    // value = (01xxxxxx & 0x3f) << 8 | array[offset + 1]
    final value = ((first & 0x3f) << 8) | array[offset + 1];
    return VarIntReadResult(value: value, byteLength: 2);
  }

  // 4-byte encoding (10xxxxxx)
  if (prefix == 0x02) {
    if (offset + 3 >= array.length) return null;

    final value =
        ((first & 0x3F) << 24) |
        (array[offset + 1] << 16) |
        (array[offset + 2] << 8) |
        array[offset + 3];

    // Dart's `int` is 64-bit and handles the result directly.
    return VarIntReadResult(value: value, byteLength: 4);
  }

  // 8-byte encoding (11xxxxxx)
  if (prefix == 0x03) {
    if (offset + 7 >= array.length) return null;

    // In Dart, we can construct the full 62-bit value directly into a 64-bit `int`.
    // value = (11xxxxxx & 0x3F) << 56 | B1 << 48 | ... | B7
    int value = (first & 0x3F) << 56;
    value |= array[offset + 1] << 48;
    value |= array[offset + 2] << 40;
    value |= array[offset + 3] << 32;
    value |= array[offset + 4] << 24;
    value |= array[offset + 5] << 16;
    value |= array[offset + 6] << 8;
    value |= array[offset + 7];

    return VarIntReadResult(value: value, byteLength: 8);
  }

  // Should be unreachable given the 2-bit prefix logic, but included for completeness
  return null;
}