Skip to content

Commit ad70153

Browse files
committed
feat!: return ArrayBuffer instead of Blob
1 parent c2c03f6 commit ad70153

8 files changed

+99
-134
lines changed

__test__/objects.spec.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,6 @@ describe("Binarypack", () => {
9898
}
9999
});
100100

101-
it("should transfer Blobs as ArrayBuffer", async () => {
102-
const values = [
103-
new Blob(),
104-
new Blob(["test"]),
105-
new Blob(["test", "test", "test", "test", "test"]),
106-
];
107-
expect.assertions(values.length);
108-
for (const v of values) {
109-
expect(await packAndUnpack(v)).toEqual(await v.arrayBuffer());
110-
}
111-
});
112-
113101
it("should transfer Dates as String", async () => {
114102
const values = [new Date(), new Date(Date.UTC(1, 1, 1, 1, 1, 1, 1))];
115103
expect.assertions(values.length);

__test__/util.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { pack, Packable, unpack, Unpackable } from "../lib/binarypack";
22

3-
// jsdom doesn't support Blob yet
4-
import "blob-polyfill";
5-
63
export const packAndUnpack = async <T extends Unpackable>(data: Packable) => {
74
const encoded = pack(data);
8-
const onTheWire = await encoded.arrayBuffer();
9-
return unpack<T>(onTheWire);
5+
return unpack<T>(encoded);
106
};

jest.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const config = {
88
// "node_modules"
99
],
1010
collectCoverageFrom: ["./lib/**"],
11+
setupFilesAfterEnv: ["./jest.setup.cjs"],
1112
};
1213

1314
// noinspection JSUnusedGlobalSymbols

jest.setup.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
globalThis.TextEncoder = require("util").TextEncoder;

lib/binarypack.ts

Lines changed: 64 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ export type Packable =
77
| number
88
| boolean
99
| Date
10-
| Blob
1110
| ArrayBuffer
1211
| Array<Packable>
1312
| { [key: string]: Packable }
14-
| ({ BYTES_PER_ELEMENT: number; buffer: ArrayBuffer } & DataView);
13+
| ({ BYTES_PER_ELEMENT: number } & ArrayBufferView);
1514
export type Unpackable =
1615
| null
1716
| undefined
@@ -289,15 +288,12 @@ class Unpacker {
289288
}
290289
}
291290

