source: imaps-frontend/node_modules/webpack/lib/serialization/BinaryMiddleware.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 30.9 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7const memoize = require("../util/memoize");
8const SerializerMiddleware = require("./SerializerMiddleware");
9
10/** @typedef {import("./types").BufferSerializableType} BufferSerializableType */
11/** @typedef {import("./types").PrimitiveSerializableType} PrimitiveSerializableType */
12
13/*
14Format:
15
16File -> Section*
17
18Section -> NullsSection |
19 BooleansSection |
20 F64NumbersSection |
21 I32NumbersSection |
22 I8NumbersSection |
23 ShortStringSection |
24 BigIntSection |
25 I32BigIntSection |
26 I8BigIntSection
27 StringSection |
28 BufferSection |
29 NopSection
30
31
32
33NullsSection ->
34 NullHeaderByte | Null2HeaderByte | Null3HeaderByte |
35 Nulls8HeaderByte 0xnn (n:count - 4) |
36 Nulls32HeaderByte n:ui32 (n:count - 260) |
37BooleansSection -> TrueHeaderByte | FalseHeaderByte | BooleansSectionHeaderByte BooleansCountAndBitsByte
38F64NumbersSection -> F64NumbersSectionHeaderByte f64*
39I32NumbersSection -> I32NumbersSectionHeaderByte i32*
40I8NumbersSection -> I8NumbersSectionHeaderByte i8*
41ShortStringSection -> ShortStringSectionHeaderByte ascii-byte*
42StringSection -> StringSectionHeaderByte i32:length utf8-byte*
43BufferSection -> BufferSectionHeaderByte i32:length byte*
44NopSection --> NopSectionHeaderByte
45BigIntSection -> BigIntSectionHeaderByte i32:length ascii-byte*
46I32BigIntSection -> I32BigIntSectionHeaderByte i32
47I8BigIntSection -> I8BigIntSectionHeaderByte i8
48
49ShortStringSectionHeaderByte -> 0b1nnn_nnnn (n:length)
50
51F64NumbersSectionHeaderByte -> 0b001n_nnnn (n:count - 1)
52I32NumbersSectionHeaderByte -> 0b010n_nnnn (n:count - 1)
53I8NumbersSectionHeaderByte -> 0b011n_nnnn (n:count - 1)
54
55NullsSectionHeaderByte -> 0b0001_nnnn (n:count - 1)
56BooleansCountAndBitsByte ->
57 0b0000_1xxx (count = 3) |
58 0b0001_xxxx (count = 4) |
59 0b001x_xxxx (count = 5) |
60 0b01xx_xxxx (count = 6) |
61 0b1nnn_nnnn (n:count - 7, 7 <= count <= 133)
62 0xff n:ui32 (n:count, 134 <= count < 2^32)
63
64StringSectionHeaderByte -> 0b0000_1110
65BufferSectionHeaderByte -> 0b0000_1111
66NopSectionHeaderByte -> 0b0000_1011
67BigIntSectionHeaderByte -> 0b0001_1010
68I32BigIntSectionHeaderByte -> 0b0001_1100
69I8BigIntSectionHeaderByte -> 0b0001_1011
70FalseHeaderByte -> 0b0000_1100
71TrueHeaderByte -> 0b0000_1101
72
73RawNumber -> n (n <= 10)
74
75*/
76
77const LAZY_HEADER = 0x0b;
78const TRUE_HEADER = 0x0c;
79const FALSE_HEADER = 0x0d;
80const BOOLEANS_HEADER = 0x0e;
81const NULL_HEADER = 0x10;
82const NULL2_HEADER = 0x11;
83const NULL3_HEADER = 0x12;
84const NULLS8_HEADER = 0x13;
85const NULLS32_HEADER = 0x14;
86const NULL_AND_I8_HEADER = 0x15;
87const NULL_AND_I32_HEADER = 0x16;
88const NULL_AND_TRUE_HEADER = 0x17;
89const NULL_AND_FALSE_HEADER = 0x18;
90const BIGINT_HEADER = 0x1a;
91const BIGINT_I8_HEADER = 0x1b;
92const BIGINT_I32_HEADER = 0x1c;
93const STRING_HEADER = 0x1e;
94const BUFFER_HEADER = 0x1f;
95const I8_HEADER = 0x60;
96const I32_HEADER = 0x40;
97const F64_HEADER = 0x20;
98const SHORT_STRING_HEADER = 0x80;
99
100/** Uplift high-order bits */
101const NUMBERS_HEADER_MASK = 0xe0; // 0b1010_0000
102const NUMBERS_COUNT_MASK = 0x1f; // 0b0001_1111
103const SHORT_STRING_LENGTH_MASK = 0x7f; // 0b0111_1111
104
105const HEADER_SIZE = 1;
106const I8_SIZE = 1;
107const I32_SIZE = 4;
108const F64_SIZE = 8;
109
110const MEASURE_START_OPERATION = Symbol("MEASURE_START_OPERATION");
111const MEASURE_END_OPERATION = Symbol("MEASURE_END_OPERATION");
112
113/** @typedef {typeof MEASURE_START_OPERATION} MEASURE_START_OPERATION_TYPE */
114/** @typedef {typeof MEASURE_END_OPERATION} MEASURE_END_OPERATION_TYPE */
115
116/**
117 * @param {number} n number
118 * @returns {0 | 1 | 2} type of number for serialization
119 */
120const identifyNumber = n => {
121 if (n === (n | 0)) {
122 if (n <= 127 && n >= -128) return 0;
123 if (n <= 2147483647 && n >= -2147483648) return 1;
124 }
125 return 2;
126};
127
128/**
129 * @param {bigint} n bigint
130 * @returns {0 | 1 | 2} type of bigint for serialization
131 */
132const identifyBigInt = n => {
133 if (n <= BigInt(127) && n >= BigInt(-128)) return 0;
134 if (n <= BigInt(2147483647) && n >= BigInt(-2147483648)) return 1;
135 return 2;
136};
137
138/** @typedef {TODO} Context */
139
140/**
141 * @typedef {PrimitiveSerializableType[]} DeserializedType
142 * @typedef {BufferSerializableType[]} SerializedType
143 * @extends {SerializerMiddleware<DeserializedType, SerializedType>}
144 */
145class BinaryMiddleware extends SerializerMiddleware {
146 /**
147 * @param {DeserializedType} data data
148 * @param {object} context context object
149 * @returns {SerializedType|Promise<SerializedType>} serialized data
150 */
151 serialize(data, context) {
152 return this._serialize(data, context);
153 }
154
155 /**
156 * @param {function(): Promise<any> | any} fn lazy function
157 * @param {TODO} context serialize function
158 * @returns {function(): Promise<any> | any} new lazy
159 */
160 _serializeLazy(fn, context) {
161 return SerializerMiddleware.serializeLazy(fn, data =>
162 this._serialize(data, context)
163 );
164 }
165
166 /**
167 * @param {DeserializedType} data data
168 * @param {TODO} context context object
169 * @param {{ leftOverBuffer: Buffer | null, allocationSize: number, increaseCounter: number }} allocationScope allocation scope
170 * @returns {SerializedType} serialized data
171 */
172 _serialize(
173 data,
174 context,
175 allocationScope = {
176 allocationSize: 1024,
177 increaseCounter: 0,
178 leftOverBuffer: null
179 }
180 ) {
181 /** @type {Buffer | null} */
182 let leftOverBuffer = null;
183 /** @type {BufferSerializableType[]} */
184 let buffers = [];
185 /** @type {Buffer | null} */
186 let currentBuffer = allocationScope ? allocationScope.leftOverBuffer : null;
187 allocationScope.leftOverBuffer = null;
188 let currentPosition = 0;
189 if (currentBuffer === null) {
190 currentBuffer = Buffer.allocUnsafe(allocationScope.allocationSize);
191 }
192 /**
193 * @param {number} bytesNeeded bytes needed
194 */
195 const allocate = bytesNeeded => {
196 if (currentBuffer !== null) {
197 if (currentBuffer.length - currentPosition >= bytesNeeded) return;
198 flush();
199 }
200 if (leftOverBuffer && leftOverBuffer.length >= bytesNeeded) {
201 currentBuffer = leftOverBuffer;
202 leftOverBuffer = null;
203 } else {
204 currentBuffer = Buffer.allocUnsafe(
205 Math.max(bytesNeeded, allocationScope.allocationSize)
206 );
207 if (
208 !(allocationScope.increaseCounter =
209 (allocationScope.increaseCounter + 1) % 4) &&
210 allocationScope.allocationSize < 16777216
211 ) {
212 allocationScope.allocationSize = allocationScope.allocationSize << 1;
213 }
214 }
215 };
216 const flush = () => {
217 if (currentBuffer !== null) {
218 if (currentPosition > 0) {
219 buffers.push(
220 Buffer.from(
221 currentBuffer.buffer,
222 currentBuffer.byteOffset,
223 currentPosition
224 )
225 );
226 }
227 if (
228 !leftOverBuffer ||
229 leftOverBuffer.length < currentBuffer.length - currentPosition
230 ) {
231 leftOverBuffer = Buffer.from(
232 currentBuffer.buffer,
233 currentBuffer.byteOffset + currentPosition,
234 currentBuffer.byteLength - currentPosition
235 );
236 }
237
238 currentBuffer = null;
239 currentPosition = 0;
240 }
241 };
242 /**
243 * @param {number} byte byte
244 */
245 const writeU8 = byte => {
246 /** @type {Buffer} */
247 (currentBuffer).writeUInt8(byte, currentPosition++);
248 };
249 /**
250 * @param {number} ui32 ui32
251 */
252 const writeU32 = ui32 => {
253 /** @type {Buffer} */
254 (currentBuffer).writeUInt32LE(ui32, currentPosition);
255 currentPosition += 4;
256 };
257 /** @type {number[]} */
258 const measureStack = [];
259 const measureStart = () => {
260 measureStack.push(buffers.length, currentPosition);
261 };
262 /**
263 * @returns {number} size
264 */
265 const measureEnd = () => {
266 const oldPos = /** @type {number} */ (measureStack.pop());
267 const buffersIndex = /** @type {number} */ (measureStack.pop());
268 let size = currentPosition - oldPos;
269 for (let i = buffersIndex; i < buffers.length; i++) {
270 size += buffers[i].length;
271 }
272 return size;
273 };
274 for (let i = 0; i < data.length; i++) {
275 const thing = data[i];
276 switch (typeof thing) {
277 case "function": {
278 if (!SerializerMiddleware.isLazy(thing))
279 throw new Error(`Unexpected function ${thing}`);
280 /** @type {SerializedType | (() => SerializedType)} */
281 let serializedData =
282 SerializerMiddleware.getLazySerializedValue(thing);
283 if (serializedData === undefined) {
284 if (SerializerMiddleware.isLazy(thing, this)) {
285 flush();
286 allocationScope.leftOverBuffer = leftOverBuffer;
287 const result =
288 /** @type {(Exclude<PrimitiveSerializableType, Promise<PrimitiveSerializableType>>)[]} */ (
289 thing()
290 );
291 const data = this._serialize(result, context, allocationScope);
292 leftOverBuffer = allocationScope.leftOverBuffer;
293 allocationScope.leftOverBuffer = null;
294 SerializerMiddleware.setLazySerializedValue(thing, data);
295 serializedData = data;
296 } else {
297 serializedData = this._serializeLazy(thing, context);
298 flush();
299 buffers.push(serializedData);
300 break;
301 }
302 } else if (typeof serializedData === "function") {
303 flush();
304 buffers.push(serializedData);
305 break;
306 }
307 /** @type {number[]} */
308 const lengths = [];
309 for (const item of serializedData) {
310 let last;
311 if (typeof item === "function") {
312 lengths.push(0);
313 } else if (item.length === 0) {
314 // ignore
315 } else if (
316 lengths.length > 0 &&
317 (last = lengths[lengths.length - 1]) !== 0
318 ) {
319 const remaining = 0xffffffff - last;
320 if (remaining >= item.length) {
321 lengths[lengths.length - 1] += item.length;
322 } else {
323 lengths.push(item.length - remaining);
324 lengths[lengths.length - 2] = 0xffffffff;
325 }
326 } else {
327 lengths.push(item.length);
328 }
329 }
330 allocate(5 + lengths.length * 4);
331 writeU8(LAZY_HEADER);
332 writeU32(lengths.length);
333 for (const l of lengths) {
334 writeU32(l);
335 }
336 flush();
337 for (const item of serializedData) {
338 buffers.push(item);
339 }
340 break;
341 }
342 case "string": {
343 const len = Buffer.byteLength(thing);
344 if (len >= 128 || len !== thing.length) {
345 allocate(len + HEADER_SIZE + I32_SIZE);
346 writeU8(STRING_HEADER);
347 writeU32(len);
348 currentBuffer.write(thing, currentPosition);
349 currentPosition += len;
350 } else if (len >= 70) {
351 allocate(len + HEADER_SIZE);
352 writeU8(SHORT_STRING_HEADER | len);
353
354 currentBuffer.write(thing, currentPosition, "latin1");
355 currentPosition += len;
356 } else {
357 allocate(len + HEADER_SIZE);
358 writeU8(SHORT_STRING_HEADER | len);
359
360 for (let i = 0; i < len; i++) {
361 currentBuffer[currentPosition++] = thing.charCodeAt(i);
362 }
363 }
364 break;
365 }
366 case "bigint": {
367 const type = identifyBigInt(thing);
368 if (type === 0 && thing >= 0 && thing <= BigInt(10)) {
369 // shortcut for very small bigints
370 allocate(HEADER_SIZE + I8_SIZE);
371 writeU8(BIGINT_I8_HEADER);
372 writeU8(Number(thing));
373 break;
374 }
375
376 switch (type) {
377 case 0: {
378 let n = 1;
379 allocate(HEADER_SIZE + I8_SIZE * n);
380 writeU8(BIGINT_I8_HEADER | (n - 1));
381 while (n > 0) {
382 currentBuffer.writeInt8(
383 Number(/** @type {bigint} */ (data[i])),
384 currentPosition
385 );
386 currentPosition += I8_SIZE;
387 n--;
388 i++;
389 }
390 i--;
391 break;
392 }
393 case 1: {
394 let n = 1;
395 allocate(HEADER_SIZE + I32_SIZE * n);
396 writeU8(BIGINT_I32_HEADER | (n - 1));
397 while (n > 0) {
398 currentBuffer.writeInt32LE(
399 Number(/** @type {bigint} */ (data[i])),
400 currentPosition
401 );
402 currentPosition += I32_SIZE;
403 n--;
404 i++;
405 }
406 i--;
407 break;
408 }
409 default: {
410 const value = thing.toString();
411 const len = Buffer.byteLength(value);
412 allocate(len + HEADER_SIZE + I32_SIZE);
413 writeU8(BIGINT_HEADER);
414 writeU32(len);
415 currentBuffer.write(value, currentPosition);
416 currentPosition += len;
417 break;
418 }
419 }
420 break;
421 }
422 case "number": {
423 const type = identifyNumber(thing);
424 if (type === 0 && thing >= 0 && thing <= 10) {
425 // shortcut for very small numbers
426 allocate(I8_SIZE);
427 writeU8(thing);
428 break;
429 }
430 /**
431 * amount of numbers to write
432 * @type {number}
433 */
434 let n = 1;
435 for (; n < 32 && i + n < data.length; n++) {
436 const item = data[i + n];
437 if (typeof item !== "number") break;
438 if (identifyNumber(item) !== type) break;
439 }
440 switch (type) {
441 case 0:
442 allocate(HEADER_SIZE + I8_SIZE * n);
443 writeU8(I8_HEADER | (n - 1));
444 while (n > 0) {
445 currentBuffer.writeInt8(
446 /** @type {number} */ (data[i]),
447 currentPosition
448 );
449 currentPosition += I8_SIZE;
450 n--;
451 i++;
452 }
453 break;
454 case 1:
455 allocate(HEADER_SIZE + I32_SIZE * n);
456 writeU8(I32_HEADER | (n - 1));
457 while (n > 0) {
458 currentBuffer.writeInt32LE(
459 /** @type {number} */ (data[i]),
460 currentPosition
461 );
462 currentPosition += I32_SIZE;
463 n--;
464 i++;
465 }
466 break;
467 case 2:
468 allocate(HEADER_SIZE + F64_SIZE * n);
469 writeU8(F64_HEADER | (n - 1));
470 while (n > 0) {
471 currentBuffer.writeDoubleLE(
472 /** @type {number} */ (data[i]),
473 currentPosition
474 );
475 currentPosition += F64_SIZE;
476 n--;
477 i++;
478 }
479 break;
480 }
481
482 i--;
483 break;
484 }
485 case "boolean": {
486 let lastByte = thing === true ? 1 : 0;
487 const bytes = [];
488 let count = 1;
489 let n;
490 for (n = 1; n < 0xffffffff && i + n < data.length; n++) {
491 const item = data[i + n];
492 if (typeof item !== "boolean") break;
493 const pos = count & 0x7;
494 if (pos === 0) {
495 bytes.push(lastByte);
496 lastByte = item === true ? 1 : 0;
497 } else if (item === true) {
498 lastByte |= 1 << pos;
499 }
500 count++;
501 }
502 i += count - 1;
503 if (count === 1) {
504 allocate(HEADER_SIZE);
505 writeU8(lastByte === 1 ? TRUE_HEADER : FALSE_HEADER);
506 } else if (count === 2) {
507 allocate(HEADER_SIZE * 2);
508 writeU8(lastByte & 1 ? TRUE_HEADER : FALSE_HEADER);
509 writeU8(lastByte & 2 ? TRUE_HEADER : FALSE_HEADER);
510 } else if (count <= 6) {
511 allocate(HEADER_SIZE + I8_SIZE);
512 writeU8(BOOLEANS_HEADER);
513 writeU8((1 << count) | lastByte);
514 } else if (count <= 133) {
515 allocate(HEADER_SIZE + I8_SIZE + I8_SIZE * bytes.length + I8_SIZE);
516 writeU8(BOOLEANS_HEADER);
517 writeU8(0x80 | (count - 7));
518 for (const byte of bytes) writeU8(byte);
519 writeU8(lastByte);
520 } else {
521 allocate(
522 HEADER_SIZE +
523 I8_SIZE +
524 I32_SIZE +
525 I8_SIZE * bytes.length +
526 I8_SIZE
527 );
528 writeU8(BOOLEANS_HEADER);
529 writeU8(0xff);
530 writeU32(count);
531 for (const byte of bytes) writeU8(byte);
532 writeU8(lastByte);
533 }
534 break;
535 }
536 case "object": {
537 if (thing === null) {
538 let n;
539 for (n = 1; n < 0x100000104 && i + n < data.length; n++) {
540 const item = data[i + n];
541 if (item !== null) break;
542 }
543 i += n - 1;
544 if (n === 1) {
545 if (i + 1 < data.length) {
546 const next = data[i + 1];
547 if (next === true) {
548 allocate(HEADER_SIZE);
549 writeU8(NULL_AND_TRUE_HEADER);
550 i++;
551 } else if (next === false) {
552 allocate(HEADER_SIZE);
553 writeU8(NULL_AND_FALSE_HEADER);
554 i++;
555 } else if (typeof next === "number") {
556 const type = identifyNumber(next);
557 if (type === 0) {
558 allocate(HEADER_SIZE + I8_SIZE);
559 writeU8(NULL_AND_I8_HEADER);
560 currentBuffer.writeInt8(next, currentPosition);
561 currentPosition += I8_SIZE;
562 i++;
563 } else if (type === 1) {
564 allocate(HEADER_SIZE + I32_SIZE);
565 writeU8(NULL_AND_I32_HEADER);
566 currentBuffer.writeInt32LE(next, currentPosition);
567 currentPosition += I32_SIZE;
568 i++;
569 } else {
570 allocate(HEADER_SIZE);
571 writeU8(NULL_HEADER);
572 }
573 } else {
574 allocate(HEADER_SIZE);
575 writeU8(NULL_HEADER);
576 }
577 } else {
578 allocate(HEADER_SIZE);
579 writeU8(NULL_HEADER);
580 }
581 } else if (n === 2) {
582 allocate(HEADER_SIZE);
583 writeU8(NULL2_HEADER);
584 } else if (n === 3) {
585 allocate(HEADER_SIZE);
586 writeU8(NULL3_HEADER);
587 } else if (n < 260) {
588 allocate(HEADER_SIZE + I8_SIZE);
589 writeU8(NULLS8_HEADER);
590 writeU8(n - 4);
591 } else {
592 allocate(HEADER_SIZE + I32_SIZE);
593 writeU8(NULLS32_HEADER);
594 writeU32(n - 260);
595 }
596 } else if (Buffer.isBuffer(thing)) {
597 if (thing.length < 8192) {
598 allocate(HEADER_SIZE + I32_SIZE + thing.length);
599 writeU8(BUFFER_HEADER);
600 writeU32(thing.length);
601 thing.copy(currentBuffer, currentPosition);
602 currentPosition += thing.length;
603 } else {
604 allocate(HEADER_SIZE + I32_SIZE);
605 writeU8(BUFFER_HEADER);
606 writeU32(thing.length);
607 flush();
608 buffers.push(thing);
609 }
610 }
611 break;
612 }
613 case "symbol": {
614 if (thing === MEASURE_START_OPERATION) {
615 measureStart();
616 } else if (thing === MEASURE_END_OPERATION) {
617 const size = measureEnd();
618 allocate(HEADER_SIZE + I32_SIZE);
619 writeU8(I32_HEADER);
620 currentBuffer.writeInt32LE(size, currentPosition);
621 currentPosition += I32_SIZE;
622 }
623 break;
624 }
625 default: {
626 throw new Error(
627 `Unknown typeof "${typeof thing}" in binary middleware`
628 );
629 }
630 }
631 }
632 flush();
633
634 allocationScope.leftOverBuffer = leftOverBuffer;
635
636 // avoid leaking memory
637 currentBuffer = null;
638 leftOverBuffer = null;
639 allocationScope = /** @type {EXPECTED_ANY} */ (undefined);
640 const _buffers = buffers;
641 buffers = /** @type {EXPECTED_ANY} */ (undefined);
642 return _buffers;
643 }
644
645 /**
646 * @param {SerializedType} data data
647 * @param {object} context context object
648 * @returns {DeserializedType|Promise<DeserializedType>} deserialized data
649 */
650 deserialize(data, context) {
651 return this._deserialize(data, context);
652 }
653
654 _createLazyDeserialized(content, context) {
655 return SerializerMiddleware.createLazy(
656 memoize(() => this._deserialize(content, context)),
657 this,
658 undefined,
659 content
660 );
661 }
662
663 _deserializeLazy(fn, context) {
664 return SerializerMiddleware.deserializeLazy(fn, data =>
665 this._deserialize(data, context)
666 );
667 }
668
669 /**
670 * @param {SerializedType} data data
671 * @param {TODO} context context object
672 * @returns {DeserializedType} deserialized data
673 */
674 _deserialize(data, context) {
675 let currentDataItem = 0;
676 /** @type {BufferSerializableType | null} */
677 let currentBuffer = data[0];
678 let currentIsBuffer = Buffer.isBuffer(currentBuffer);
679 let currentPosition = 0;
680
681 /** @type {(x: Buffer) => Buffer} */
682 const retainedBuffer = context.retainedBuffer || (x => x);
683
684 const checkOverflow = () => {
685 if (currentPosition >= /** @type {Buffer} */ (currentBuffer).length) {
686 currentPosition = 0;
687 currentDataItem++;
688 currentBuffer =
689 currentDataItem < data.length ? data[currentDataItem] : null;
690 currentIsBuffer = Buffer.isBuffer(currentBuffer);
691 }
692 };
693 /**
694 * @param {number} n n
695 * @returns {boolean} true when in current buffer, otherwise false
696 */
697 const isInCurrentBuffer = n =>
698 currentIsBuffer &&
699 n + currentPosition <= /** @type {Buffer} */ (currentBuffer).length;
700 const ensureBuffer = () => {
701 if (!currentIsBuffer) {
702 throw new Error(
703 currentBuffer === null
704 ? "Unexpected end of stream"
705 : "Unexpected lazy element in stream"
706 );
707 }
708 };
709 /**
710 * Reads n bytes
711 * @param {number} n amount of bytes to read
712 * @returns {Buffer} buffer with bytes
713 */
714 const read = n => {
715 ensureBuffer();
716 const rem =
717 /** @type {Buffer} */ (currentBuffer).length - currentPosition;
718 if (rem < n) {
719 const buffers = [read(rem)];
720 n -= rem;
721 ensureBuffer();
722 while (/** @type {Buffer} */ (currentBuffer).length < n) {
723 const b = /** @type {Buffer} */ (currentBuffer);
724 buffers.push(b);
725 n -= b.length;
726 currentDataItem++;
727 currentBuffer =
728 currentDataItem < data.length ? data[currentDataItem] : null;
729 currentIsBuffer = Buffer.isBuffer(currentBuffer);
730 ensureBuffer();
731 }
732 buffers.push(read(n));
733 return Buffer.concat(buffers);
734 }
735 const b = /** @type {Buffer} */ (currentBuffer);
736 const res = Buffer.from(b.buffer, b.byteOffset + currentPosition, n);
737 currentPosition += n;
738 checkOverflow();
739 return res;
740 };
741 /**
742 * Reads up to n bytes
743 * @param {number} n amount of bytes to read
744 * @returns {Buffer} buffer with bytes
745 */
746 const readUpTo = n => {
747 ensureBuffer();
748 const rem =
749 /** @type {Buffer} */
750 (currentBuffer).length - currentPosition;
751 if (rem < n) {
752 n = rem;
753 }
754 const b = /** @type {Buffer} */ (currentBuffer);
755 const res = Buffer.from(b.buffer, b.byteOffset + currentPosition, n);
756 currentPosition += n;
757 checkOverflow();
758 return res;
759 };
760 /**
761 * @returns {number} U8
762 */
763 const readU8 = () => {
764 ensureBuffer();
765 /**
766 * There is no need to check remaining buffer size here
767 * since {@link checkOverflow} guarantees at least one byte remaining
768 */
769 const byte =
770 /** @type {Buffer} */
771 (currentBuffer).readUInt8(currentPosition);
772 currentPosition += I8_SIZE;
773 checkOverflow();
774 return byte;
775 };
776 /**
777 * @returns {number} U32
778 */
779 const readU32 = () => read(I32_SIZE).readUInt32LE(0);
780 /**
781 * @param {number} data data
782 * @param {number} n n
783 */
784 const readBits = (data, n) => {
785 let mask = 1;
786 while (n !== 0) {
787 result.push((data & mask) !== 0);
788 mask = mask << 1;
789 n--;
790 }
791 };
792 const dispatchTable = Array.from({ length: 256 }).map((_, header) => {
793 switch (header) {
794 case LAZY_HEADER:
795 return () => {
796 const count = readU32();
797 const lengths = Array.from({ length: count }).map(() => readU32());
798 const content = [];
799 for (let l of lengths) {
800 if (l === 0) {
801 if (typeof currentBuffer !== "function") {
802 throw new Error("Unexpected non-lazy element in stream");
803 }
804 content.push(currentBuffer);
805 currentDataItem++;
806 currentBuffer =
807 currentDataItem < data.length ? data[currentDataItem] : null;
808 currentIsBuffer = Buffer.isBuffer(currentBuffer);
809 } else {
810 do {
811 const buf = readUpTo(l);
812 l -= buf.length;
813 content.push(retainedBuffer(buf));
814 } while (l > 0);
815 }
816 }
817 result.push(this._createLazyDeserialized(content, context));
818 };
819 case BUFFER_HEADER:
820 return () => {
821 const len = readU32();
822 result.push(retainedBuffer(read(len)));
823 };
824 case TRUE_HEADER:
825 return () => result.push(true);
826 case FALSE_HEADER:
827 return () => result.push(false);
828 case NULL3_HEADER:
829 return () => result.push(null, null, null);
830 case NULL2_HEADER:
831 return () => result.push(null, null);
832 case NULL_HEADER:
833 return () => result.push(null);
834 case NULL_AND_TRUE_HEADER:
835 return () => result.push(null, true);
836 case NULL_AND_FALSE_HEADER:
837 return () => result.push(null, false);
838 case NULL_AND_I8_HEADER:
839 return () => {
840 if (currentIsBuffer) {
841 result.push(
842 null,
843 /** @type {Buffer} */ (currentBuffer).readInt8(currentPosition)
844 );
845 currentPosition += I8_SIZE;
846 checkOverflow();
847 } else {
848 result.push(null, read(I8_SIZE).readInt8(0));
849 }
850 };
851 case NULL_AND_I32_HEADER:
852 return () => {
853 result.push(null);
854 if (isInCurrentBuffer(I32_SIZE)) {
855 result.push(
856 /** @type {Buffer} */ (currentBuffer).readInt32LE(
857 currentPosition
858 )
859 );
860 currentPosition += I32_SIZE;
861 checkOverflow();
862 } else {
863 result.push(read(I32_SIZE).readInt32LE(0));
864 }
865 };
866 case NULLS8_HEADER:
867 return () => {
868 const len = readU8() + 4;
869 for (let i = 0; i < len; i++) {
870 result.push(null);
871 }
872 };
873 case NULLS32_HEADER:
874 return () => {
875 const len = readU32() + 260;
876 for (let i = 0; i < len; i++) {
877 result.push(null);
878 }
879 };
880 case BOOLEANS_HEADER:
881 return () => {
882 const innerHeader = readU8();
883 if ((innerHeader & 0xf0) === 0) {
884 readBits(innerHeader, 3);
885 } else if ((innerHeader & 0xe0) === 0) {
886 readBits(innerHeader, 4);
887 } else if ((innerHeader & 0xc0) === 0) {
888 readBits(innerHeader, 5);
889 } else if ((innerHeader & 0x80) === 0) {
890 readBits(innerHeader, 6);
891 } else if (innerHeader !== 0xff) {
892 let count = (innerHeader & 0x7f) + 7;
893 while (count > 8) {
894 readBits(readU8(), 8);
895 count -= 8;
896 }
897 readBits(readU8(), count);
898 } else {
899 let count = readU32();
900 while (count > 8) {
901 readBits(readU8(), 8);
902 count -= 8;
903 }
904 readBits(readU8(), count);
905 }
906 };
907 case STRING_HEADER:
908 return () => {
909 const len = readU32();
910 if (isInCurrentBuffer(len) && currentPosition + len < 0x7fffffff) {
911 result.push(
912 /** @type {Buffer} */
913 (currentBuffer).toString(
914 undefined,
915 currentPosition,
916 currentPosition + len
917 )
918 );
919 currentPosition += len;
920 checkOverflow();
921 } else {
922 result.push(read(len).toString());
923 }
924 };
925 case SHORT_STRING_HEADER:
926 return () => result.push("");
927 case SHORT_STRING_HEADER | 1:
928 return () => {
929 if (currentIsBuffer && currentPosition < 0x7ffffffe) {
930 result.push(
931 /** @type {Buffer} */
932 (currentBuffer).toString(
933 "latin1",
934 currentPosition,
935 currentPosition + 1
936 )
937 );
938 currentPosition++;
939 checkOverflow();
940 } else {
941 result.push(read(1).toString("latin1"));
942 }
943 };
944 case I8_HEADER:
945 return () => {
946 if (currentIsBuffer) {
947 result.push(
948 /** @type {Buffer} */ (currentBuffer).readInt8(currentPosition)
949 );
950 currentPosition++;
951 checkOverflow();
952 } else {
953 result.push(read(1).readInt8(0));
954 }
955 };
956 case BIGINT_I8_HEADER: {
957 const len = 1;
958 return () => {
959 const need = I8_SIZE * len;
960
961 if (isInCurrentBuffer(need)) {
962 for (let i = 0; i < len; i++) {
963 const value =
964 /** @type {Buffer} */
965 (currentBuffer).readInt8(currentPosition);
966 result.push(BigInt(value));
967 currentPosition += I8_SIZE;
968 }
969 checkOverflow();
970 } else {
971 const buf = read(need);
972 for (let i = 0; i < len; i++) {
973 const value = buf.readInt8(i * I8_SIZE);
974 result.push(BigInt(value));
975 }
976 }
977 };
978 }
979 case BIGINT_I32_HEADER: {
980 const len = 1;
981 return () => {
982 const need = I32_SIZE * len;
983 if (isInCurrentBuffer(need)) {
984 for (let i = 0; i < len; i++) {
985 const value = /** @type {Buffer} */ (currentBuffer).readInt32LE(
986 currentPosition
987 );
988 result.push(BigInt(value));
989 currentPosition += I32_SIZE;
990 }
991 checkOverflow();
992 } else {
993 const buf = read(need);
994 for (let i = 0; i < len; i++) {
995 const value = buf.readInt32LE(i * I32_SIZE);
996 result.push(BigInt(value));
997 }
998 }
999 };
1000 }
1001 case BIGINT_HEADER: {
1002 return () => {
1003 const len = readU32();
1004 if (isInCurrentBuffer(len) && currentPosition + len < 0x7fffffff) {
1005 const value =
1006 /** @type {Buffer} */
1007 (currentBuffer).toString(
1008 undefined,
1009 currentPosition,
1010 currentPosition + len
1011 );
1012
1013 result.push(BigInt(value));
1014 currentPosition += len;
1015 checkOverflow();
1016 } else {
1017 const value = read(len).toString();
1018 result.push(BigInt(value));
1019 }
1020 };
1021 }
1022 default:
1023 if (header <= 10) {
1024 return () => result.push(header);
1025 } else if ((header & SHORT_STRING_HEADER) === SHORT_STRING_HEADER) {
1026 const len = header & SHORT_STRING_LENGTH_MASK;
1027 return () => {
1028 if (
1029 isInCurrentBuffer(len) &&
1030 currentPosition + len < 0x7fffffff
1031 ) {
1032 result.push(
1033 /** @type {Buffer} */
1034 (currentBuffer).toString(
1035 "latin1",
1036 currentPosition,
1037 currentPosition + len
1038 )
1039 );
1040 currentPosition += len;
1041 checkOverflow();
1042 } else {
1043 result.push(read(len).toString("latin1"));
1044 }
1045 };
1046 } else if ((header & NUMBERS_HEADER_MASK) === F64_HEADER) {
1047 const len = (header & NUMBERS_COUNT_MASK) + 1;
1048 return () => {
1049 const need = F64_SIZE * len;
1050 if (isInCurrentBuffer(need)) {
1051 for (let i = 0; i < len; i++) {
1052 result.push(
1053 /** @type {Buffer} */ (currentBuffer).readDoubleLE(
1054 currentPosition
1055 )
1056 );
1057 currentPosition += F64_SIZE;
1058 }
1059 checkOverflow();
1060 } else {
1061 const buf = read(need);
1062 for (let i = 0; i < len; i++) {
1063 result.push(buf.readDoubleLE(i * F64_SIZE));
1064 }
1065 }
1066 };
1067 } else if ((header & NUMBERS_HEADER_MASK) === I32_HEADER) {
1068 const len = (header & NUMBERS_COUNT_MASK) + 1;
1069 return () => {
1070 const need = I32_SIZE * len;
1071 if (isInCurrentBuffer(need)) {
1072 for (let i = 0; i < len; i++) {
1073 result.push(
1074 /** @type {Buffer} */ (currentBuffer).readInt32LE(
1075 currentPosition
1076 )
1077 );
1078 currentPosition += I32_SIZE;
1079 }
1080 checkOverflow();
1081 } else {
1082 const buf = read(need);
1083 for (let i = 0; i < len; i++) {
1084 result.push(buf.readInt32LE(i * I32_SIZE));
1085 }
1086 }
1087 };
1088 } else if ((header & NUMBERS_HEADER_MASK) === I8_HEADER) {
1089 const len = (header & NUMBERS_COUNT_MASK) + 1;
1090 return () => {
1091 const need = I8_SIZE * len;
1092 if (isInCurrentBuffer(need)) {
1093 for (let i = 0; i < len; i++) {
1094 result.push(
1095 /** @type {Buffer} */ (currentBuffer).readInt8(
1096 currentPosition
1097 )
1098 );
1099 currentPosition += I8_SIZE;
1100 }
1101 checkOverflow();
1102 } else {
1103 const buf = read(need);
1104 for (let i = 0; i < len; i++) {
1105 result.push(buf.readInt8(i * I8_SIZE));
1106 }
1107 }
1108 };
1109 }
1110 return () => {
1111 throw new Error(`Unexpected header byte 0x${header.toString(16)}`);
1112 };
1113 }
1114 });
1115
1116 /** @type {DeserializedType} */
1117 let result = [];
1118 while (currentBuffer !== null) {
1119 if (typeof currentBuffer === "function") {
1120 result.push(this._deserializeLazy(currentBuffer, context));
1121 currentDataItem++;
1122 currentBuffer =
1123 currentDataItem < data.length ? data[currentDataItem] : null;
1124 currentIsBuffer = Buffer.isBuffer(currentBuffer);
1125 } else {
1126 const header = readU8();
1127 dispatchTable[header]();
1128 }
1129 }
1130
1131 // avoid leaking memory in context
1132 // eslint-disable-next-line prefer-const
1133 let _result = result;
1134 result = /** @type {EXPECTED_ANY} */ (undefined);
1135 return _result;
1136 }
1137}
1138
1139module.exports = BinaryMiddleware;
1140
1141module.exports.MEASURE_START_OPERATION = MEASURE_START_OPERATION;
1142module.exports.MEASURE_END_OPERATION = MEASURE_END_OPERATION;
Note: See TracBrowser for help on using the repository browser.