msgpackr 1.4.6 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -3
- package/dist/index.js +95 -15
- package/dist/index.min.js +56 -53
- package/dist/node.cjs +96 -18
- package/dist/str.cjs +100 -0
- package/dist/test.js +33 -3
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/node-index.js +2 -4
- package/pack.js +43 -6
- package/package.json +7 -1
- package/unpack.d.ts +3 -0
- package/unpack.js +52 -11
- package/.vscode/launch.json +0 -23
- package/tests/benchmark-stream.cjs +0 -282
- package/tests/benchmark.cjs +0 -199
- package/tests/example.json +0 -52
- package/tests/example2.json +0 -26
- package/tests/example3.json +0 -22
- package/tests/example4.json +0 -1
- package/tests/example5.json +0 -12
- package/tests/floats.json +0 -1
- package/tests/index.html +0 -28
- package/tests/sample-large.json +0 -231
- package/tests/strings2.json +0 -1
- package/tests/test-compatibility.cjs +0 -64
- package/tests/test-incomplete.js +0 -41
- package/tests/test-node-iterators.js +0 -72
- package/tests/test-node-stream.js +0 -76
- package/tests/test.js +0 -633
package/dist/node.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var currentStructures;
|
|
|
20
20
|
var srcString;
|
|
21
21
|
var srcStringStart = 0;
|
|
22
22
|
var srcStringEnd = 0;
|
|
23
|
+
var bundledStrings;
|
|
23
24
|
var referenceMap;
|
|
24
25
|
var currentExtensions = [];
|
|
25
26
|
var dataView;
|
|
@@ -60,12 +61,21 @@ class Unpackr {
|
|
|
60
61
|
srcStringEnd = 0;
|
|
61
62
|
srcString = null;
|
|
62
63
|
strings = EMPTY_ARRAY;
|
|
64
|
+
bundledStrings = null;
|
|
63
65
|
src = source;
|
|
64
66
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
65
67
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
66
68
|
// new ones
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
try {
|
|
70
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
|
|
71
|
+
} catch(error) {
|
|
72
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
73
|
+
src = null;
|
|
74
|
+
if (source instanceof Uint8Array)
|
|
75
|
+
throw error
|
|
76
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
77
|
+
}
|
|
78
|
+
if (this instanceof Unpackr) {
|
|
69
79
|
currentUnpackr = this;
|
|
70
80
|
if (this.structures) {
|
|
71
81
|
currentStructures = this.structures;
|
|
@@ -242,7 +252,15 @@ function read() {
|
|
|
242
252
|
let value;
|
|
243
253
|
switch (token) {
|
|
244
254
|
case 0xc0: return null
|
|
245
|
-
case 0xc1:
|
|
255
|
+
case 0xc1:
|
|
256
|
+
if (bundledStrings) {
|
|
257
|
+
value = read(); // followed by the length of the string in characters (not bytes!)
|
|
258
|
+
if (value > 0)
|
|
259
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
260
|
+
else
|
|
261
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 -= value)
|
|
262
|
+
}
|
|
263
|
+
return C1; // "never-used", return special object to denote that
|
|
246
264
|
case 0xc2: return false
|
|
247
265
|
case 0xc3: return true
|
|
248
266
|
case 0xc4:
|
|
@@ -297,10 +315,11 @@ function read() {
|
|
|
297
315
|
position += 4;
|
|
298
316
|
return value
|
|
299
317
|
case 0xcf:
|
|
300
|
-
if (currentUnpackr.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
318
|
+
if (currentUnpackr.int64AsNumber) {
|
|
319
|
+
value = dataView.getUint32(position) * 0x100000000;
|
|
320
|
+
value += dataView.getUint32(position + 4);
|
|
321
|
+
} else
|
|
322
|
+
value = dataView.getBigUint64(position);
|
|
304
323
|
position += 8;
|
|
305
324
|
return value
|
|
306
325
|
|
|
@@ -316,7 +335,11 @@ function read() {
|
|
|
316
335
|
position += 4;
|
|
317
336
|
return value
|
|
318
337
|
case 0xd3:
|
|
319
|
-
|
|
338
|
+
if (currentUnpackr.int64AsNumber) {
|
|
339
|
+
value = dataView.getInt32(position) * 0x100000000;
|
|
340
|
+
value += dataView.getUint32(position + 4);
|
|
341
|
+
} else
|
|
342
|
+
value = dataView.getBigInt64(position);
|
|
320
343
|
position += 8;
|
|
321
344
|
return value
|
|
322
345
|
|
|
@@ -465,8 +488,10 @@ var readFixedString = readStringJS;
|
|
|
465
488
|
var readString8 = readStringJS;
|
|
466
489
|
var readString16 = readStringJS;
|
|
467
490
|
var readString32 = readStringJS;
|
|
491
|
+
exports.isNativeAccelerationEnabled = false;
|
|
468
492
|
|
|
469
493
|
function setExtractor(extractStrings) {
|
|
494
|
+
exports.isNativeAccelerationEnabled = true;
|
|
470
495
|
readFixedString = readString(1);
|
|
471
496
|
readString8 = readString(2);
|
|
472
497
|
readString16 = readString(3);
|
|
@@ -885,6 +910,22 @@ currentExtensions[0x78] = () => {
|
|
|
885
910
|
return new RegExp(data[0], data[1])
|
|
886
911
|
};
|
|
887
912
|
|
|
913
|
+
currentExtensions[0x62] = (data) => {
|
|
914
|
+
let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
|
|
915
|
+
let dataPosition = position;
|
|
916
|
+
position += dataSize - 4;
|
|
917
|
+
bundledStrings = [read(), read()];
|
|
918
|
+
bundledStrings.position0 = 0;
|
|
919
|
+
bundledStrings.position1 = 0;
|
|
920
|
+
let postBundlePosition = position;
|
|
921
|
+
position = dataPosition;
|
|
922
|
+
try {
|
|
923
|
+
return read()
|
|
924
|
+
} finally {
|
|
925
|
+
position = postBundlePosition;
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
|
|
888
929
|
currentExtensions[0xff] = (data) => {
|
|
889
930
|
// 32-bit date extension
|
|
890
931
|
if (data.length == 4)
|
|
@@ -898,7 +939,7 @@ currentExtensions[0xff] = (data) => {
|
|
|
898
939
|
((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
|
|
899
940
|
(((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
|
|
900
941
|
else
|
|
901
|
-
|
|
942
|
+
return new Date('invalid')
|
|
902
943
|
}; // notepack defines extension 0 to mean undefined, so use that as the default here
|
|
903
944
|
// registration of bulk record definition?
|
|
904
945
|
// currentExtensions[0x52] = () =>
|
|
@@ -912,6 +953,7 @@ function saveState(callback) {
|
|
|
912
953
|
let savedSrcString = srcString;
|
|
913
954
|
let savedStrings = strings;
|
|
914
955
|
let savedReferenceMap = referenceMap;
|
|
956
|
+
let savedBundledStrings = bundledStrings;
|
|
915
957
|
|
|
916
958
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
917
959
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
@@ -928,6 +970,7 @@ function saveState(callback) {
|
|
|
928
970
|
srcString = savedSrcString;
|
|
929
971
|
strings = savedStrings;
|
|
930
972
|
referenceMap = savedReferenceMap;
|
|
973
|
+
bundledStrings = savedBundledStrings;
|
|
931
974
|
src = savedSrc;
|
|
932
975
|
sequentialMode = savedSequentialMode;
|
|
933
976
|
currentStructures = savedStructures;
|
|
@@ -985,6 +1028,8 @@ let target;
|
|
|
985
1028
|
let targetView;
|
|
986
1029
|
let position$1 = 0;
|
|
987
1030
|
let safeEnd;
|
|
1031
|
+
let bundledStrings$1 = null;
|
|
1032
|
+
const hasNonLatin = /[\u0080-\uFFFF]/;
|
|
988
1033
|
const RECORD_SYMBOL = Symbol('record-id');
|
|
989
1034
|
class Packr extends Unpackr {
|
|
990
1035
|
constructor(options) {
|
|
@@ -1046,6 +1091,14 @@ class Packr extends Unpackr {
|
|
|
1046
1091
|
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
1047
1092
|
start = position$1;
|
|
1048
1093
|
referenceMap = packr.structuredClone ? new Map() : null;
|
|
1094
|
+
if (packr.bundleStrings) {
|
|
1095
|
+
bundledStrings$1 = ['', ''];
|
|
1096
|
+
target[position$1++] = 0xd6;
|
|
1097
|
+
target[position$1++] = 0x62; // 'b'
|
|
1098
|
+
bundledStrings$1.position = position$1 - start;
|
|
1099
|
+
position$1 += 4;
|
|
1100
|
+
} else
|
|
1101
|
+
bundledStrings$1 = null;
|
|
1049
1102
|
sharedStructures = packr.structures;
|
|
1050
1103
|
if (sharedStructures) {
|
|
1051
1104
|
if (sharedStructures.uninitialized)
|
|
@@ -1084,6 +1137,13 @@ class Packr extends Unpackr {
|
|
|
1084
1137
|
structures = sharedStructures || [];
|
|
1085
1138
|
try {
|
|
1086
1139
|
pack(value);
|
|
1140
|
+
if (bundledStrings$1) {
|
|
1141
|
+
targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
|
|
1142
|
+
let writeStrings = bundledStrings$1;
|
|
1143
|
+
bundledStrings$1 = null;
|
|
1144
|
+
pack(writeStrings[0]);
|
|
1145
|
+
pack(writeStrings[1]);
|
|
1146
|
+
}
|
|
1087
1147
|
packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
1088
1148
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
1089
1149
|
position$1 += referenceMap.idsToInsert.length * 6;
|
|
@@ -1094,7 +1154,7 @@ class Packr extends Unpackr {
|
|
|
1094
1154
|
referenceMap = null;
|
|
1095
1155
|
return serialized
|
|
1096
1156
|
}
|
|
1097
|
-
if (encodeOptions
|
|
1157
|
+
if (encodeOptions & REUSE_BUFFER_MODE) {
|
|
1098
1158
|
target.start = start;
|
|
1099
1159
|
target.end = position$1;
|
|
1100
1160
|
return target
|
|
@@ -1133,6 +1193,8 @@ class Packr extends Unpackr {
|
|
|
1133
1193
|
return returnBuffer
|
|
1134
1194
|
}
|
|
1135
1195
|
}
|
|
1196
|
+
if (encodeOptions & RESET_BUFFER_MODE)
|
|
1197
|
+
position$1 = start;
|
|
1136
1198
|
}
|
|
1137
1199
|
};
|
|
1138
1200
|
const pack = (value) => {
|
|
@@ -1143,13 +1205,20 @@ class Packr extends Unpackr {
|
|
|
1143
1205
|
var length;
|
|
1144
1206
|
if (type === 'string') {
|
|
1145
1207
|
let strLength = value.length;
|
|
1208
|
+
if (bundledStrings$1 && strLength >= 8 && strLength < 0x1000) {
|
|
1209
|
+
let twoByte = hasNonLatin.test(value);
|
|
1210
|
+
bundledStrings$1[twoByte ? 0 : 1] += value;
|
|
1211
|
+
target[position$1++] = 0xc1;
|
|
1212
|
+
pack(twoByte ? -strLength : strLength);
|
|
1213
|
+
return
|
|
1214
|
+
}
|
|
1146
1215
|
let headerSize;
|
|
1147
1216
|
// first we estimate the header size, so we can write to the correct location
|
|
1148
1217
|
if (strLength < 0x20) {
|
|
1149
1218
|
headerSize = 1;
|
|
1150
|
-
} else if (strLength <
|
|
1219
|
+
} else if (strLength < 0x100) {
|
|
1151
1220
|
headerSize = 2;
|
|
1152
|
-
} else if (strLength <
|
|
1221
|
+
} else if (strLength < 0x10000) {
|
|
1153
1222
|
headerSize = 3;
|
|
1154
1223
|
} else {
|
|
1155
1224
|
headerSize = 5;
|
|
@@ -1562,7 +1631,7 @@ class Packr extends Unpackr {
|
|
|
1562
1631
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
1563
1632
|
throw new Error('Packed buffer would be larger than maximum buffer size')
|
|
1564
1633
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
1565
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
1634
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
|
|
1566
1635
|
} else // faster handling for smaller buffers
|
|
1567
1636
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
|
|
1568
1637
|
let newBuffer = new ByteArrayAllocate(newSize);
|
|
@@ -1587,7 +1656,7 @@ class Packr extends Unpackr {
|
|
|
1587
1656
|
|
|
1588
1657
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
|
|
1589
1658
|
extensions = [{
|
|
1590
|
-
pack(date, allocateForWrite) {
|
|
1659
|
+
pack(date, allocateForWrite, pack) {
|
|
1591
1660
|
let seconds = date.getTime() / 1000;
|
|
1592
1661
|
if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
|
|
1593
1662
|
// Timestamp 32
|
|
@@ -1602,6 +1671,16 @@ extensions = [{
|
|
|
1602
1671
|
target[position++] = 0xff;
|
|
1603
1672
|
targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0));
|
|
1604
1673
|
targetView.setUint32(position + 4, seconds);
|
|
1674
|
+
} else if (isNaN(seconds)) {
|
|
1675
|
+
if (this.onInvalidDate) {
|
|
1676
|
+
allocateForWrite(0);
|
|
1677
|
+
return pack(this.onInvalidDate())
|
|
1678
|
+
}
|
|
1679
|
+
// Intentionally invalid timestamp
|
|
1680
|
+
let { target, targetView, position} = allocateForWrite(3);
|
|
1681
|
+
target[position++] = 0xd4;
|
|
1682
|
+
target[position++] = 0xff;
|
|
1683
|
+
target[position++] = 0xff;
|
|
1605
1684
|
} else {
|
|
1606
1685
|
// Timestamp 96
|
|
1607
1686
|
let { target, targetView, position} = allocateForWrite(15);
|
|
@@ -1787,7 +1866,8 @@ const pack = defaultPackr.pack;
|
|
|
1787
1866
|
const encode = defaultPackr.pack;
|
|
1788
1867
|
const Encoder = Packr;
|
|
1789
1868
|
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1790
|
-
const REUSE_BUFFER_MODE =
|
|
1869
|
+
const REUSE_BUFFER_MODE = 512;
|
|
1870
|
+
const RESET_BUFFER_MODE = 1024;
|
|
1791
1871
|
|
|
1792
1872
|
class PackrStream extends stream.Transform {
|
|
1793
1873
|
constructor(options) {
|
|
@@ -1939,9 +2019,7 @@ function tryRequire(moduleId) {
|
|
|
1939
2019
|
let require$1 = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('node.cjs', document.baseURI).href)));
|
|
1940
2020
|
return require$1(moduleId)
|
|
1941
2021
|
} catch (error) {
|
|
1942
|
-
if (typeof window
|
|
1943
|
-
console.warn('Native extraction module not loaded, msgpackr will still run, but with decreased performance. ' + error.message.split('\n')[0]);
|
|
1944
|
-
else
|
|
2022
|
+
if (typeof window != 'undefined')
|
|
1945
2023
|
console.warn('For browser usage, directly use msgpackr/unpack or msgpackr/pack modules. ' + error.message.split('\n')[0]);
|
|
1946
2024
|
}
|
|
1947
2025
|
}
|
package/dist/str.cjs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
let utfz = require('../../msgpack-benchmark/node_modules/utfz-lib')
|
|
2
|
+
|
|
3
|
+
var safeEnd = 1000000;
|
|
4
|
+
var b = new Uint8Array(32768)
|
|
5
|
+
function writeString(value, target, position) {
|
|
6
|
+
var length, strLength = value.length;
|
|
7
|
+
let headerSize;
|
|
8
|
+
// first we estimate the header size, so we can write to the correct location
|
|
9
|
+
if (strLength < 0x20) {
|
|
10
|
+
headerSize = 1;
|
|
11
|
+
} else if (strLength < 0x100) {
|
|
12
|
+
headerSize = 2;
|
|
13
|
+
} else if (strLength < 0x10000) {
|
|
14
|
+
headerSize = 3;
|
|
15
|
+
} else {
|
|
16
|
+
headerSize = 5;
|
|
17
|
+
}
|
|
18
|
+
let maxBytes = strLength * 3;
|
|
19
|
+
//if (position + maxBytes > safeEnd)
|
|
20
|
+
// target = makeRoom(position + maxBytes);
|
|
21
|
+
for (let i = 0; i < 100; i++) {
|
|
22
|
+
length = pack(value, strLength, target, position + headerSize);
|
|
23
|
+
}
|
|
24
|
+
if (strLength < 0x40 || !encodeUtf8) {
|
|
25
|
+
var strPosition = position + headerSize;
|
|
26
|
+
var c2 = 0;
|
|
27
|
+
for (let i = 0; i < strLength; i++) {
|
|
28
|
+
const c1 = value.charCodeAt(i);
|
|
29
|
+
if (c1 < 0x80) {
|
|
30
|
+
target[strPosition++] = c1;
|
|
31
|
+
} else if (c1 < 0x800) {
|
|
32
|
+
target[strPosition++] = c1 >> 6 | 0xc0;
|
|
33
|
+
target[strPosition++] = c1 & 0x3f | 0x80;
|
|
34
|
+
} else if (
|
|
35
|
+
(c1 & 0xfc00) === 0xd800 &&
|
|
36
|
+
((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
|
|
37
|
+
) {
|
|
38
|
+
c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
|
|
39
|
+
i++;
|
|
40
|
+
target[strPosition++] = c1 >> 18 | 0xf0;
|
|
41
|
+
target[strPosition++] = c1 >> 12 & 0x3f | 0x80;
|
|
42
|
+
target[strPosition++] = c1 >> 6 & 0x3f | 0x80;
|
|
43
|
+
target[strPosition++] = c1 & 0x3f | 0x80;
|
|
44
|
+
} else {
|
|
45
|
+
target[strPosition++] = c1 >> 12 | 0xe0;
|
|
46
|
+
target[strPosition++] = c1 >> 6 & 0x3f | 0x80;
|
|
47
|
+
target[strPosition++] = c1 & 0x3f | 0x80;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
length = strPosition - position - headerSize;
|
|
51
|
+
} else {
|
|
52
|
+
length = encodeUtf8(value, position + headerSize, maxBytes);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if (length < 0x20) {
|
|
57
|
+
target[position++] = 0xa0 | length;
|
|
58
|
+
} else if (length < 0x100) {
|
|
59
|
+
if (headerSize < 2) {
|
|
60
|
+
target.copyWithin(position + 2, position + 1, position + 1 + length);
|
|
61
|
+
}
|
|
62
|
+
target[position++] = 0xd9;
|
|
63
|
+
target[position++] = length;
|
|
64
|
+
} else if (length < 0x10000) {
|
|
65
|
+
if (headerSize < 3) {
|
|
66
|
+
target.copyWithin(position + 3, position + 2, position + 2 + length);
|
|
67
|
+
}
|
|
68
|
+
target[position++] = 0xda;
|
|
69
|
+
target[position++] = length >> 8;
|
|
70
|
+
target[position++] = length & 0xff;
|
|
71
|
+
} else {
|
|
72
|
+
if (headerSize < 5) {
|
|
73
|
+
target.copyWithin(position + 5, position + 3, position + 3 + length);
|
|
74
|
+
}
|
|
75
|
+
target[position++] = 0xdb;
|
|
76
|
+
targetView.setUint32(position, length);
|
|
77
|
+
position += 4;
|
|
78
|
+
}
|
|
79
|
+
return position + length
|
|
80
|
+
};
|
|
81
|
+
const pack = (str, length, buf, offset) => {
|
|
82
|
+
const start = offset;
|
|
83
|
+
let currHigh = 0;
|
|
84
|
+
for (let i = 0; i < length; i++) {
|
|
85
|
+
const code = str.charCodeAt(i);
|
|
86
|
+
const high = code >> 8;
|
|
87
|
+
if (high !== currHigh) {
|
|
88
|
+
buf[i + offset++] = 0;
|
|
89
|
+
buf[i + offset++] = high;
|
|
90
|
+
currHigh = high;
|
|
91
|
+
}
|
|
92
|
+
const low = code & 0xff;
|
|
93
|
+
buf[i + offset] = low;
|
|
94
|
+
if (!low) {
|
|
95
|
+
buf[i + ++offset] = currHigh;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return length + offset - start;
|
|
99
|
+
};
|
|
100
|
+
module.exports = writeString;
|
package/dist/test.js
CHANGED
|
@@ -660,6 +660,13 @@
|
|
|
660
660
|
assert.deepEqual(deserialized, data);
|
|
661
661
|
});
|
|
662
662
|
|
|
663
|
+
test('255 chars', function() {
|
|
664
|
+
const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W';
|
|
665
|
+
var serialized = pack(data);
|
|
666
|
+
var deserialized = unpack(serialized);
|
|
667
|
+
assert.equal(deserialized, data);
|
|
668
|
+
});
|
|
669
|
+
|
|
663
670
|
test('pack/unpack sample data', function(){
|
|
664
671
|
var data = sampleData;
|
|
665
672
|
var serialized = pack(data);
|
|
@@ -677,6 +684,14 @@
|
|
|
677
684
|
var deserialized = packr.unpack(serialized);
|
|
678
685
|
assert.deepEqual(deserialized, data);
|
|
679
686
|
});
|
|
687
|
+
test('pack/unpack sample data with bundled strings', function(){
|
|
688
|
+
var data = sampleData;
|
|
689
|
+
let structures = [];
|
|
690
|
+
let packr = new Packr({ structures, bundleStrings: true });
|
|
691
|
+
var serialized = packr.pack(data);
|
|
692
|
+
var deserialized = packr.unpack(serialized);
|
|
693
|
+
assert.deepEqual(deserialized, data);
|
|
694
|
+
});
|
|
680
695
|
if (typeof Buffer != 'undefined')
|
|
681
696
|
test('replace data', function(){
|
|
682
697
|
var data1 = {
|
|
@@ -982,6 +997,7 @@
|
|
|
982
997
|
date: new Date(1532219539733),
|
|
983
998
|
farFutureDate: new Date(3532219539133),
|
|
984
999
|
ancient: new Date(-3532219539133),
|
|
1000
|
+
invalidDate: new Date('invalid')
|
|
985
1001
|
};
|
|
986
1002
|
let packr = new Packr();
|
|
987
1003
|
var serialized = packr.pack(data);
|
|
@@ -991,6 +1007,7 @@
|
|
|
991
1007
|
assert.equal(deserialized.date.getTime(), 1532219539733);
|
|
992
1008
|
assert.equal(deserialized.farFutureDate.getTime(), 3532219539133);
|
|
993
1009
|
assert.equal(deserialized.ancient.getTime(), -3532219539133);
|
|
1010
|
+
assert.equal(deserialized.invalidDate.toString(), 'Invalid Date');
|
|
994
1011
|
});
|
|
995
1012
|
test('map/date with options', function(){
|
|
996
1013
|
var map = new Map();
|
|
@@ -1001,16 +1018,19 @@
|
|
|
1001
1018
|
var data = {
|
|
1002
1019
|
map: map,
|
|
1003
1020
|
date: new Date(1532219539011),
|
|
1021
|
+
invalidDate: new Date('invalid')
|
|
1004
1022
|
};
|
|
1005
1023
|
let packr = new Packr({
|
|
1006
1024
|
mapsAsObjects: true,
|
|
1007
1025
|
useTimestamp32: true,
|
|
1026
|
+
onInvalidDate: () => 'Custom invalid date'
|
|
1008
1027
|
});
|
|
1009
1028
|
var serialized = packr.pack(data);
|
|
1010
1029
|
var deserialized = packr.unpack(serialized);
|
|
1011
1030
|
assert.equal(deserialized.map[4], 'four');
|
|
1012
1031
|
assert.equal(deserialized.map.three, 3);
|
|
1013
1032
|
assert.equal(deserialized.date.getTime(), 1532219539000);
|
|
1033
|
+
assert.equal(deserialized.invalidDate, 'Custom invalid date');
|
|
1014
1034
|
});
|
|
1015
1035
|
test('key caching', function() {
|
|
1016
1036
|
var data = {
|
|
@@ -1064,7 +1084,17 @@
|
|
|
1064
1084
|
var deserialized = packr.unpack(serialized);
|
|
1065
1085
|
assert.deepEqual(deserialized, data);
|
|
1066
1086
|
});
|
|
1067
|
-
|
|
1087
|
+
test('bigint to float', function() {
|
|
1088
|
+
var data = {
|
|
1089
|
+
a: 325283295382932843n
|
|
1090
|
+
};
|
|
1091
|
+
let packr = new Packr({
|
|
1092
|
+
int64AsNumber: true
|
|
1093
|
+
});
|
|
1094
|
+
var serialized = packr.pack(data);
|
|
1095
|
+
var deserialized = packr.unpack(serialized);
|
|
1096
|
+
assert.deepEqual(deserialized.a, 325283295382932843);
|
|
1097
|
+
});
|
|
1068
1098
|
test('numbers', function(){
|
|
1069
1099
|
var data = {
|
|
1070
1100
|
bigEncodable: 48978578104322,
|
|
@@ -1180,7 +1210,7 @@
|
|
|
1180
1210
|
let structures = [];
|
|
1181
1211
|
var serialized = pack(data);
|
|
1182
1212
|
console.log('MessagePack size', serialized.length);
|
|
1183
|
-
let packr = new Packr({ structures });
|
|
1213
|
+
let packr = new Packr({ structures, bundleStrings: false });
|
|
1184
1214
|
var serialized = packr.pack(data);
|
|
1185
1215
|
console.log('msgpackr w/ record ext size', serialized.length);
|
|
1186
1216
|
for (var i = 0; i < ITERATIONS; i++) {
|
|
@@ -1191,7 +1221,7 @@
|
|
|
1191
1221
|
var data = sampleData;
|
|
1192
1222
|
this.timeout(10000);
|
|
1193
1223
|
let structures = [];
|
|
1194
|
-
let packr = new Packr({ structures });
|
|
1224
|
+
let packr = new Packr({ structures, bundleStrings: false });
|
|
1195
1225
|
let buffer = typeof Buffer != 'undefined' ? Buffer.alloc(0x10000) : new Uint8Array(0x10000);
|
|
1196
1226
|
|
|
1197
1227
|
for (var i = 0; i < ITERATIONS; i++) {
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Unpackr, Decoder, unpack, decode, addExtension, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './unpack'
|
|
1
|
+
export { Unpackr, Decoder, unpack, decode, addExtension, FLOAT32_OPTIONS, clearSource, roundFloat32, isNativeAccelerationEnabled } from './unpack'
|
|
2
2
|
import { Options } from './unpack'
|
|
3
3
|
export { Packr, Encoder, pack, encode } from './pack'
|
|
4
4
|
import { Transform, Readable } from 'stream'
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT, REUSE_BUFFER_MODE } from './pack.js'
|
|
2
|
-
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './unpack.js'
|
|
2
|
+
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32, isNativeAccelerationEnabled } from './unpack.js'
|
|
3
3
|
export { decodeIter, encodeIter } from './iterators.js'
|
|
4
4
|
export const useRecords = false
|
|
5
5
|
export const mapsAsObjects = true
|
package/node-index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './pack.js'
|
|
2
|
-
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './unpack.js'
|
|
2
|
+
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32, isNativeAccelerationEnabled } from './unpack.js'
|
|
3
3
|
export { PackrStream, UnpackrStream, PackrStream as EncoderStream, UnpackrStream as DecoderStream } from './stream.js'
|
|
4
4
|
export { decodeIter, encodeIter } from './iterators.js'
|
|
5
5
|
export const useRecords = false
|
|
@@ -16,9 +16,7 @@ function tryRequire(moduleId) {
|
|
|
16
16
|
let require = createRequire(import.meta.url)
|
|
17
17
|
return require(moduleId)
|
|
18
18
|
} catch (error) {
|
|
19
|
-
if (typeof window
|
|
20
|
-
console.warn('Native extraction module not loaded, msgpackr will still run, but with decreased performance. ' + error.message.split('\n')[0])
|
|
21
|
-
else
|
|
19
|
+
if (typeof window != 'undefined')
|
|
22
20
|
console.warn('For browser usage, directly use msgpackr/unpack or msgpackr/pack modules. ' + error.message.split('\n')[0])
|
|
23
21
|
}
|
|
24
22
|
}
|
package/pack.js
CHANGED
|
@@ -13,6 +13,8 @@ let target
|
|
|
13
13
|
let targetView
|
|
14
14
|
let position = 0
|
|
15
15
|
let safeEnd
|
|
16
|
+
let bundledStrings = null
|
|
17
|
+
const hasNonLatin = /[\u0080-\uFFFF]/
|
|
16
18
|
const RECORD_SYMBOL = Symbol('record-id')
|
|
17
19
|
export class Packr extends Unpackr {
|
|
18
20
|
constructor(options) {
|
|
@@ -75,6 +77,14 @@ export class Packr extends Unpackr {
|
|
|
75
77
|
position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster
|
|
76
78
|
start = position
|
|
77
79
|
referenceMap = packr.structuredClone ? new Map() : null
|
|
80
|
+
if (packr.bundleStrings) {
|
|
81
|
+
bundledStrings = ['', '']
|
|
82
|
+
target[position++] = 0xd6
|
|
83
|
+
target[position++] = 0x62 // 'b'
|
|
84
|
+
bundledStrings.position = position - start
|
|
85
|
+
position += 4
|
|
86
|
+
} else
|
|
87
|
+
bundledStrings = null
|
|
78
88
|
sharedStructures = packr.structures
|
|
79
89
|
if (sharedStructures) {
|
|
80
90
|
if (sharedStructures.uninitialized)
|
|
@@ -113,6 +123,13 @@ export class Packr extends Unpackr {
|
|
|
113
123
|
structures = sharedStructures || []
|
|
114
124
|
try {
|
|
115
125
|
pack(value)
|
|
126
|
+
if (bundledStrings) {
|
|
127
|
+
targetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start)
|
|
128
|
+
let writeStrings = bundledStrings
|
|
129
|
+
bundledStrings = null
|
|
130
|
+
pack(writeStrings[0])
|
|
131
|
+
pack(writeStrings[1])
|
|
132
|
+
}
|
|
116
133
|
packr.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
117
134
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
118
135
|
position += referenceMap.idsToInsert.length * 6
|
|
@@ -123,7 +140,7 @@ export class Packr extends Unpackr {
|
|
|
123
140
|
referenceMap = null
|
|
124
141
|
return serialized
|
|
125
142
|
}
|
|
126
|
-
if (encodeOptions
|
|
143
|
+
if (encodeOptions & REUSE_BUFFER_MODE) {
|
|
127
144
|
target.start = start
|
|
128
145
|
target.end = position
|
|
129
146
|
return target
|
|
@@ -162,6 +179,8 @@ export class Packr extends Unpackr {
|
|
|
162
179
|
return returnBuffer
|
|
163
180
|
}
|
|
164
181
|
}
|
|
182
|
+
if (encodeOptions & RESET_BUFFER_MODE)
|
|
183
|
+
position = start
|
|
165
184
|
}
|
|
166
185
|
}
|
|
167
186
|
const pack = (value) => {
|
|
@@ -172,13 +191,20 @@ export class Packr extends Unpackr {
|
|
|
172
191
|
var length
|
|
173
192
|
if (type === 'string') {
|
|
174
193
|
let strLength = value.length
|
|
194
|
+
if (bundledStrings && strLength >= 8 && strLength < 0x1000) {
|
|
195
|
+
let twoByte = hasNonLatin.test(value)
|
|
196
|
+
bundledStrings[twoByte ? 0 : 1] += value
|
|
197
|
+
target[position++] = 0xc1
|
|
198
|
+
pack(twoByte ? -strLength : strLength);
|
|
199
|
+
return
|
|
200
|
+
}
|
|
175
201
|
let headerSize
|
|
176
202
|
// first we estimate the header size, so we can write to the correct location
|
|
177
203
|
if (strLength < 0x20) {
|
|
178
204
|
headerSize = 1
|
|
179
|
-
} else if (strLength <
|
|
205
|
+
} else if (strLength < 0x100) {
|
|
180
206
|
headerSize = 2
|
|
181
|
-
} else if (strLength <
|
|
207
|
+
} else if (strLength < 0x10000) {
|
|
182
208
|
headerSize = 3
|
|
183
209
|
} else {
|
|
184
210
|
headerSize = 5
|
|
@@ -591,7 +617,7 @@ export class Packr extends Unpackr {
|
|
|
591
617
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
592
618
|
throw new Error('Packed buffer would be larger than maximum buffer size')
|
|
593
619
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
594
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
620
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000)
|
|
595
621
|
} else // faster handling for smaller buffers
|
|
596
622
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12
|
|
597
623
|
let newBuffer = new ByteArrayAllocate(newSize)
|
|
@@ -622,7 +648,7 @@ function copyBinary(source, target, targetOffset, offset, endOffset) {
|
|
|
622
648
|
|
|
623
649
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ]
|
|
624
650
|
extensions = [{
|
|
625
|
-
pack(date, allocateForWrite) {
|
|
651
|
+
pack(date, allocateForWrite, pack) {
|
|
626
652
|
let seconds = date.getTime() / 1000
|
|
627
653
|
if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
|
|
628
654
|
// Timestamp 32
|
|
@@ -637,6 +663,16 @@ extensions = [{
|
|
|
637
663
|
target[position++] = 0xff
|
|
638
664
|
targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0))
|
|
639
665
|
targetView.setUint32(position + 4, seconds)
|
|
666
|
+
} else if (isNaN(seconds)) {
|
|
667
|
+
if (this.onInvalidDate) {
|
|
668
|
+
allocateForWrite(0)
|
|
669
|
+
return pack(this.onInvalidDate())
|
|
670
|
+
}
|
|
671
|
+
// Intentionally invalid timestamp
|
|
672
|
+
let { target, targetView, position} = allocateForWrite(3)
|
|
673
|
+
target[position++] = 0xd4
|
|
674
|
+
target[position++] = 0xff
|
|
675
|
+
target[position++] = 0xff
|
|
640
676
|
} else {
|
|
641
677
|
// Timestamp 96
|
|
642
678
|
let { target, targetView, position} = allocateForWrite(15)
|
|
@@ -824,4 +860,5 @@ export const Encoder = Packr
|
|
|
824
860
|
export { FLOAT32_OPTIONS } from './unpack.js'
|
|
825
861
|
import { FLOAT32_OPTIONS } from './unpack.js'
|
|
826
862
|
export const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS
|
|
827
|
-
export const REUSE_BUFFER_MODE =
|
|
863
|
+
export const REUSE_BUFFER_MODE = 512
|
|
864
|
+
export const RESET_BUFFER_MODE = 1024
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msgpackr",
|
|
3
3
|
"author": "Kris Zyp",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.2",
|
|
5
5
|
"description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"types": "./index.d.ts",
|
|
@@ -49,6 +49,12 @@
|
|
|
49
49
|
"default": "./unpack.js"
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
|
+
"files": [
|
|
53
|
+
"/dist",
|
|
54
|
+
"*.md",
|
|
55
|
+
"/*.js",
|
|
56
|
+
"/*.ts"
|
|
57
|
+
],
|
|
52
58
|
"optionalDependencies": {
|
|
53
59
|
"msgpackr-extract": "^1.0.14"
|
|
54
60
|
},
|
package/unpack.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface Options {
|
|
|
13
13
|
mapsAsObjects?: boolean
|
|
14
14
|
variableMapSize?: boolean
|
|
15
15
|
copyBuffers?: boolean
|
|
16
|
+
bundleStrings?: boolean
|
|
16
17
|
useTimestamp32?: boolean
|
|
17
18
|
largeBigIntToFloat?: boolean
|
|
18
19
|
encodeUndefinedAsNil?: boolean
|
|
@@ -21,6 +22,7 @@ export interface Options {
|
|
|
21
22
|
shouldShareStructure?: (keys: string[]) => boolean
|
|
22
23
|
getStructures?(): {}[]
|
|
23
24
|
saveStructures?(structures: {}[]): boolean | void
|
|
25
|
+
onInvalidDate?: () => any
|
|
24
26
|
}
|
|
25
27
|
interface Extension {
|
|
26
28
|
Class: Function
|
|
@@ -44,3 +46,4 @@ export function addExtension(extension: Extension): void
|
|
|
44
46
|
export function clearSource(): void
|
|
45
47
|
export function roundFloat32(float32Number: number): number
|
|
46
48
|
export const C1: {}
|
|
49
|
+
export let isNativeAccelerationEnabled: boolean
|