msgpackr 1.6.2 → 1.7.0-alpha1
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/dist/index.js +30 -6
- package/dist/index.min.js +45 -45
- package/dist/node.cjs +275 -6
- package/dist/test.js +2231 -49
- package/node-index.js +1 -0
- package/pack.js +27 -5
- package/package.json +83 -83
- package/struct.js +260 -0
- package/unpack.js +19 -2
package/dist/node.cjs
CHANGED
|
@@ -33,6 +33,7 @@ const C1 = new C1Type();
|
|
|
33
33
|
C1.name = 'MessagePack 0xC1';
|
|
34
34
|
var sequentialMode = false;
|
|
35
35
|
var inlineObjectReadThreshold = 2;
|
|
36
|
+
var readStruct;
|
|
36
37
|
try {
|
|
37
38
|
new Function('');
|
|
38
39
|
} catch(error) {
|
|
@@ -172,7 +173,13 @@ function checkedRead() {
|
|
|
172
173
|
if (sharedLength < currentStructures.length)
|
|
173
174
|
currentStructures.length = sharedLength;
|
|
174
175
|
}
|
|
175
|
-
let result
|
|
176
|
+
let result;
|
|
177
|
+
if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && readStruct) {
|
|
178
|
+
let id = (src[position++] << 8) + src[position++];
|
|
179
|
+
result = readStruct(src, position, srcEnd, currentStructures[id - 0x40] || loadStructures()[id - 0x40], currentUnpackr);
|
|
180
|
+
position = srcEnd;
|
|
181
|
+
} else
|
|
182
|
+
result = read();
|
|
176
183
|
if (bundledStrings) // bundled strings to skip past
|
|
177
184
|
position = bundledStrings.postBundlePosition;
|
|
178
185
|
|
|
@@ -249,6 +256,8 @@ function read() {
|
|
|
249
256
|
for (let i = 0; i < token; i++) {
|
|
250
257
|
array[i] = read();
|
|
251
258
|
}
|
|
259
|
+
if (currentUnpackr.freezeData)
|
|
260
|
+
return Object.freeze(array)
|
|
252
261
|
return array
|
|
253
262
|
}
|
|
254
263
|
} else if (token < 0xc0) {
|
|
@@ -459,7 +468,8 @@ function createStructureReader(structure, firstId) {
|
|
|
459
468
|
function readObject() {
|
|
460
469
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
461
470
|
if (readObject.count++ > inlineObjectReadThreshold) {
|
|
462
|
-
let readObject = structure.read = (new Function('r', 'return function(){return
|
|
471
|
+
let readObject = structure.read = (new Function('r', 'return function(){return ' + (currentUnpackr.freezeData ? 'Object.freeze' : '') +
|
|
472
|
+
'({' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '})}'))(read);
|
|
463
473
|
if (structure.highByte === 0)
|
|
464
474
|
structure.read = createSecondByteReader(firstId, structure.read);
|
|
465
475
|
return readObject() // second byte is already read, if there is one so immediately read object
|
|
@@ -469,6 +479,8 @@ function createStructureReader(structure, firstId) {
|
|
|
469
479
|
let key = structure[i];
|
|
470
480
|
object[key] = read();
|
|
471
481
|
}
|
|
482
|
+
if (currentUnpackr.freezeData)
|
|
483
|
+
return Object.freeze(object);
|
|
472
484
|
return object
|
|
473
485
|
}
|
|
474
486
|
readObject.count = 0;
|
|
@@ -606,6 +618,8 @@ function readArray(length) {
|
|
|
606
618
|
for (let i = 0; i < length; i++) {
|
|
607
619
|
array[i] = read();
|
|
608
620
|
}
|
|
621
|
+
if (currentUnpackr.freezeData)
|
|
622
|
+
return Object.freeze(array)
|
|
609
623
|
return array
|
|
610
624
|
}
|
|
611
625
|
|
|
@@ -1061,6 +1075,9 @@ function roundFloat32(float32Number) {
|
|
|
1061
1075
|
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
|
|
1062
1076
|
return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
|
|
1063
1077
|
}
|
|
1078
|
+
function setReadStruct(func) {
|
|
1079
|
+
readStruct = func;
|
|
1080
|
+
}
|
|
1064
1081
|
|
|
1065
1082
|
let textEncoder;
|
|
1066
1083
|
try {
|
|
@@ -1077,6 +1094,7 @@ let targetView;
|
|
|
1077
1094
|
let position$1 = 0;
|
|
1078
1095
|
let safeEnd;
|
|
1079
1096
|
let bundledStrings$1 = null;
|
|
1097
|
+
let writeStructSlots;
|
|
1080
1098
|
const MAX_BUNDLE_SIZE = 0xf000;
|
|
1081
1099
|
const hasNonLatin = /[\u0080-\uFFFF]/;
|
|
1082
1100
|
const RECORD_SYMBOL = Symbol('record-id');
|
|
@@ -1128,14 +1146,14 @@ class Packr extends Unpackr {
|
|
|
1128
1146
|
this.pack = this.encode = function(value, encodeOptions) {
|
|
1129
1147
|
if (!target) {
|
|
1130
1148
|
target = new ByteArrayAllocate(8192);
|
|
1131
|
-
targetView = new DataView(target.buffer, 0, 8192);
|
|
1149
|
+
targetView = target.dataView = new DataView(target.buffer, 0, 8192);
|
|
1132
1150
|
position$1 = 0;
|
|
1133
1151
|
}
|
|
1134
1152
|
safeEnd = target.length - 10;
|
|
1135
1153
|
if (safeEnd - position$1 < 0x800) {
|
|
1136
1154
|
// don't start too close to the end,
|
|
1137
1155
|
target = new ByteArrayAllocate(target.length);
|
|
1138
|
-
targetView = new DataView(target.buffer, 0, target.length);
|
|
1156
|
+
targetView = target.dataView = new DataView(target.buffer, 0, target.length);
|
|
1139
1157
|
safeEnd = target.length - 10;
|
|
1140
1158
|
position$1 = 0;
|
|
1141
1159
|
} else
|
|
@@ -1183,7 +1201,10 @@ class Packr extends Unpackr {
|
|
|
1183
1201
|
if (hasSharedUpdate)
|
|
1184
1202
|
hasSharedUpdate = false;
|
|
1185
1203
|
try {
|
|
1186
|
-
|
|
1204
|
+
if (packr.randomAccessStructure)
|
|
1205
|
+
writeStruct(value);
|
|
1206
|
+
else
|
|
1207
|
+
pack(value);
|
|
1187
1208
|
if (bundledStrings$1) {
|
|
1188
1209
|
writeBundles(start, pack);
|
|
1189
1210
|
}
|
|
@@ -1657,7 +1678,7 @@ class Packr extends Unpackr {
|
|
|
1657
1678
|
} else // faster handling for smaller buffers
|
|
1658
1679
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
|
|
1659
1680
|
let newBuffer = new ByteArrayAllocate(newSize);
|
|
1660
|
-
targetView = new DataView(newBuffer.buffer, 0, newSize);
|
|
1681
|
+
targetView = newBuffer.dataView = new DataView(newBuffer.buffer, 0, newSize);
|
|
1661
1682
|
end = Math.min(end, target.length);
|
|
1662
1683
|
if (target.copy)
|
|
1663
1684
|
target.copy(newBuffer, 0, start, end);
|
|
@@ -1748,6 +1769,21 @@ class Packr extends Unpackr {
|
|
|
1748
1769
|
target[insertionOffset + start] = keysTarget[0];
|
|
1749
1770
|
}
|
|
1750
1771
|
};
|
|
1772
|
+
const writeStruct = (object, safePrototype) => {
|
|
1773
|
+
let newPosition = writeStructSlots(object, target, position$1, structures, makeRoom, (value, newPosition) => {
|
|
1774
|
+
position$1 = newPosition;
|
|
1775
|
+
if (start > 0) {
|
|
1776
|
+
pack(value);
|
|
1777
|
+
if (start == 0)
|
|
1778
|
+
return { position: position$1, targetView }; // indicate the buffer was re-allocated
|
|
1779
|
+
} else
|
|
1780
|
+
pack(value);
|
|
1781
|
+
return position$1;
|
|
1782
|
+
});
|
|
1783
|
+
if (newPosition === 0) // bail and go to a msgpack object
|
|
1784
|
+
return writeObject(object, true);
|
|
1785
|
+
position$1 = newPosition;
|
|
1786
|
+
};
|
|
1751
1787
|
}
|
|
1752
1788
|
useBuffer(buffer) {
|
|
1753
1789
|
// this means we are finished using our own buffer and we can write over it safely
|
|
@@ -1977,6 +2013,9 @@ function addExtension$1(extension) {
|
|
|
1977
2013
|
}
|
|
1978
2014
|
addExtension(extension);
|
|
1979
2015
|
}
|
|
2016
|
+
function setWriteStructSlots(func) {
|
|
2017
|
+
writeStructSlots = func;
|
|
2018
|
+
}
|
|
1980
2019
|
|
|
1981
2020
|
let defaultPackr = new Packr({ useRecords: false });
|
|
1982
2021
|
const pack = defaultPackr.pack;
|
|
@@ -1986,6 +2025,236 @@ const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
|
1986
2025
|
const REUSE_BUFFER_MODE = 512;
|
|
1987
2026
|
const RESET_BUFFER_MODE = 1024;
|
|
1988
2027
|
|
|
2028
|
+
// first four bits
|
|
2029
|
+
const hasNonLatin$1 = /[\u0080-\uFFFF]/;
|
|
2030
|
+
const float32Headers = [false, true, true, false, false, true, true, false];
|
|
2031
|
+
setWriteStructSlots(writeStruct);
|
|
2032
|
+
function writeStruct(object, target, position, structures, makeRoom, pack) {
|
|
2033
|
+
let transition = structures.transitions || false;
|
|
2034
|
+
let start = position;
|
|
2035
|
+
position += 4;
|
|
2036
|
+
let queuedReferences = [];
|
|
2037
|
+
let uint32 = target.uint32 || (target.uint32 = new Uint32Array(target.buffer));
|
|
2038
|
+
let targetView = target.dataView;
|
|
2039
|
+
let encoded;
|
|
2040
|
+
let stringData = '';
|
|
2041
|
+
let safeEnd = target.length - 10;
|
|
2042
|
+
for (let key in object) {
|
|
2043
|
+
let nextTransition = transition[key];
|
|
2044
|
+
if (!nextTransition) {
|
|
2045
|
+
return 0; // bail
|
|
2046
|
+
//nextTransition = transition[key] = Object.create(null)
|
|
2047
|
+
//newTransitions++
|
|
2048
|
+
}
|
|
2049
|
+
if (position > safeEnd) {
|
|
2050
|
+
let newPosition = position - start;
|
|
2051
|
+
target = makeRoom(position);
|
|
2052
|
+
position = newPosition;
|
|
2053
|
+
start = 0;
|
|
2054
|
+
safeEnd = target.length - 10;
|
|
2055
|
+
}
|
|
2056
|
+
transition = nextTransition;
|
|
2057
|
+
let value = object[key];
|
|
2058
|
+
switch (typeof value) {
|
|
2059
|
+
case 'number':
|
|
2060
|
+
if (value >>> 0 === value && value < 0x20000000) {
|
|
2061
|
+
encoded = value;
|
|
2062
|
+
break;
|
|
2063
|
+
} else if (value < 0x100000000 && value >= -0x80000000) {
|
|
2064
|
+
targetView.setFloat32(position, value, true);
|
|
2065
|
+
if (float32Headers[target[position + 3] >>> 5]) {
|
|
2066
|
+
let xShifted;
|
|
2067
|
+
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
2068
|
+
if (((xShifted = value * mult10[((target[position + 3] & 0x7f) << 1) | (target[position + 2] >> 7)]) >> 0) === xShifted) {
|
|
2069
|
+
position += 4;
|
|
2070
|
+
continue;
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
// fall back to msgpack encoding
|
|
2075
|
+
queuedReferences.push(value, position - start);
|
|
2076
|
+
position += 4;
|
|
2077
|
+
continue;
|
|
2078
|
+
case 'string':
|
|
2079
|
+
if (hasNonLatin$1.test(value)) {
|
|
2080
|
+
queuedReferences.push(value, position - start);
|
|
2081
|
+
position += 4;
|
|
2082
|
+
continue;
|
|
2083
|
+
}
|
|
2084
|
+
if (value.length < 4) { // we can inline really small strings
|
|
2085
|
+
encoded = 0xf8000000 + (value.length << 24) + (value.charCodeAt(0) << 16) + (value.charCodeAt(1) << 8) + (value.charCodeAt(2) || 0);
|
|
2086
|
+
// TODO: determining remaining and make max value be a ratio of that (probably 1/256th)
|
|
2087
|
+
} else if (value.length < 256 && stringData.length < 61440) {
|
|
2088
|
+
// bundle these strings
|
|
2089
|
+
encoded = 0x60000000 | (value.length << 16) | stringData.length;
|
|
2090
|
+
stringData += value;
|
|
2091
|
+
} else { // else queue it
|
|
2092
|
+
queuedReferences.push(value, position - start);
|
|
2093
|
+
position += 4;
|
|
2094
|
+
continue;
|
|
2095
|
+
}
|
|
2096
|
+
break;
|
|
2097
|
+
case 'object':
|
|
2098
|
+
if (value) {
|
|
2099
|
+
queuedReferences.push(value, position - start);
|
|
2100
|
+
position += 4;
|
|
2101
|
+
continue;
|
|
2102
|
+
} else { // null
|
|
2103
|
+
encoded = 0xe0000000;
|
|
2104
|
+
}
|
|
2105
|
+
break;
|
|
2106
|
+
case 'boolean':
|
|
2107
|
+
encoded = value ? 0xe3000000 : 0xe2000000;
|
|
2108
|
+
break;
|
|
2109
|
+
case 'undefined':
|
|
2110
|
+
encoded = 0xe1000000;
|
|
2111
|
+
break;
|
|
2112
|
+
}
|
|
2113
|
+
targetView.setUint32(position, encoded, true);
|
|
2114
|
+
position += 4;
|
|
2115
|
+
}
|
|
2116
|
+
let recordId = transition[RECORD_SYMBOL];
|
|
2117
|
+
if (!(recordId < 1024)) {
|
|
2118
|
+
// for now just punt and go back to writeObject
|
|
2119
|
+
return 0;
|
|
2120
|
+
// newRecord(transition, transition.__keys__ || Object.keys(object), newTransitions, true)
|
|
2121
|
+
}
|
|
2122
|
+
let stringLength = stringData.length;
|
|
2123
|
+
if (stringData) {
|
|
2124
|
+
if (position + stringLength > safeEnd) {
|
|
2125
|
+
target = makeRoom(position + stringLength);
|
|
2126
|
+
}
|
|
2127
|
+
position += target.latin1Write(stringData, position, 0xffffffff);
|
|
2128
|
+
}
|
|
2129
|
+
target[start] = recordId >> 8;
|
|
2130
|
+
target[start + 1] = recordId & 0xff;
|
|
2131
|
+
target[start + 2] = stringLength >> 8;
|
|
2132
|
+
target[start + 3] = stringLength & 0xff;
|
|
2133
|
+
let queued32BitReferences;
|
|
2134
|
+
for (let i = 0, l = queuedReferences.length; i < l;) {
|
|
2135
|
+
let value = queuedReferences[i++];
|
|
2136
|
+
let slotOffset = queuedReferences[i++] + start;
|
|
2137
|
+
let offset = position - slotOffset;
|
|
2138
|
+
if (offset < 0x1f000000) {
|
|
2139
|
+
targetView.setUint32(slotOffset, 0x80000000 | (offset), true);
|
|
2140
|
+
} else {
|
|
2141
|
+
if (!queued32BitReferences)
|
|
2142
|
+
queued32BitReferences = [];
|
|
2143
|
+
queued32BitReferences.push({slotOffset, offset: position - start});
|
|
2144
|
+
}
|
|
2145
|
+
let newPosition = pack(value, position);
|
|
2146
|
+
if (typeof newPosition === 'object') {
|
|
2147
|
+
// re-allocated
|
|
2148
|
+
position = newPosition.position;
|
|
2149
|
+
targetView = newPosition.targetView;
|
|
2150
|
+
start = 0;
|
|
2151
|
+
} else
|
|
2152
|
+
position = newPosition;
|
|
2153
|
+
}
|
|
2154
|
+
if (queued32BitReferences) {
|
|
2155
|
+
// TODO: makeRoom
|
|
2156
|
+
for (let i = 0, l = queued32BitReferences.length; i < l; i++) {
|
|
2157
|
+
let ref = queued32BitReferences[i];
|
|
2158
|
+
targetView.setUint32(ref.slotOffset, 0xa0000000 - ((l - i) << 2), true);
|
|
2159
|
+
targetView.setUint32(position, ref.offset, true);
|
|
2160
|
+
position += 4;
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
return position;
|
|
2165
|
+
}
|
|
2166
|
+
var sourceSymbol = Symbol('source');
|
|
2167
|
+
function readStruct$1(src, position, srcEnd, structure, unpackr) {
|
|
2168
|
+
var stringLength = (src[position++] << 8) | src[position++];
|
|
2169
|
+
var construct = structure.construct;
|
|
2170
|
+
var srcString;
|
|
2171
|
+
if (!construct) {
|
|
2172
|
+
construct = structure.construct = function() {
|
|
2173
|
+
};
|
|
2174
|
+
var prototype = construct.prototype;
|
|
2175
|
+
Object.defineProperty(prototype, 'toJSON', {
|
|
2176
|
+
get() {
|
|
2177
|
+
// return an enumerable object with own properties to JSON stringify
|
|
2178
|
+
let resolved = {};
|
|
2179
|
+
for (let i = 0, l = structure.length; i < l; i++) {
|
|
2180
|
+
let key = structure[i];
|
|
2181
|
+
resolved[key] = this[key];
|
|
2182
|
+
}
|
|
2183
|
+
return resolved;
|
|
2184
|
+
},
|
|
2185
|
+
// not enumerable or anything
|
|
2186
|
+
});
|
|
2187
|
+
for (let i = 0, l = structure.length; i < l; i++) {
|
|
2188
|
+
let key = structure[i];
|
|
2189
|
+
Object.defineProperty(prototype, key, {
|
|
2190
|
+
get() {
|
|
2191
|
+
let source = this[sourceSymbol];
|
|
2192
|
+
let src = source.src;
|
|
2193
|
+
//let uint32 = src.uint32 || (src.uint32 = new Uint32Array(src.buffer, src.byteOffset, src.byteLength));
|
|
2194
|
+
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
2195
|
+
let position = source.position + (i << 2);
|
|
2196
|
+
let value = dataView.getUint32(position, true);
|
|
2197
|
+
let start;
|
|
2198
|
+
switch (value >>> 29) {
|
|
2199
|
+
case 0:
|
|
2200
|
+
return value;
|
|
2201
|
+
case 3:
|
|
2202
|
+
if (value & 0x10000000) {
|
|
2203
|
+
start = (value & 0xffff) + position;
|
|
2204
|
+
return src.toString('utf8', start, start + ((value >> 16) & 0x7ff));
|
|
2205
|
+
} else {
|
|
2206
|
+
if (!srcString) {
|
|
2207
|
+
start = source.position + (l << 2);
|
|
2208
|
+
srcString = src.toString('latin1', start, start + stringLength);
|
|
2209
|
+
}
|
|
2210
|
+
start = value & 0xffff;
|
|
2211
|
+
return srcString.slice(start, start + ((value >> 16) & 0x7ff));
|
|
2212
|
+
}
|
|
2213
|
+
case 4:
|
|
2214
|
+
start = (0x1fffffff & value) + position;
|
|
2215
|
+
let end = srcEnd;
|
|
2216
|
+
for (let next = i + 1; next < l; next++) {
|
|
2217
|
+
position = source.position + (next << 2);
|
|
2218
|
+
let nextValue = dataView.getUint32(position, true); if ((nextValue & 0xe0000000) == -0x80000000) {
|
|
2219
|
+
end = (0x1fffffff & nextValue) + position;
|
|
2220
|
+
break;
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
return unpackr.unpack(src.slice(start, end));
|
|
2224
|
+
case 1: case 2: case 5: case 6:
|
|
2225
|
+
let fValue = dataView.getFloat32(position, true);
|
|
2226
|
+
// this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
2227
|
+
let multiplier = mult10[((src[position + 3] & 0x7f) << 1) | (src[position + 2] >> 7)];
|
|
2228
|
+
return ((multiplier * fValue + (fValue > 0 ? 0.5 : -0.5)) >> 0) / multiplier;
|
|
2229
|
+
case 7:
|
|
2230
|
+
switch((value >> 24) & 0x1f) {
|
|
2231
|
+
case 0: return null;
|
|
2232
|
+
case 1: return undefined;
|
|
2233
|
+
case 2: return false;
|
|
2234
|
+
case 3: return true;
|
|
2235
|
+
case 8: return dataView.getFloat64(position + (value & 0x3ffffff), true);
|
|
2236
|
+
case 0x18: return '';
|
|
2237
|
+
case 0x19: return String.fromCharCode((value >> 16) & 0xff);
|
|
2238
|
+
case 0x20: return String.fromCharCode((value >> 16) & 0xff, (value >> 8) & 0xff);
|
|
2239
|
+
case 0x21: return String.fromCharCode((value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff);
|
|
2240
|
+
default: throw new Error('Unknown constant');
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
},
|
|
2244
|
+
enumerable: true,
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
var instance = new construct();
|
|
2249
|
+
instance[sourceSymbol] = {
|
|
2250
|
+
src,
|
|
2251
|
+
uint32: src.uint32,
|
|
2252
|
+
position,
|
|
2253
|
+
};
|
|
2254
|
+
return instance;
|
|
2255
|
+
}
|
|
2256
|
+
setReadStruct(readStruct$1);
|
|
2257
|
+
|
|
1989
2258
|
class PackrStream extends stream.Transform {
|
|
1990
2259
|
constructor(options) {
|
|
1991
2260
|
if (!options)
|