@indutny/protopiler 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +51 -0
- package/bin/cli.mjs +56 -0
- package/lib/__snapshots__/compiler.test.mjs.snap +159 -0
- package/lib/compiler.mjs +794 -0
- package/lib/constants.mjs +78 -0
- package/lib/decoder.mjs +432 -0
- package/lib/encoder.mjs +570 -0
- package/lib/index.mjs +3 -0
- package/lib/parser.mjs +1897 -0
- package/lib/utf8.mjs +206 -0
- package/package.json +44 -0
package/lib/encoder.mjs
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TYPE_VARINT,
|
|
3
|
+
TYPE_I64,
|
|
4
|
+
TYPE_LEN,
|
|
5
|
+
TYPE_I32,
|
|
6
|
+
FIELD_UNKNOWN,
|
|
7
|
+
FIELD_SIZE_UNKNOWN,
|
|
8
|
+
FIELD_SIZE_32,
|
|
9
|
+
FIELD_SIZE_64,
|
|
10
|
+
FIELD_SIZE_FIXED_32,
|
|
11
|
+
FIELD_SIZE_FIXED_64,
|
|
12
|
+
FIELD_SIZE_MASK,
|
|
13
|
+
FIELD_ENC_SIGNED,
|
|
14
|
+
FIELD_ENC_UNSIGNED,
|
|
15
|
+
FIELD_ENC_RSIGNED,
|
|
16
|
+
FIELD_ENC_BOOL,
|
|
17
|
+
FIELD_ENC_IEEE754,
|
|
18
|
+
FIELD_ENC_BYTES,
|
|
19
|
+
FIELD_ENC_MESSAGE,
|
|
20
|
+
FIELD_ENC_STRING,
|
|
21
|
+
FIELD_ENC_MASK,
|
|
22
|
+
FIELD_FLAG_PACKED,
|
|
23
|
+
} from './constants.mjs';
|
|
24
|
+
import { stringByteLength, encodeStringInto } from './utf8.mjs';
|
|
25
|
+
|
|
26
|
+
export const ERR_VARINT_INVALID_ENCODING = 'Unexpected varint encoding';
|
|
27
|
+
export const ERR_UNEXPECTED_SIZE = 'Unexpected field size';
|
|
28
|
+
export const ERR_UNEXPECTED_ENCODING = 'Unexpected field encoding';
|
|
29
|
+
export const ERR_INVALID_OUTPUT_LEN = 'Invalid length of produced output';
|
|
30
|
+
|
|
31
|
+
export const FIELD_ID = 'i';
|
|
32
|
+
export const FIELD_TYPE = 't';
|
|
33
|
+
export const FIELD_VALUE = 'v';
|
|
34
|
+
export const FIELD_BYTE_LENGTH = 'b';
|
|
35
|
+
|
|
36
|
+
// This is faster than naive branched version by 15%
|
|
37
|
+
function intByteLength(value) {
|
|
38
|
+
if (value === 0) {
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
return 5 - (((Math.clz32(value) + 3) / 7) | 0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function bigintByteLength(raw) {
|
|
45
|
+
const value = BigInt.asUintN(64, raw);
|
|
46
|
+
if (value < 0x80n) {
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
if (value < 0x4000n) {
|
|
50
|
+
return 2;
|
|
51
|
+
}
|
|
52
|
+
if (value < 0x200000n) {
|
|
53
|
+
return 3;
|
|
54
|
+
}
|
|
55
|
+
if (value < 0x10000000n) {
|
|
56
|
+
return 4;
|
|
57
|
+
}
|
|
58
|
+
if (value < 0x800000000n) {
|
|
59
|
+
return 5;
|
|
60
|
+
}
|
|
61
|
+
if (value < 0x40000000000n) {
|
|
62
|
+
return 6;
|
|
63
|
+
}
|
|
64
|
+
if (value < 0x2000000000000n) {
|
|
65
|
+
return 7;
|
|
66
|
+
}
|
|
67
|
+
if (value < 0x100000000000000n) {
|
|
68
|
+
return 8;
|
|
69
|
+
}
|
|
70
|
+
if (value < 0x8000000000000000n) {
|
|
71
|
+
return 9;
|
|
72
|
+
}
|
|
73
|
+
return 10;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function byteLength(fields) {
|
|
77
|
+
let size = 0;
|
|
78
|
+
for (const f of fields) {
|
|
79
|
+
const { i: id, t: field, v: value } = f;
|
|
80
|
+
|
|
81
|
+
// Unknown field
|
|
82
|
+
if (field === FIELD_UNKNOWN) {
|
|
83
|
+
size += value.length;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Known field
|
|
88
|
+
size += intByteLength(id << 3);
|
|
89
|
+
|
|
90
|
+
// Packed fields
|
|
91
|
+
if ((field & FIELD_FLAG_PACKED) !== 0) {
|
|
92
|
+
let len = 0;
|
|
93
|
+
for (const elem of value) {
|
|
94
|
+
switch (field & FIELD_SIZE_MASK) {
|
|
95
|
+
case FIELD_SIZE_32: {
|
|
96
|
+
switch (field & FIELD_ENC_MASK) {
|
|
97
|
+
case FIELD_ENC_SIGNED:
|
|
98
|
+
case FIELD_ENC_UNSIGNED:
|
|
99
|
+
len += intByteLength(elem);
|
|
100
|
+
break;
|
|
101
|
+
case FIELD_ENC_BOOL:
|
|
102
|
+
len += intByteLength(elem ? 1 : 0);
|
|
103
|
+
break;
|
|
104
|
+
case FIELD_ENC_RSIGNED:
|
|
105
|
+
len += intByteLength((elem << 1) ^ (elem >> 31));
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case FIELD_SIZE_64: {
|
|
113
|
+
switch (field & FIELD_ENC_MASK) {
|
|
114
|
+
case FIELD_ENC_SIGNED:
|
|
115
|
+
case FIELD_ENC_UNSIGNED:
|
|
116
|
+
len += bigintByteLength(elem);
|
|
117
|
+
break;
|
|
118
|
+
case FIELD_ENC_RSIGNED:
|
|
119
|
+
len += bigintByteLength((elem << 1n) ^ (elem >> 63n));
|
|
120
|
+
break;
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case FIELD_SIZE_FIXED_32:
|
|
127
|
+
len += 4;
|
|
128
|
+
break;
|
|
129
|
+
case FIELD_SIZE_FIXED_64:
|
|
130
|
+
len += 8;
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
throw new Error(ERR_UNEXPECTED_SIZE);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
size += intByteLength(len) + len;
|
|
138
|
+
|
|
139
|
+
// Cache size for encoder
|
|
140
|
+
f.b = len;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
switch (field & FIELD_SIZE_MASK) {
|
|
145
|
+
case FIELD_SIZE_32: {
|
|
146
|
+
switch (field & FIELD_ENC_MASK) {
|
|
147
|
+
case FIELD_ENC_SIGNED:
|
|
148
|
+
case FIELD_ENC_UNSIGNED:
|
|
149
|
+
size += intByteLength(value);
|
|
150
|
+
break;
|
|
151
|
+
case FIELD_ENC_RSIGNED:
|
|
152
|
+
size += intByteLength((value << 1) ^ (value >> 31));
|
|
153
|
+
break;
|
|
154
|
+
case FIELD_ENC_BOOL:
|
|
155
|
+
size += intByteLength(value ? 1 : 0);
|
|
156
|
+
break;
|
|
157
|
+
default:
|
|
158
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case FIELD_SIZE_64: {
|
|
163
|
+
switch (field & FIELD_ENC_MASK) {
|
|
164
|
+
case FIELD_ENC_SIGNED:
|
|
165
|
+
case FIELD_ENC_UNSIGNED:
|
|
166
|
+
size += bigintByteLength(value);
|
|
167
|
+
break;
|
|
168
|
+
case FIELD_ENC_RSIGNED:
|
|
169
|
+
size += bigintByteLength((value << 1n) ^ (value >> 63n));
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case FIELD_SIZE_FIXED_32:
|
|
177
|
+
size += 4;
|
|
178
|
+
break;
|
|
179
|
+
case FIELD_SIZE_FIXED_64:
|
|
180
|
+
size += 8;
|
|
181
|
+
break;
|
|
182
|
+
case FIELD_SIZE_UNKNOWN:
|
|
183
|
+
switch (field & FIELD_ENC_MASK) {
|
|
184
|
+
case FIELD_ENC_BYTES:
|
|
185
|
+
size += intByteLength(value.length) + value.length;
|
|
186
|
+
break;
|
|
187
|
+
case FIELD_ENC_STRING: {
|
|
188
|
+
const len = stringByteLength(value);
|
|
189
|
+
size += intByteLength(len) + len;
|
|
190
|
+
|
|
191
|
+
// Cache size for encoder
|
|
192
|
+
f.b = len;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
case FIELD_ENC_MESSAGE: {
|
|
196
|
+
const len = byteLength(value);
|
|
197
|
+
size += intByteLength(len) + len;
|
|
198
|
+
|
|
199
|
+
// Cache size for encoder
|
|
200
|
+
f.b = len;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
default:
|
|
208
|
+
throw new Error(ERR_UNEXPECTED_SIZE);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return size;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function encode(fields) {
|
|
215
|
+
const size = byteLength(fields);
|
|
216
|
+
const result =
|
|
217
|
+
typeof Buffer === 'function'
|
|
218
|
+
? // eslint-disable-next-line no-undef
|
|
219
|
+
Buffer.allocUnsafe(size)
|
|
220
|
+
: new Uint8Array(size);
|
|
221
|
+
|
|
222
|
+
const end = encodeInner(fields, result, 0);
|
|
223
|
+
if (end !== size) {
|
|
224
|
+
throw new Error(ERR_INVALID_OUTPUT_LEN);
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function encodeUInt32(raw, data, start) {
|
|
230
|
+
const value = raw >>> 0;
|
|
231
|
+
let offset = start;
|
|
232
|
+
|
|
233
|
+
if (value < 0x80) {
|
|
234
|
+
data[offset++] = value;
|
|
235
|
+
} else if (value < 0x4000) {
|
|
236
|
+
data[offset++] = 0x80 | (value & 0x7f);
|
|
237
|
+
data[offset++] = value >>> 7;
|
|
238
|
+
} else if (value < 0x200000) {
|
|
239
|
+
data[offset++] = 0x80 | (value & 0x7f);
|
|
240
|
+
data[offset++] = 0x80 | ((value >>> 7) & 0x7f);
|
|
241
|
+
data[offset++] = value >>> 14;
|
|
242
|
+
} else if (value < 0x10000000) {
|
|
243
|
+
data[offset++] = 0x80 | (value & 0x7f);
|
|
244
|
+
data[offset++] = 0x80 | ((value >>> 7) & 0x7f);
|
|
245
|
+
data[offset++] = 0x80 | ((value >>> 14) & 0x7f);
|
|
246
|
+
data[offset++] = value >>> 21;
|
|
247
|
+
} else {
|
|
248
|
+
data[offset++] = 0x80 | (value & 0x7f);
|
|
249
|
+
data[offset++] = 0x80 | ((value >>> 7) & 0x7f);
|
|
250
|
+
data[offset++] = 0x80 | ((value >>> 14) & 0x7f);
|
|
251
|
+
data[offset++] = 0x80 | ((value >>> 21) & 0x7f);
|
|
252
|
+
data[offset++] = value >>> 28;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return offset;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function encodeUInt64(value, data, start) {
|
|
259
|
+
let offset = start;
|
|
260
|
+
|
|
261
|
+
const low = Number(BigInt.asUintN(32, value));
|
|
262
|
+
const high = Number(BigInt.asUintN(32, value >> 32n));
|
|
263
|
+
|
|
264
|
+
if (high === 0) {
|
|
265
|
+
return encodeUInt32(low, data, offset);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
data[offset++] = 0x80 | (low & 0x7f);
|
|
269
|
+
data[offset++] = 0x80 | ((low >>> 7) & 0x7f);
|
|
270
|
+
data[offset++] = 0x80 | ((low >>> 14) & 0x7f);
|
|
271
|
+
data[offset++] = 0x80 | ((low >>> 21) & 0x7f);
|
|
272
|
+
|
|
273
|
+
if (high < 0x08) {
|
|
274
|
+
data[offset++] = (high << 4) | (low >>> 28);
|
|
275
|
+
} else if (high < 0x400) {
|
|
276
|
+
data[offset++] = 0x80 | ((high << 4) & 0x7f) | (low >>> 28);
|
|
277
|
+
data[offset++] = high >>> 3;
|
|
278
|
+
} else if (high < 0x20000) {
|
|
279
|
+
data[offset++] = 0x80 | ((high << 4) & 0x7f) | (low >>> 28);
|
|
280
|
+
data[offset++] = 0x80 | ((high >>> 3) & 0x7f);
|
|
281
|
+
data[offset++] = high >>> 10;
|
|
282
|
+
} else if (high < 0x1000000) {
|
|
283
|
+
data[offset++] = 0x80 | ((high << 4) & 0x7f) | (low >>> 28);
|
|
284
|
+
data[offset++] = 0x80 | ((high >>> 3) & 0x7f);
|
|
285
|
+
data[offset++] = 0x80 | ((high >>> 10) & 0x7f);
|
|
286
|
+
data[offset++] = high >>> 17;
|
|
287
|
+
} else if (high < 0x80000000) {
|
|
288
|
+
data[offset++] = 0x80 | ((high << 4) & 0x7f) | (low >>> 28);
|
|
289
|
+
data[offset++] = 0x80 | ((high >>> 3) & 0x7f);
|
|
290
|
+
data[offset++] = 0x80 | ((high >>> 10) & 0x7f);
|
|
291
|
+
data[offset++] = 0x80 | ((high >>> 17) & 0x7f);
|
|
292
|
+
data[offset++] = high >>> 24;
|
|
293
|
+
} else {
|
|
294
|
+
data[offset++] = 0x80 | ((high << 4) & 0x7f) | (low >>> 28);
|
|
295
|
+
data[offset++] = 0x80 | ((high >>> 3) & 0x7f);
|
|
296
|
+
data[offset++] = 0x80 | ((high >>> 10) & 0x7f);
|
|
297
|
+
data[offset++] = 0x80 | ((high >>> 17) & 0x7f);
|
|
298
|
+
data[offset++] = 0x80 | ((high >>> 24) & 0x7f);
|
|
299
|
+
data[offset++] = high >>> 31;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return offset;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const nativeUTF8 = new TextEncoder();
|
|
306
|
+
|
|
307
|
+
// Rough value based on benchmarks. Below this cost of calling into C++ is
|
|
308
|
+
// higher than decoding the string in JS.
|
|
309
|
+
const NATIVE_UTF8_THRESHOLD = 48;
|
|
310
|
+
|
|
311
|
+
function encodeInner(fields, data, start) {
|
|
312
|
+
let offset = start;
|
|
313
|
+
for (const f of fields) {
|
|
314
|
+
const { i: id, t: field, v: value } = f;
|
|
315
|
+
|
|
316
|
+
// Unknown field
|
|
317
|
+
if (field === FIELD_UNKNOWN) {
|
|
318
|
+
data.set(value, offset);
|
|
319
|
+
offset += value.length;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Known field
|
|
324
|
+
|
|
325
|
+
// Packed fields
|
|
326
|
+
// Note: this duplicates a lot of code above, but only because V8
|
|
327
|
+
// refuses inlining it if moved to a separate function.
|
|
328
|
+
if ((field & FIELD_FLAG_PACKED) !== 0) {
|
|
329
|
+
// Encode LEN tag
|
|
330
|
+
offset = encodeUInt32((id << 3) | TYPE_LEN, data, offset);
|
|
331
|
+
|
|
332
|
+
// Encode length
|
|
333
|
+
offset = encodeUInt32(f.b, data, offset);
|
|
334
|
+
|
|
335
|
+
for (const elem of value) {
|
|
336
|
+
switch (field & FIELD_SIZE_MASK) {
|
|
337
|
+
case FIELD_SIZE_32:
|
|
338
|
+
switch (field & FIELD_ENC_MASK) {
|
|
339
|
+
case FIELD_ENC_SIGNED:
|
|
340
|
+
case FIELD_ENC_UNSIGNED:
|
|
341
|
+
offset = encodeUInt32(elem, data, offset);
|
|
342
|
+
break;
|
|
343
|
+
case FIELD_ENC_BOOL:
|
|
344
|
+
offset = encodeUInt32(elem ? 1 : 0, data, offset);
|
|
345
|
+
break;
|
|
346
|
+
case FIELD_ENC_RSIGNED:
|
|
347
|
+
offset = encodeUInt32((elem << 1) ^ (elem >> 31), data, offset);
|
|
348
|
+
break;
|
|
349
|
+
default:
|
|
350
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
351
|
+
}
|
|
352
|
+
break;
|
|
353
|
+
case FIELD_SIZE_64: {
|
|
354
|
+
switch (field & FIELD_ENC_MASK) {
|
|
355
|
+
case FIELD_ENC_SIGNED:
|
|
356
|
+
case FIELD_ENC_UNSIGNED:
|
|
357
|
+
offset = encodeUInt64(elem, data, offset);
|
|
358
|
+
break;
|
|
359
|
+
case FIELD_ENC_RSIGNED: {
|
|
360
|
+
offset = encodeUInt64(
|
|
361
|
+
(elem << 1n) ^ (elem >> 63n),
|
|
362
|
+
data,
|
|
363
|
+
offset
|
|
364
|
+
);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
default:
|
|
368
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
case FIELD_SIZE_FIXED_32:
|
|
373
|
+
switch (field & FIELD_ENC_MASK) {
|
|
374
|
+
case FIELD_ENC_UNSIGNED:
|
|
375
|
+
case FIELD_ENC_SIGNED:
|
|
376
|
+
data[offset++] = elem & 0xff;
|
|
377
|
+
data[offset++] = (elem >>> 8) & 0xff;
|
|
378
|
+
data[offset++] = (elem >>> 16) & 0xff;
|
|
379
|
+
data[offset++] = (elem >>> 24) & 0xff;
|
|
380
|
+
break;
|
|
381
|
+
case FIELD_ENC_IEEE754:
|
|
382
|
+
new DataView(
|
|
383
|
+
data.buffer,
|
|
384
|
+
data.byteOffset + offset,
|
|
385
|
+
4
|
|
386
|
+
).setFloat32(0, elem, true);
|
|
387
|
+
offset += 4;
|
|
388
|
+
break;
|
|
389
|
+
default:
|
|
390
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
391
|
+
}
|
|
392
|
+
break;
|
|
393
|
+
case FIELD_SIZE_FIXED_64:
|
|
394
|
+
switch (field & FIELD_ENC_MASK) {
|
|
395
|
+
case FIELD_ENC_UNSIGNED:
|
|
396
|
+
case FIELD_ENC_SIGNED: {
|
|
397
|
+
const low = Number(BigInt.asUintN(32, elem));
|
|
398
|
+
const high = Number(BigInt.asUintN(32, elem >> 32n));
|
|
399
|
+
|
|
400
|
+
data[offset++] = low & 0xff;
|
|
401
|
+
data[offset++] = (low >>> 8) & 0xff;
|
|
402
|
+
data[offset++] = (low >>> 16) & 0xff;
|
|
403
|
+
data[offset++] = (low >>> 24) & 0xff;
|
|
404
|
+
data[offset++] = high & 0xff;
|
|
405
|
+
data[offset++] = (high >>> 8) & 0xff;
|
|
406
|
+
data[offset++] = (high >>> 16) & 0xff;
|
|
407
|
+
data[offset++] = (high >>> 24) & 0xff;
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
case FIELD_ENC_IEEE754:
|
|
411
|
+
new DataView(
|
|
412
|
+
data.buffer,
|
|
413
|
+
data.byteOffset + offset,
|
|
414
|
+
8
|
|
415
|
+
).setFloat64(0, elem, true);
|
|
416
|
+
offset += 8;
|
|
417
|
+
break;
|
|
418
|
+
default:
|
|
419
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
default:
|
|
423
|
+
throw new Error(ERR_UNEXPECTED_SIZE);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
let type;
|
|
430
|
+
switch (field & FIELD_SIZE_MASK) {
|
|
431
|
+
case FIELD_SIZE_32:
|
|
432
|
+
case FIELD_SIZE_64:
|
|
433
|
+
type = TYPE_VARINT;
|
|
434
|
+
break;
|
|
435
|
+
case FIELD_SIZE_FIXED_32:
|
|
436
|
+
type = TYPE_I32;
|
|
437
|
+
break;
|
|
438
|
+
case FIELD_SIZE_FIXED_64:
|
|
439
|
+
type = TYPE_I64;
|
|
440
|
+
break;
|
|
441
|
+
case FIELD_SIZE_UNKNOWN:
|
|
442
|
+
type = TYPE_LEN;
|
|
443
|
+
break;
|
|
444
|
+
default:
|
|
445
|
+
throw new Error(ERR_UNEXPECTED_SIZE);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Encode tag
|
|
449
|
+
offset = encodeUInt32((id << 3) | type, data, offset);
|
|
450
|
+
|
|
451
|
+
// Encode value
|
|
452
|
+
switch (field & FIELD_SIZE_MASK) {
|
|
453
|
+
case FIELD_SIZE_32:
|
|
454
|
+
switch (field & FIELD_ENC_MASK) {
|
|
455
|
+
case FIELD_ENC_SIGNED:
|
|
456
|
+
case FIELD_ENC_UNSIGNED:
|
|
457
|
+
offset = encodeUInt32(value, data, offset);
|
|
458
|
+
break;
|
|
459
|
+
case FIELD_ENC_RSIGNED:
|
|
460
|
+
offset = encodeUInt32((value << 1) ^ (value >> 31), data, offset);
|
|
461
|
+
break;
|
|
462
|
+
case FIELD_ENC_BOOL:
|
|
463
|
+
offset = encodeUInt32(value ? 1 : 0, data, offset);
|
|
464
|
+
break;
|
|
465
|
+
default:
|
|
466
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
467
|
+
}
|
|
468
|
+
break;
|
|
469
|
+
case FIELD_SIZE_64: {
|
|
470
|
+
switch (field & FIELD_ENC_MASK) {
|
|
471
|
+
case FIELD_ENC_SIGNED:
|
|
472
|
+
case FIELD_ENC_UNSIGNED:
|
|
473
|
+
offset = encodeUInt64(value, data, offset);
|
|
474
|
+
break;
|
|
475
|
+
case FIELD_ENC_RSIGNED: {
|
|
476
|
+
offset = encodeUInt64((value << 1n) ^ (value >> 63n), data, offset);
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
default:
|
|
480
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
481
|
+
}
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
case FIELD_SIZE_FIXED_32:
|
|
485
|
+
switch (field & FIELD_ENC_MASK) {
|
|
486
|
+
case FIELD_ENC_UNSIGNED:
|
|
487
|
+
case FIELD_ENC_SIGNED:
|
|
488
|
+
data[offset++] = value & 0xff;
|
|
489
|
+
data[offset++] = (value >>> 8) & 0xff;
|
|
490
|
+
data[offset++] = (value >>> 16) & 0xff;
|
|
491
|
+
data[offset++] = (value >>> 24) & 0xff;
|
|
492
|
+
break;
|
|
493
|
+
case FIELD_ENC_IEEE754:
|
|
494
|
+
new DataView(data.buffer, data.byteOffset + offset, 4).setFloat32(
|
|
495
|
+
0,
|
|
496
|
+
value,
|
|
497
|
+
true
|
|
498
|
+
);
|
|
499
|
+
offset += 4;
|
|
500
|
+
break;
|
|
501
|
+
default:
|
|
502
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
503
|
+
}
|
|
504
|
+
break;
|
|
505
|
+
case FIELD_SIZE_FIXED_64:
|
|
506
|
+
switch (field & FIELD_ENC_MASK) {
|
|
507
|
+
case FIELD_ENC_UNSIGNED:
|
|
508
|
+
case FIELD_ENC_SIGNED: {
|
|
509
|
+
const low = Number(BigInt.asUintN(32, value));
|
|
510
|
+
const high = Number(BigInt.asUintN(32, value >> 32n));
|
|
511
|
+
|
|
512
|
+
data[offset++] = low & 0xff;
|
|
513
|
+
data[offset++] = (low >>> 8) & 0xff;
|
|
514
|
+
data[offset++] = (low >>> 16) & 0xff;
|
|
515
|
+
data[offset++] = (low >>> 24) & 0xff;
|
|
516
|
+
data[offset++] = high & 0xff;
|
|
517
|
+
data[offset++] = (high >>> 8) & 0xff;
|
|
518
|
+
data[offset++] = (high >>> 16) & 0xff;
|
|
519
|
+
data[offset++] = (high >>> 24) & 0xff;
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
case FIELD_ENC_IEEE754:
|
|
523
|
+
new DataView(data.buffer, data.byteOffset + offset, 8).setFloat64(
|
|
524
|
+
0,
|
|
525
|
+
value,
|
|
526
|
+
true
|
|
527
|
+
);
|
|
528
|
+
offset += 8;
|
|
529
|
+
break;
|
|
530
|
+
default:
|
|
531
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
532
|
+
}
|
|
533
|
+
break;
|
|
534
|
+
case FIELD_SIZE_UNKNOWN:
|
|
535
|
+
switch (field & FIELD_ENC_MASK) {
|
|
536
|
+
case FIELD_ENC_BYTES:
|
|
537
|
+
offset = encodeUInt32(value.length, data, offset);
|
|
538
|
+
data.set(value, offset);
|
|
539
|
+
offset += value.length;
|
|
540
|
+
break;
|
|
541
|
+
case FIELD_ENC_STRING: {
|
|
542
|
+
const len = f.b;
|
|
543
|
+
offset = encodeUInt32(len, data, offset);
|
|
544
|
+
if ('write' in data) {
|
|
545
|
+
// Buffer
|
|
546
|
+
data.write(value, offset, len);
|
|
547
|
+
offset += len;
|
|
548
|
+
} else if (len <= NATIVE_UTF8_THRESHOLD) {
|
|
549
|
+
offset = encodeStringInto(value, data, offset);
|
|
550
|
+
} else {
|
|
551
|
+
nativeUTF8.encodeInto(value, data.subarray(offset, offset + len));
|
|
552
|
+
offset += len;
|
|
553
|
+
}
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case FIELD_ENC_MESSAGE: {
|
|
557
|
+
offset = encodeUInt32(f.b, data, offset);
|
|
558
|
+
offset = encodeInner(value, data, offset);
|
|
559
|
+
break;
|
|
560
|
+
}
|
|
561
|
+
default:
|
|
562
|
+
throw new Error(ERR_UNEXPECTED_ENCODING);
|
|
563
|
+
}
|
|
564
|
+
break;
|
|
565
|
+
default:
|
|
566
|
+
throw new Error(ERR_UNEXPECTED_SIZE);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return offset;
|
|
570
|
+
}
|
package/lib/index.mjs
ADDED