292-
class Packer {
293-
private bufferBuilder: BufferBuilder;
294-
295-
constructor() {
296-
this.bufferBuilder = new BufferBuilder();
297-
}
291+
export class Packer {
292+
private _bufferBuilder = new BufferBuilder();
293+
private _textEncoder = new TextEncoder();
298294

299295
getBuffer() {
300-
return this.bufferBuilder.getBuffer();
296+
return this._bufferBuilder.toArrayBuffer();
301297
}
302298

303299
pack(value: Packable) {
@@ -311,21 +307,19 @@ class Packer {
311307
}
312308
} else if (typeof value === "boolean") {
313309
if (value === true) {
314-
this.bufferBuilder.append(0xc3);
310+
this._bufferBuilder.append(0xc3);
315311
} else if (value === false) {
316-
this.bufferBuilder.append(0xc2);
312+
this._bufferBuilder.append(0xc2);
317313
}
318314
} else if (value === undefined) {
319-
this.bufferBuilder.append(0xc1);
315+
this._bufferBuilder.append(0xc1);
320316
} else if (typeof value === "object") {
321317
if (value === null) {
322-
this.bufferBuilder.append(0xc0);
318+
this._bufferBuilder.append(0xc0);
323319
} else {
324320
const constructor = value.constructor;
325321
if (value instanceof Array) {
326322
this.pack_array(value);
327-
} else if (value instanceof Blob) {
328-
this.pack_bin(value);
329323
} else if (value instanceof ArrayBuffer) {
330324
this.pack_bin(new Uint8Array(value));
331325
} else if ("BYTES_PER_ELEMENT" in value) {
@@ -345,52 +339,53 @@ class Packer {
345339
} else {
346340
throw new Error(`Type "${typeof value}" not yet supported`);
347341
}
348-
this.bufferBuilder.flush();
342+
this._bufferBuilder.flush();
349343
}
350344

351-
pack_bin(blob: Blob | Uint8Array) {
352-
const length = blob instanceof Uint8Array ? blob.length : blob.size;
345+
pack_bin(blob: Uint8Array) {
346+
const length = blob.length;
353347

354348
if (length <= 0x0f) {
355349
this.pack_uint8(0xa0 + length);
356350
} else if (length <= 0xffff) {
357-
this.bufferBuilder.append(0xda);
351+
this._bufferBuilder.append(0xda);
358352
this.pack_uint16(length);
359353
} else if (length <= 0xffffffff) {
360-
this.bufferBuilder.append(0xdb);
354+
this._bufferBuilder.append(0xdb);
361355
this.pack_uint32(length);
362356
} else {
363357
throw new Error("Invalid length");
364358
}
365-
this.bufferBuilder.append(blob);
359+
this._bufferBuilder.append_buffer(blob);
366360
}
367361

368362
pack_string(str: string) {
369-
const length = utf8Length(str);
363+
const encoded = this._textEncoder.encode(str);
364+
const length = encoded.length;
370365

371366
if (length <= 0x0f) {
372367
this.pack_uint8(0xb0 + length);
373368
} else if (length <= 0xffff) {
374-
this.bufferBuilder.append(0xd8);
369+
this._bufferBuilder.append(0xd8);
375370
this.pack_uint16(length);
376371
} else if (length <= 0xffffffff) {
377-
this.bufferBuilder.append(0xd9);
372+
this._bufferBuilder.append(0xd9);
378373
this.pack_uint32(length);
379374
} else {
380375
throw new Error("Invalid length");
381376
}
382-
this.bufferBuilder.append(str);
377+
this._bufferBuilder.append_buffer(encoded);
383378
}
384379

385380
pack_array(ary: Packable[]) {
386381
const length = ary.length;
387382
if (length <= 0x0f) {
388383
this.pack_uint8(0x90 + length);
389384
} else if (length <= 0xffff) {
390-
this.bufferBuilder.append(0xdc);
385+
this._bufferBuilder.append(0xdc);
391386
this.pack_uint16(length);
392387
} else if (length <= 0xffffffff) {
393-
this.bufferBuilder.append(0xdd);
388+
this._bufferBuilder.append(0xdd);
394389
this.pack_uint32(length);
395390
} else {
396391
throw new Error("Invalid length");
@@ -402,30 +397,30 @@ class Packer {
402397

403398
pack_integer(num: number) {
404399
if (num >= -0x20 && num <= 0x7f) {
405-
this.bufferBuilder.append(num & 0xff);
400+
this._bufferBuilder.append(num & 0xff);
406401
} else if (num >= 0x00 && num <= 0xff) {
407-
this.bufferBuilder.append(0xcc);
402+
this._bufferBuilder.append(0xcc);
408403
this.pack_uint8(num);
409404
} else if (num >= -0x80 && num <= 0x7f) {
410-
this.bufferBuilder.append(0xd0);
405+
this._bufferBuilder.append(0xd0);
411406
this.pack_int8(num);
412407
} else if (num >= 0x0000 && num <= 0xffff) {
413-
this.bufferBuilder.append(0xcd);
408+
this._bufferBuilder.append(0xcd);
414409
this.pack_uint16(num);
415410
} else if (num >= -0x8000 && num <= 0x7fff) {
416-
this.bufferBuilder.append(0xd1);
411+
this._bufferBuilder.append(0xd1);
417412
this.pack_int16(num);
418413
} else if (num >= 0x00000000 && num <= 0xffffffff) {
419-
this.bufferBuilder.append(0xce);
414+
this._bufferBuilder.append(0xce);
420415
this.pack_uint32(num);
421416
} else if (num >= -0x80000000 && num <= 0x7fffffff) {
422-
this.bufferBuilder.append(0xd2);
417+
this._bufferBuilder.append(0xd2);
423418
this.pack_int32(num);
424419
} else if (num >= -0x8000000000000000 && num <= 0x7fffffffffffffff) {
425-
this.bufferBuilder.append(0xd3);
420+
this._bufferBuilder.append(0xd3);
426421
this.pack_int64(num);
427422
} else if (num >= 0x0000000000000000 && num <= 0xffffffffffffffff) {
428-
this.bufferBuilder.append(0xcf);
423+
this._bufferBuilder.append(0xcf);
429424
this.pack_uint64(num);
430425
} else {
431426
throw new Error("Invalid integer");
@@ -445,7 +440,7 @@ class Packer {
445440
const h32 =
446441
(sign << 31) | ((exp + 1023) << 20) | ((frac1 / b32) & 0x0fffff);
447442
const l32 = frac1 % b32;
448-
this.bufferBuilder.append(0xcb);
443+
this._bufferBuilder.append(0xcb);
449444
this.pack_int32(h32);
450445
this.pack_int32(l32);
451446
}
@@ -456,10 +451,10 @@ class Packer {
456451
if (length <= 0x0f) {
457452
this.pack_uint8(0x80 + length);
458453
} else if (length <= 0xffff) {
459-
this.bufferBuilder.append(0xde);
454+
this._bufferBuilder.append(0xde);
460455
this.pack_uint16(length);
461456
} else if (length <= 0xffffffff) {
462-
this.bufferBuilder.append(0xdf);
457+
this._bufferBuilder.append(0xdf);
463458
this.pack_uint32(length);
464459
} else {
465460
throw new Error("Invalid length");
@@ -474,84 +469,61 @@ class Packer {
474469
}
475470

476471
pack_uint8(num: number) {
477-
this.bufferBuilder.append(num);
472+
this._bufferBuilder.append(num);
478473
}
479474

480475
pack_uint16(num: number) {
481-
this.bufferBuilder.append(num >> 8);
482-
this.bufferBuilder.append(num & 0xff);
476+
this._bufferBuilder.append(num >> 8);
477+
this._bufferBuilder.append(num & 0xff);
483478
}
484479

485480
pack_uint32(num: number) {
486481
const n = num & 0xffffffff;
487-
this.bufferBuilder.append((n & 0xff000000) >>> 24);
488-
this.bufferBuilder.append((n & 0x00ff0000) >>> 16);
489-
this.bufferBuilder.append((n & 0x0000ff00) >>> 8);
490-
this.bufferBuilder.append(n & 0x000000ff);
482+
this._bufferBuilder.append((n & 0xff000000) >>> 24);
483+
this._bufferBuilder.append((n & 0x00ff0000) >>> 16);
484+
this._bufferBuilder.append((n & 0x0000ff00) >>> 8);
485+
this._bufferBuilder.append(n & 0x000000ff);
491486
}
492487

493488
pack_uint64(num: number) {
494489
const high = num / 2 ** 32;
495490
const low = num % 2 ** 32;
496-
this.bufferBuilder.append((high & 0xff000000) >>> 24);
497-
this.bufferBuilder.append((high & 0x00ff0000) >>> 16);
498-
this.bufferBuilder.append((high & 0x0000ff00) >>> 8);
499-
this.bufferBuilder.append(high & 0x000000ff);
500-
this.bufferBuilder.append((low & 0xff000000) >>> 24);
501-
this.bufferBuilder.append((low & 0x00ff0000) >>> 16);
502-
this.bufferBuilder.append((low & 0x0000ff00) >>> 8);
503-
this.bufferBuilder.append(low & 0x000000ff);
491+
this._bufferBuilder.append((high & 0xff000000) >>> 24);
492+
this._bufferBuilder.append((high & 0x00ff0000) >>> 16);
493+
this._bufferBuilder.append((high & 0x0000ff00) >>> 8);
494+
this._bufferBuilder.append(high & 0x000000ff);
495+
this._bufferBuilder.append((low & 0xff000000) >>> 24);
496+
this._bufferBuilder.append((low & 0x00ff0000) >>> 16);
497+
this._bufferBuilder.append((low & 0x0000ff00) >>> 8);
498+
this._bufferBuilder.append(low & 0x000000ff);
504499
}
505500

506501
pack_int8(num: number) {
507-
this.bufferBuilder.append(num & 0xff);
502+
this._bufferBuilder.append(num & 0xff);
508503
}
509504

510505
pack_int16(num: number) {
511-
this.bufferBuilder.append((num & 0xff00) >> 8);
512-
this.bufferBuilder.append(num & 0xff);
506+
this._bufferBuilder.append((num & 0xff00) >> 8);
507+
this._bufferBuilder.append(num & 0xff);
513508
}
514509

515510
pack_int32(num: number) {
516-
this.bufferBuilder.append((num >>> 24) & 0xff);
517-
this.bufferBuilder.append((num & 0x00ff0000) >>> 16);
518-
this.bufferBuilder.append((num & 0x0000ff00) >>> 8);
519-
this.bufferBuilder.append(num & 0x000000ff);
511+
this._bufferBuilder.append((num >>> 24) & 0xff);
512+
this._bufferBuilder.append((num & 0x00ff0000) >>> 16);
513+
this._bufferBuilder.append((num & 0x0000ff00) >>> 8);
514+
this._bufferBuilder.append(num & 0x000000ff);
520515
}
521516

522517
pack_int64(num: number) {
523518
const high = Math.floor(num / 2 ** 32);
524519
const low = num % 2 ** 32;
525-
this.bufferBuilder.append((high & 0xff000000) >>> 24);
526-
this.bufferBuilder.append((high & 0x00ff0000) >>> 16);
527-
this.bufferBuilder.append((high & 0x0000ff00) >>> 8);
528-
this.bufferBuilder.append(high & 0x000000ff);
529-
this.bufferBuilder.append((low & 0xff000000) >>> 24);
530-
this.bufferBuilder.append((low & 0x00ff0000) >>> 16);
531-
this.bufferBuilder.append((low & 0x0000ff00) >>> 8);
532-
this.bufferBuilder.append(low & 0x000000ff);
533-
}
534-
}
535-
536-
function _utf8Replace(m: string) {
537-
const code = m.codePointAt(0)!;
538-
539-
if (code <= 0x7ff) return "00";
540-
if (code <= 0xffff) return "000";
541-
if (code <= 0x1fffff) return "0000";
542-
if (code <= 0x3ffffff) return "00000";
543-
return "000000";
544-
}
545-
546-
function utf8Length(str: string) {
547-
if (str.length > 600) {
548-
// Blob method faster for large strings
549-
return new Blob([str]).size;
550-
} else {
551-
return str.replace(
552-
// eslint-disable-next-line no-control-regex
553-
/[\ud800-\udbff][\udc00-\udfff]|[^\u0000-\u007f]/g,
554-
_utf8Replace,
555-
).length;
520+
this._bufferBuilder.append((high & 0xff000000) >>> 24);
521+
this._bufferBuilder.append((high & 0x00ff0000) >>> 16);
522+
this._bufferBuilder.append((high & 0x0000ff00) >>> 8);
523+
this._bufferBuilder.append(high & 0x000000ff);
524+
this._bufferBuilder.append((low & 0xff000000) >>> 24);
525+
this._bufferBuilder.append((low & 0x00ff0000) >>> 16);
526+
this._bufferBuilder.append((low & 0x0000ff00) >>> 8);
527+
this._bufferBuilder.append(low & 0x000000ff);
556528
}
557529
}

0 commit comments

Comments
 (0)