BinaryMiddleware.js 32 KB

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