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

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

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