Spaces:
Sleeping
Sleeping
File size: 4,531 Bytes
f6266b9 | 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /**
* Protobuf wire format codec β zero-dependency, schema-less.
*
* Wire types:
* 0 = Varint (int32, uint64, bool, enum)
* 1 = Fixed64 (double, fixed64)
* 2 = LenDelim (string, bytes, embedded messages)
* 5 = Fixed32 (float, fixed32)
*/
// βββ Varint ββββββββββββββββββββββββββββββββββββββββββββββββ
export function encodeVarint(value) {
const bytes = [];
let v = Number(value);
if (v < 0) {
const big = BigInt(v) & 0xFFFFFFFFFFFFFFFFn;
let b = big;
for (let i = 0; i < 10; i++) {
bytes.push(Number(b & 0x7Fn) | (i < 9 ? 0x80 : 0));
b >>= 7n;
}
return Buffer.from(bytes);
}
do {
let byte = v & 0x7F;
v >>>= 7;
if (v > 0) byte |= 0x80;
bytes.push(byte);
} while (v > 0);
return Buffer.from(bytes);
}
export function decodeVarint(buf, offset = 0) {
let result = 0, shift = 0, pos = offset;
while (pos < buf.length) {
const byte = buf[pos++];
result |= (byte & 0x7F) << shift;
if (!(byte & 0x80)) break;
shift += 7;
if (shift >= 64) throw new Error('Varint overflow');
}
return { value: result >>> 0, length: pos - offset };
}
// βββ Field-level writers (standalone functions) ββββββββββββ
function makeTag(field, wireType) {
return encodeVarint((field << 3) | wireType);
}
/** Write a varint field (wire type 0). */
export function writeVarintField(field, value) {
return Buffer.concat([makeTag(field, 0), encodeVarint(value)]);
}
/** Write a length-delimited string field (wire type 2). */
export function writeStringField(field, str) {
if (!str && str !== '') return Buffer.alloc(0);
const data = Buffer.from(str, 'utf-8');
return Buffer.concat([makeTag(field, 2), encodeVarint(data.length), data]);
}
/** Write a length-delimited bytes field (wire type 2). */
export function writeBytesField(field, data) {
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
return Buffer.concat([makeTag(field, 2), encodeVarint(buf.length), buf]);
}
/** Write an embedded message field (wire type 2). */
export function writeMessageField(field, msgBuf) {
if (!msgBuf || msgBuf.length === 0) return Buffer.alloc(0);
return Buffer.concat([makeTag(field, 2), encodeVarint(msgBuf.length), msgBuf]);
}
/** Write a fixed64 field (wire type 1). */
export function writeFixed64Field(field, buf8) {
return Buffer.concat([makeTag(field, 1), buf8]);
}
/** Write a bool field (wire type 0), only if true. */
export function writeBoolField(field, value) {
if (!value) return Buffer.alloc(0);
return writeVarintField(field, 1);
}
// βββ Parser ββββββββββββββββββββββββββββββββββββββββββββββββ
/**
* Parse a protobuf buffer into an array of { field, wireType, value }.
* For varint (0): value is a Number.
* For lendelim (2): value is a Buffer (caller decides string vs message).
* For fixed64 (1): value is an 8-byte Buffer.
* For fixed32 (5): value is a 4-byte Buffer.
*/
export function parseFields(buf) {
const fields = [];
let pos = 0;
while (pos < buf.length) {
const tag = decodeVarint(buf, pos);
pos += tag.length;
const fieldNum = tag.value >>> 3;
const wireType = tag.value & 0x07;
let value;
switch (wireType) {
case 0: { // varint
const v = decodeVarint(buf, pos);
pos += v.length;
value = v.value;
break;
}
case 1: { // fixed64
value = buf.subarray(pos, pos + 8);
pos += 8;
break;
}
case 2: { // length-delimited
const len = decodeVarint(buf, pos);
pos += len.length;
value = buf.subarray(pos, pos + len.value);
pos += len.value;
break;
}
case 5: { // fixed32
value = buf.subarray(pos, pos + 4);
pos += 4;
break;
}
default:
throw new Error(`Unknown wire type ${wireType} at offset ${pos}`);
}
fields.push({ field: fieldNum, wireType, value });
}
return fields;
}
/** Get first field matching number and optional wire type. */
export function getField(fields, num, wireType) {
return fields.find(f => f.field === num && (wireType === undefined || f.wireType === wireType)) || null;
}
/** Get all fields matching number. */
export function getAllFields(fields, num) {
return fields.filter(f => f.field === num);
}
|