msgpackr 1.5.0 → 1.5.4
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 +4 -1
- package/dist/index.js +271 -113
- package/dist/index.min.js +66 -100
- package/dist/node.cjs +273 -113
- package/dist/str.cjs +100 -0
- package/dist/test.js +33 -2
- package/pack.js +206 -105
- package/package.json +7 -1
- package/unpack.d.ts +2 -0
- package/unpack.js +62 -2
- 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 -650
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,6 +61,7 @@ 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
|
|
@@ -156,6 +158,9 @@ function checkedRead() {
|
|
|
156
158
|
currentStructures.length = sharedLength;
|
|
157
159
|
}
|
|
158
160
|
let result = read();
|
|
161
|
+
if (bundledStrings) // bundled strings to skip past
|
|
162
|
+
position = bundledStrings.postBundlePosition;
|
|
163
|
+
|
|
159
164
|
if (position == srcEnd) {
|
|
160
165
|
// finished reading this source, cleanup references
|
|
161
166
|
if (currentStructures.restoreStructures)
|
|
@@ -250,7 +255,15 @@ function read() {
|
|
|
250
255
|
let value;
|
|
251
256
|
switch (token) {
|
|
252
257
|
case 0xc0: return null
|
|
253
|
-
case 0xc1:
|
|
258
|
+
case 0xc1:
|
|
259
|
+
if (bundledStrings) {
|
|
260
|
+
value = read(); // followed by the length of the string in characters (not bytes!)
|
|
261
|
+
if (value > 0)
|
|
262
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
263
|
+
else
|
|
264
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 -= value)
|
|
265
|
+
}
|
|
266
|
+
return C1; // "never-used", return special object to denote that
|
|
254
267
|
case 0xc2: return false
|
|
255
268
|
case 0xc3: return true
|
|
256
269
|
case 0xc4:
|
|
@@ -490,6 +503,8 @@ function setExtractor(extractStrings) {
|
|
|
490
503
|
return function readString(length) {
|
|
491
504
|
let string = strings[stringPosition++];
|
|
492
505
|
if (string == null) {
|
|
506
|
+
if (bundledStrings)
|
|
507
|
+
return readStringJS(length)
|
|
493
508
|
let extraction = extractStrings(position - headerLength, srcEnd, src);
|
|
494
509
|
if (typeof extraction == 'string') {
|
|
495
510
|
string = extraction;
|
|
@@ -748,6 +763,36 @@ function shortStringInJS(length) {
|
|
|
748
763
|
}
|
|
749
764
|
}
|
|
750
765
|
|
|
766
|
+
function readOnlyJSString() {
|
|
767
|
+
let token = src[position++];
|
|
768
|
+
let length;
|
|
769
|
+
if (token < 0xc0) {
|
|
770
|
+
// fixstr
|
|
771
|
+
length = token - 0xa0;
|
|
772
|
+
} else {
|
|
773
|
+
switch(token) {
|
|
774
|
+
case 0xd9:
|
|
775
|
+
// str 8
|
|
776
|
+
length = src[position++];
|
|
777
|
+
break
|
|
778
|
+
case 0xda:
|
|
779
|
+
// str 16
|
|
780
|
+
length = dataView.getUint16(position);
|
|
781
|
+
position += 2;
|
|
782
|
+
break
|
|
783
|
+
case 0xdb:
|
|
784
|
+
// str 32
|
|
785
|
+
length = dataView.getUint32(position);
|
|
786
|
+
position += 4;
|
|
787
|
+
break
|
|
788
|
+
default:
|
|
789
|
+
throw new Error('Expected string')
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return readStringJS(length)
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
|
|
751
796
|
function readBin(length) {
|
|
752
797
|
return currentUnpackr.copyBuffers ?
|
|
753
798
|
// specifically use the copying slice (not the node one)
|
|
@@ -899,6 +944,19 @@ currentExtensions[0x78] = () => {
|
|
|
899
944
|
let data = read();
|
|
900
945
|
return new RegExp(data[0], data[1])
|
|
901
946
|
};
|
|
947
|
+
const TEMP_BUNDLE = [];
|
|
948
|
+
currentExtensions[0x62] = (data) => {
|
|
949
|
+
let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
|
|
950
|
+
let dataPosition = position;
|
|
951
|
+
position += dataSize - data.length;
|
|
952
|
+
bundledStrings = TEMP_BUNDLE;
|
|
953
|
+
bundledStrings = [readOnlyJSString(), readOnlyJSString()];
|
|
954
|
+
bundledStrings.position0 = 0;
|
|
955
|
+
bundledStrings.position1 = 0;
|
|
956
|
+
bundledStrings.postBundlePosition = position;
|
|
957
|
+
position = dataPosition;
|
|
958
|
+
return read()
|
|
959
|
+
};
|
|
902
960
|
|
|
903
961
|
currentExtensions[0xff] = (data) => {
|
|
904
962
|
// 32-bit date extension
|
|
@@ -913,7 +971,7 @@ currentExtensions[0xff] = (data) => {
|
|
|
913
971
|
((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
|
|
914
972
|
(((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
|
|
915
973
|
else
|
|
916
|
-
|
|
974
|
+
return new Date('invalid')
|
|
917
975
|
}; // notepack defines extension 0 to mean undefined, so use that as the default here
|
|
918
976
|
// registration of bulk record definition?
|
|
919
977
|
// currentExtensions[0x52] = () =>
|
|
@@ -927,6 +985,7 @@ function saveState(callback) {
|
|
|
927
985
|
let savedSrcString = srcString;
|
|
928
986
|
let savedStrings = strings;
|
|
929
987
|
let savedReferenceMap = referenceMap;
|
|
988
|
+
let savedBundledStrings = bundledStrings;
|
|
930
989
|
|
|
931
990
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
932
991
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
@@ -943,6 +1002,7 @@ function saveState(callback) {
|
|
|
943
1002
|
srcString = savedSrcString;
|
|
944
1003
|
strings = savedStrings;
|
|
945
1004
|
referenceMap = savedReferenceMap;
|
|
1005
|
+
bundledStrings = savedBundledStrings;
|
|
946
1006
|
src = savedSrc;
|
|
947
1007
|
sequentialMode = savedSequentialMode;
|
|
948
1008
|
currentStructures = savedStructures;
|
|
@@ -996,17 +1056,19 @@ const hasNodeBuffer = typeof Buffer !== 'undefined';
|
|
|
996
1056
|
const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
|
|
997
1057
|
const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
|
|
998
1058
|
const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
|
|
999
|
-
let target;
|
|
1059
|
+
let target, keysTarget;
|
|
1000
1060
|
let targetView;
|
|
1001
1061
|
let position$1 = 0;
|
|
1002
1062
|
let safeEnd;
|
|
1063
|
+
let bundledStrings$1 = null;
|
|
1064
|
+
const MAX_BUNDLE_SIZE = 0xf000;
|
|
1065
|
+
const hasNonLatin = /[\u0080-\uFFFF]/;
|
|
1003
1066
|
const RECORD_SYMBOL = Symbol('record-id');
|
|
1004
1067
|
class Packr extends Unpackr {
|
|
1005
1068
|
constructor(options) {
|
|
1006
1069
|
super(options);
|
|
1007
1070
|
this.offset = 0;
|
|
1008
1071
|
let start;
|
|
1009
|
-
let sharedStructures;
|
|
1010
1072
|
let hasSharedUpdate;
|
|
1011
1073
|
let structures;
|
|
1012
1074
|
let referenceMap;
|
|
@@ -1031,7 +1093,7 @@ class Packr extends Unpackr {
|
|
|
1031
1093
|
let maxOwnStructures = options.maxOwnStructures;
|
|
1032
1094
|
if (maxOwnStructures == null)
|
|
1033
1095
|
maxOwnStructures = hasSharedStructures ? 32 : 64;
|
|
1034
|
-
if (
|
|
1096
|
+
if (!this.structures && options.useRecords != false)
|
|
1035
1097
|
this.structures = [];
|
|
1036
1098
|
// two byte record ids for shared structures
|
|
1037
1099
|
let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64);
|
|
@@ -1061,23 +1123,28 @@ class Packr extends Unpackr {
|
|
|
1061
1123
|
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
1062
1124
|
start = position$1;
|
|
1063
1125
|
referenceMap = packr.structuredClone ? new Map() : null;
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1126
|
+
if (packr.bundleStrings && typeof value !== 'string') {
|
|
1127
|
+
bundledStrings$1 = [];
|
|
1128
|
+
bundledStrings$1.size = Infinity; // force a new bundle start on first string
|
|
1129
|
+
} else
|
|
1130
|
+
bundledStrings$1 = null;
|
|
1131
|
+
structures = packr.structures;
|
|
1132
|
+
if (structures) {
|
|
1133
|
+
if (structures.uninitialized)
|
|
1134
|
+
structures = packr._mergeStructures(packr.getStructures());
|
|
1135
|
+
let sharedLength = structures.sharedLength || 0;
|
|
1069
1136
|
if (sharedLength > maxSharedStructures) {
|
|
1070
|
-
//if (maxSharedStructures <= 32 &&
|
|
1071
|
-
throw new Error('Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to ' +
|
|
1137
|
+
//if (maxSharedStructures <= 32 && structures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
|
|
1138
|
+
throw new Error('Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to ' + structures.sharedLength)
|
|
1072
1139
|
}
|
|
1073
|
-
if (!
|
|
1140
|
+
if (!structures.transitions) {
|
|
1074
1141
|
// rebuild our structure transitions
|
|
1075
|
-
|
|
1142
|
+
structures.transitions = Object.create(null);
|
|
1076
1143
|
for (let i = 0; i < sharedLength; i++) {
|
|
1077
|
-
let keys =
|
|
1144
|
+
let keys = structures[i];
|
|
1078
1145
|
if (!keys)
|
|
1079
1146
|
continue
|
|
1080
|
-
let nextTransition, transition =
|
|
1147
|
+
let nextTransition, transition = structures.transitions;
|
|
1081
1148
|
for (let j = 0, l = keys.length; j < l; j++) {
|
|
1082
1149
|
let key = keys[j];
|
|
1083
1150
|
nextTransition = transition[key];
|
|
@@ -1091,14 +1158,16 @@ class Packr extends Unpackr {
|
|
|
1091
1158
|
lastSharedStructuresLength = sharedLength;
|
|
1092
1159
|
}
|
|
1093
1160
|
if (!isSequential) {
|
|
1094
|
-
|
|
1161
|
+
structures.nextId = sharedLength + 0x40;
|
|
1095
1162
|
}
|
|
1096
1163
|
}
|
|
1097
1164
|
if (hasSharedUpdate)
|
|
1098
1165
|
hasSharedUpdate = false;
|
|
1099
|
-
structures = sharedStructures || [];
|
|
1100
1166
|
try {
|
|
1101
1167
|
pack(value);
|
|
1168
|
+
if (bundledStrings$1) {
|
|
1169
|
+
writeBundles(start, pack);
|
|
1170
|
+
}
|
|
1102
1171
|
packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
1103
1172
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
1104
1173
|
position$1 += referenceMap.idsToInsert.length * 6;
|
|
@@ -1109,19 +1178,22 @@ class Packr extends Unpackr {
|
|
|
1109
1178
|
referenceMap = null;
|
|
1110
1179
|
return serialized
|
|
1111
1180
|
}
|
|
1112
|
-
if (encodeOptions
|
|
1181
|
+
if (encodeOptions & REUSE_BUFFER_MODE) {
|
|
1113
1182
|
target.start = start;
|
|
1114
1183
|
target.end = position$1;
|
|
1115
1184
|
return target
|
|
1116
1185
|
}
|
|
1117
1186
|
return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
1118
1187
|
} finally {
|
|
1119
|
-
if (
|
|
1188
|
+
if (structures) {
|
|
1120
1189
|
if (serializationsSinceTransitionRebuild < 10)
|
|
1121
1190
|
serializationsSinceTransitionRebuild++;
|
|
1191
|
+
let sharedLength = structures.sharedLength || maxSharedStructures;
|
|
1192
|
+
if (structures.length > sharedLength)
|
|
1193
|
+
structures.length = sharedLength;
|
|
1122
1194
|
if (transitionsCount > 10000) {
|
|
1123
1195
|
// force a rebuild occasionally after a lot of transitions so it can get cleaned up
|
|
1124
|
-
|
|
1196
|
+
structures.transitions = null;
|
|
1125
1197
|
serializationsSinceTransitionRebuild = 0;
|
|
1126
1198
|
transitionsCount = 0;
|
|
1127
1199
|
if (recordIdsToRemove.length > 0)
|
|
@@ -1133,13 +1205,9 @@ class Packr extends Unpackr {
|
|
|
1133
1205
|
recordIdsToRemove = [];
|
|
1134
1206
|
}
|
|
1135
1207
|
if (hasSharedUpdate && packr.saveStructures) {
|
|
1136
|
-
let sharedLength = sharedStructures.sharedLength || maxSharedStructures;
|
|
1137
|
-
if (sharedStructures.length > sharedLength) {
|
|
1138
|
-
sharedStructures = sharedStructures.slice(0, sharedLength);
|
|
1139
|
-
}
|
|
1140
1208
|
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1141
1209
|
let returnBuffer = target.subarray(start, position$1);
|
|
1142
|
-
if (packr.saveStructures(
|
|
1210
|
+
if (packr.saveStructures(structures, lastSharedStructuresLength) === false) {
|
|
1143
1211
|
// get updated structures and try again if the update failed
|
|
1144
1212
|
packr._mergeStructures(packr.getStructures());
|
|
1145
1213
|
return packr.pack(value)
|
|
@@ -1148,6 +1216,8 @@ class Packr extends Unpackr {
|
|
|
1148
1216
|
return returnBuffer
|
|
1149
1217
|
}
|
|
1150
1218
|
}
|
|
1219
|
+
if (encodeOptions & RESET_BUFFER_MODE)
|
|
1220
|
+
position$1 = start;
|
|
1151
1221
|
}
|
|
1152
1222
|
};
|
|
1153
1223
|
const pack = (value) => {
|
|
@@ -1158,6 +1228,36 @@ class Packr extends Unpackr {
|
|
|
1158
1228
|
var length;
|
|
1159
1229
|
if (type === 'string') {
|
|
1160
1230
|
let strLength = value.length;
|
|
1231
|
+
if (bundledStrings$1 && strLength >= 4 && strLength < 0x1000) {
|
|
1232
|
+
if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
|
|
1233
|
+
let extStart;
|
|
1234
|
+
let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
|
|
1235
|
+
if (position$1 + maxBytes > safeEnd)
|
|
1236
|
+
target = makeRoom(position$1 + maxBytes);
|
|
1237
|
+
if (bundledStrings$1.position) { // here we use the 0x62 extension to write the last bundle and reserve sapce for the reference pointer to the next/current bundle
|
|
1238
|
+
target[position$1] = 0xc8; // ext 16
|
|
1239
|
+
position$1 += 3; // reserve for the writing bundle size
|
|
1240
|
+
target[position$1++] = 0x62; // 'b'
|
|
1241
|
+
extStart = position$1 - start;
|
|
1242
|
+
position$1 += 4; // reserve for writing bundle reference
|
|
1243
|
+
writeBundles(start, pack); // write the last bundles
|
|
1244
|
+
targetView.setUint16(extStart + start - 3, position$1 - start - extStart);
|
|
1245
|
+
} else { // here we use the 0x62 extension just to reserve the space for the reference pointer to the bundle (will be updated once the bundle is written)
|
|
1246
|
+
target[position$1++] = 0xd6; // fixext 4
|
|
1247
|
+
target[position$1++] = 0x62; // 'b'
|
|
1248
|
+
extStart = position$1 - start;
|
|
1249
|
+
position$1 += 4; // reserve for writing bundle reference
|
|
1250
|
+
}
|
|
1251
|
+
bundledStrings$1 = ['', '']; // create new ones
|
|
1252
|
+
bundledStrings$1.size = 0;
|
|
1253
|
+
bundledStrings$1.position = extStart;
|
|
1254
|
+
}
|
|
1255
|
+
let twoByte = hasNonLatin.test(value);
|
|
1256
|
+
bundledStrings$1[twoByte ? 0 : 1] += value;
|
|
1257
|
+
target[position$1++] = 0xc1;
|
|
1258
|
+
pack(twoByte ? -strLength : strLength);
|
|
1259
|
+
return
|
|
1260
|
+
}
|
|
1161
1261
|
let headerSize;
|
|
1162
1262
|
// first we estimate the header size, so we can write to the correct location
|
|
1163
1263
|
if (strLength < 0x20) {
|
|
@@ -1456,53 +1556,55 @@ class Packr extends Unpackr {
|
|
|
1456
1556
|
target[objectOffset++ + start] = size >> 8;
|
|
1457
1557
|
target[objectOffset + start] = size & 0xff;
|
|
1458
1558
|
} :
|
|
1459
|
-
|
|
1460
|
-
/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
|
|
1559
|
+
(options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
|
|
1461
1560
|
(object, safePrototype) => {
|
|
1462
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
|
|
1463
|
-
let objectOffset = position++ - start
|
|
1464
|
-
let wroteKeys
|
|
1561
|
+
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1562
|
+
let objectOffset = position$1++ - start;
|
|
1563
|
+
let wroteKeys;
|
|
1465
1564
|
for (let key in object) {
|
|
1466
1565
|
if (safePrototype || object.hasOwnProperty(key)) {
|
|
1467
|
-
nextTransition = transition[key]
|
|
1468
|
-
if (
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
let
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
nextTransition
|
|
1566
|
+
nextTransition = transition[key];
|
|
1567
|
+
if (nextTransition)
|
|
1568
|
+
transition = nextTransition;
|
|
1569
|
+
else {
|
|
1570
|
+
// record doesn't exist, create full new record and insert it
|
|
1571
|
+
let keys = Object.keys(object);
|
|
1572
|
+
let lastTransition = transition;
|
|
1573
|
+
transition = structures.transitions;
|
|
1574
|
+
let newTransitions = 0;
|
|
1575
|
+
for (let i = 0, l = keys.length; i < l; i++) {
|
|
1576
|
+
let key = keys[i];
|
|
1577
|
+
nextTransition = transition[key];
|
|
1578
|
+
if (!nextTransition) {
|
|
1579
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1580
|
+
newTransitions++;
|
|
1481
1581
|
}
|
|
1582
|
+
transition = nextTransition;
|
|
1482
1583
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1584
|
+
if (objectOffset + start + 1 == position$1) {
|
|
1585
|
+
// first key, so we don't need to insert, we can just write record directly
|
|
1586
|
+
position$1--;
|
|
1587
|
+
newRecord(transition, keys, newTransitions);
|
|
1588
|
+
} else // otherwise we need to insert the record, moving existing data after the record
|
|
1589
|
+
insertNewRecord(transition, keys, objectOffset, newTransitions);
|
|
1590
|
+
wroteKeys = true;
|
|
1591
|
+
transition = lastTransition[key];
|
|
1487
1592
|
}
|
|
1488
|
-
|
|
1489
|
-
pack(object[key])
|
|
1593
|
+
pack(object[key]);
|
|
1490
1594
|
}
|
|
1491
1595
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1596
|
+
if (!wroteKeys) {
|
|
1597
|
+
let recordId = transition[RECORD_SYMBOL];
|
|
1598
|
+
if (recordId)
|
|
1599
|
+
target[objectOffset + start] = recordId;
|
|
1600
|
+
else
|
|
1601
|
+
insertNewRecord(transition, Object.keys(object), objectOffset, 0);
|
|
1497
1602
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
(object) => {
|
|
1501
|
-
let keys = Object.keys(object);
|
|
1603
|
+
} :
|
|
1604
|
+
(object, safePrototype) => {
|
|
1502
1605
|
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1503
1606
|
let newTransitions = 0;
|
|
1504
|
-
for (let
|
|
1505
|
-
let key = keys[i];
|
|
1607
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1506
1608
|
nextTransition = transition[key];
|
|
1507
1609
|
if (!nextTransition) {
|
|
1508
1610
|
nextTransition = transition[key] = Object.create(null);
|
|
@@ -1518,57 +1620,12 @@ class Packr extends Unpackr {
|
|
|
1518
1620
|
} else
|
|
1519
1621
|
target[position$1++] = recordId;
|
|
1520
1622
|
} else {
|
|
1521
|
-
|
|
1522
|
-
if (!recordId)
|
|
1523
|
-
recordId = 0x40;
|
|
1524
|
-
if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
|
|
1525
|
-
recordId = structures.nextOwnId;
|
|
1526
|
-
if (!(recordId < maxStructureId))
|
|
1527
|
-
recordId = sharedLimitId;
|
|
1528
|
-
structures.nextOwnId = recordId + 1;
|
|
1529
|
-
} else {
|
|
1530
|
-
if (recordId >= maxStructureId)// cycle back around
|
|
1531
|
-
recordId = sharedLimitId;
|
|
1532
|
-
structures.nextId = recordId + 1;
|
|
1533
|
-
}
|
|
1534
|
-
let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1;
|
|
1535
|
-
transition[RECORD_SYMBOL] = recordId;
|
|
1536
|
-
structures[recordId - 0x40] = keys;
|
|
1537
|
-
|
|
1538
|
-
if (recordId < sharedLimitId) {
|
|
1539
|
-
keys.isShared = true;
|
|
1540
|
-
structures.sharedLength = recordId - 0x3f;
|
|
1541
|
-
hasSharedUpdate = true;
|
|
1542
|
-
if (highByte >= 0) {
|
|
1543
|
-
target[position$1++] = (recordId & 0x1f) + 0x60;
|
|
1544
|
-
target[position$1++] = highByte;
|
|
1545
|
-
} else {
|
|
1546
|
-
target[position$1++] = recordId;
|
|
1547
|
-
}
|
|
1548
|
-
} else {
|
|
1549
|
-
if (highByte >= 0) {
|
|
1550
|
-
target[position$1++] = 0xd5; // fixext 2
|
|
1551
|
-
target[position$1++] = 0x72; // "r" record defintion extension type
|
|
1552
|
-
target[position$1++] = (recordId & 0x1f) + 0x60;
|
|
1553
|
-
target[position$1++] = highByte;
|
|
1554
|
-
} else {
|
|
1555
|
-
target[position$1++] = 0xd4; // fixext 1
|
|
1556
|
-
target[position$1++] = 0x72; // "r" record defintion extension type
|
|
1557
|
-
target[position$1++] = recordId;
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
if (newTransitions)
|
|
1561
|
-
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1562
|
-
// record the removal of the id, we can maintain our shared structure
|
|
1563
|
-
if (recordIdsToRemove.length >= maxOwnStructures)
|
|
1564
|
-
recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
|
|
1565
|
-
recordIdsToRemove.push(transition);
|
|
1566
|
-
pack(keys);
|
|
1567
|
-
}
|
|
1623
|
+
newRecord(transition, transition.__keys__ || Object.keys(object), newTransitions);
|
|
1568
1624
|
}
|
|
1569
1625
|
// now write the values
|
|
1570
|
-
for (let
|
|
1571
|
-
|
|
1626
|
+
for (let key in object)
|
|
1627
|
+
if (safePrototype || object.hasOwnProperty(key))
|
|
1628
|
+
pack(object[key]);
|
|
1572
1629
|
};
|
|
1573
1630
|
const makeRoom = (end) => {
|
|
1574
1631
|
let newSize;
|
|
@@ -1591,6 +1648,86 @@ class Packr extends Unpackr {
|
|
|
1591
1648
|
safeEnd = newBuffer.length - 10;
|
|
1592
1649
|
return target = newBuffer
|
|
1593
1650
|
};
|
|
1651
|
+
const newRecord = (transition, keys, newTransitions) => {
|
|
1652
|
+
let recordId = structures.nextId;
|
|
1653
|
+
if (!recordId)
|
|
1654
|
+
recordId = 0x40;
|
|
1655
|
+
if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
|
|
1656
|
+
recordId = structures.nextOwnId;
|
|
1657
|
+
if (!(recordId < maxStructureId))
|
|
1658
|
+
recordId = sharedLimitId;
|
|
1659
|
+
structures.nextOwnId = recordId + 1;
|
|
1660
|
+
} else {
|
|
1661
|
+
if (recordId >= maxStructureId)// cycle back around
|
|
1662
|
+
recordId = sharedLimitId;
|
|
1663
|
+
structures.nextId = recordId + 1;
|
|
1664
|
+
}
|
|
1665
|
+
let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1;
|
|
1666
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1667
|
+
transition.__keys__ = keys;
|
|
1668
|
+
structures[recordId - 0x40] = keys;
|
|
1669
|
+
|
|
1670
|
+
if (recordId < sharedLimitId) {
|
|
1671
|
+
keys.isShared = true;
|
|
1672
|
+
structures.sharedLength = recordId - 0x3f;
|
|
1673
|
+
hasSharedUpdate = true;
|
|
1674
|
+
if (highByte >= 0) {
|
|
1675
|
+
target[position$1++] = (recordId & 0x1f) + 0x60;
|
|
1676
|
+
target[position$1++] = highByte;
|
|
1677
|
+
} else {
|
|
1678
|
+
target[position$1++] = recordId;
|
|
1679
|
+
}
|
|
1680
|
+
} else {
|
|
1681
|
+
if (highByte >= 0) {
|
|
1682
|
+
target[position$1++] = 0xd5; // fixext 2
|
|
1683
|
+
target[position$1++] = 0x72; // "r" record defintion extension type
|
|
1684
|
+
target[position$1++] = (recordId & 0x1f) + 0x60;
|
|
1685
|
+
target[position$1++] = highByte;
|
|
1686
|
+
} else {
|
|
1687
|
+
target[position$1++] = 0xd4; // fixext 1
|
|
1688
|
+
target[position$1++] = 0x72; // "r" record defintion extension type
|
|
1689
|
+
target[position$1++] = recordId;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
if (newTransitions)
|
|
1693
|
+
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1694
|
+
// record the removal of the id, we can maintain our shared structure
|
|
1695
|
+
if (recordIdsToRemove.length >= maxOwnStructures)
|
|
1696
|
+
recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
|
|
1697
|
+
recordIdsToRemove.push(transition);
|
|
1698
|
+
pack(keys);
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
const insertNewRecord = (transition, keys, insertionOffset, newTransitions) => {
|
|
1702
|
+
let mainTarget = target;
|
|
1703
|
+
let mainPosition = position$1;
|
|
1704
|
+
let mainSafeEnd = safeEnd;
|
|
1705
|
+
let mainStart = start;
|
|
1706
|
+
target = keysTarget;
|
|
1707
|
+
position$1 = 0;
|
|
1708
|
+
start = 0;
|
|
1709
|
+
if (!target)
|
|
1710
|
+
keysTarget = target = new ByteArrayAllocate(8192);
|
|
1711
|
+
safeEnd = target.length - 10;
|
|
1712
|
+
newRecord(transition, keys, newTransitions);
|
|
1713
|
+
keysTarget = target;
|
|
1714
|
+
let keysPosition = position$1;
|
|
1715
|
+
target = mainTarget;
|
|
1716
|
+
position$1 = mainPosition;
|
|
1717
|
+
safeEnd = mainSafeEnd;
|
|
1718
|
+
start = mainStart;
|
|
1719
|
+
if (keysPosition > 1) {
|
|
1720
|
+
let newEnd = position$1 + keysPosition - 1;
|
|
1721
|
+
if (newEnd > safeEnd)
|
|
1722
|
+
makeRoom(newEnd);
|
|
1723
|
+
let insertionPosition = insertionOffset + start;
|
|
1724
|
+
target.copyWithin(insertionPosition + keysPosition, insertionPosition + 1, position$1);
|
|
1725
|
+
target.set(keysTarget.slice(0, keysPosition), insertionPosition);
|
|
1726
|
+
position$1 = newEnd;
|
|
1727
|
+
} else {
|
|
1728
|
+
target[insertionOffset + start] = keysTarget[0];
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1594
1731
|
}
|
|
1595
1732
|
useBuffer(buffer) {
|
|
1596
1733
|
// this means we are finished using our own buffer and we can write over it safely
|
|
@@ -1598,11 +1735,15 @@ class Packr extends Unpackr {
|
|
|
1598
1735
|
targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
|
|
1599
1736
|
position$1 = 0;
|
|
1600
1737
|
}
|
|
1738
|
+
clearSharedData() {
|
|
1739
|
+
if (this.structures)
|
|
1740
|
+
this.structures = [];
|
|
1741
|
+
}
|
|
1601
1742
|
}
|
|
1602
1743
|
|
|
1603
1744
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
|
|
1604
1745
|
extensions = [{
|
|
1605
|
-
pack(date, allocateForWrite) {
|
|
1746
|
+
pack(date, allocateForWrite, pack) {
|
|
1606
1747
|
let seconds = date.getTime() / 1000;
|
|
1607
1748
|
if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
|
|
1608
1749
|
// Timestamp 32
|
|
@@ -1617,6 +1758,16 @@ extensions = [{
|
|
|
1617
1758
|
target[position++] = 0xff;
|
|
1618
1759
|
targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0));
|
|
1619
1760
|
targetView.setUint32(position + 4, seconds);
|
|
1761
|
+
} else if (isNaN(seconds)) {
|
|
1762
|
+
if (this.onInvalidDate) {
|
|
1763
|
+
allocateForWrite(0);
|
|
1764
|
+
return pack(this.onInvalidDate())
|
|
1765
|
+
}
|
|
1766
|
+
// Intentionally invalid timestamp
|
|
1767
|
+
let { target, targetView, position} = allocateForWrite(3);
|
|
1768
|
+
target[position++] = 0xd4;
|
|
1769
|
+
target[position++] = 0xff;
|
|
1770
|
+
target[position++] = 0xff;
|
|
1620
1771
|
} else {
|
|
1621
1772
|
// Timestamp 96
|
|
1622
1773
|
let { target, targetView, position} = allocateForWrite(15);
|
|
@@ -1785,6 +1936,14 @@ function insertIds(serialized, idsToInsert) {
|
|
|
1785
1936
|
return serialized
|
|
1786
1937
|
}
|
|
1787
1938
|
|
|
1939
|
+
function writeBundles(start, pack) {
|
|
1940
|
+
targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
|
|
1941
|
+
let writeStrings = bundledStrings$1;
|
|
1942
|
+
bundledStrings$1 = null;
|
|
1943
|
+
pack(writeStrings[0]);
|
|
1944
|
+
pack(writeStrings[1]);
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1788
1947
|
function addExtension$1(extension) {
|
|
1789
1948
|
if (extension.Class) {
|
|
1790
1949
|
if (!extension.pack && !extension.write)
|
|
@@ -1802,7 +1961,8 @@ const pack = defaultPackr.pack;
|
|
|
1802
1961
|
const encode = defaultPackr.pack;
|
|
1803
1962
|
const Encoder = Packr;
|
|
1804
1963
|
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1805
|
-
const REUSE_BUFFER_MODE =
|
|
1964
|
+
const REUSE_BUFFER_MODE = 512;
|
|
1965
|
+
const RESET_BUFFER_MODE = 1024;
|
|
1806
1966
|
|
|
1807
1967
|
class PackrStream extends stream.Transform {
|
|
1808
1968
|
constructor(options) {
|