msgpackr 1.4.4 → 1.5.0
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 +14 -3
- package/SECURITY.md +11 -0
- package/dist/index.js +37 -13
- package/dist/index.min.js +13 -9
- package/dist/node.cjs +37 -16
- package/dist/test.js +18 -1
- package/index.d.ts +1 -1
- package/index.js +2 -2
- package/node-index.js +2 -4
- package/pack.js +13 -5
- package/package.json +4 -1
- package/tests/test-compatibility.cjs +18 -2
- package/tests/test.js +18 -1
- package/unpack.d.ts +5 -2
- package/unpack.js +22 -9
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# msgpackr
|
|
2
|
-
[](LICENSE)
|
|
3
2
|
[](https://www.npmjs.org/package/msgpackr)
|
|
3
|
+
[](https://www.npmjs.org/package/msgpackr)
|
|
4
4
|
[](benchmark.md)
|
|
5
5
|
[](benchmark.md)
|
|
6
6
|
[](README.md)
|
|
7
7
|
[](README.md)
|
|
8
|
+
[](LICENSE)
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
The msgpackr package is an extremely fast MessagePack NodeJS/JavaScript implementation. Currently, it is significantly faster than any other known implementations, faster than Avro (for JS), and generally faster than native V8 JSON.stringify/parse, on NodeJS. It also includes an optional record extension (the `r` in msgpackr), for defining record structures that makes MessagePack even faster and more compact, often over twice as fast as even native JSON functions, several times faster than other JS implementations, and 15-50% more compact. See the performance section for more details. Structured cloning (with support for cyclical references) is also supported through optional extensions.
|
|
@@ -166,6 +167,7 @@ The following options properties can be provided to the Packr or Unpackr constru
|
|
|
166
167
|
* `sequential` - Encode structures in serialized data, and reference previously encoded structures with expectation that decoder will read the encoded structures in the same order as encoded, with `unpackMultiple`.
|
|
167
168
|
* `largeBigIntToFloat` - If a bigint needs to be encoded that is larger than will fit in 64-bit integers, it will be encoded as a float-64 (otherwise will throw a RangeError).
|
|
168
169
|
* `encodeUndefinedAsNil` - Encodes a value of `undefined` as a MessagePack `nil`, the same as a `null`.
|
|
170
|
+
* `int64AsNumber` - This will decode uint64 and int64 numbers as standard JS numbers rather than as bigint numbers.
|
|
169
171
|
|
|
170
172
|
### 32-bit Float Options
|
|
171
173
|
By default all non-integer numbers are serialized as 64-bit float (double). This is fast, and ensures maximum precision. However, often real-world data doesn't not need 64-bits of precision, and using 32-bit encoding can be much more space efficient. There are several options that provide more efficient encodings. Using the decimal rounding options for encoding and decoding provides lossless storage of common decimal representations like 7.99, in more efficient 32-bit format (rather than 64-bit). The `useFloat32` property has several possible options, available from the module as constants:
|
|
@@ -176,13 +178,22 @@ const { ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
|
176
178
|
|
|
177
179
|
* `ALWAYS` (1) - Always will encode non-integers (absolute less than 2147483648) as 32-bit float.
|
|
178
180
|
* `DECIMAL_ROUND` (3) - Always will encode non-integers as 32-bit float, and when decoding 32-bit float, round to the significant decimal digits (usually 7, but 6 or 8 digits for some ranges).
|
|
179
|
-
* `DECIMAL_FIT` (4) - Only encode non-integers as 32-bit float if all significant digits (usually up to 7) can be
|
|
181
|
+
* `DECIMAL_FIT` (4) - Only encode non-integers as 32-bit float if all significant digits (usually up to 7) can be unambiguously encoded as a 32-bit float, and decode/unpack with decimal rounding (same as above). This will ensure round-trip encoding/decoding without loss in precision and uses 32-bit when possible.
|
|
180
182
|
|
|
181
183
|
Note, that the performance is decreased with decimal rounding by about 20-25%, although if only 5% of your values are floating point, that will only have about a 1% impact overall.
|
|
182
184
|
|
|
183
|
-
In addition, msgpackr exports a `roundFloat32(number)` function that can be used to round floating point numbers to the maximum significant decimal digits that can be stored in 32-bit float, just as DECIMAL_ROUND does when
|
|
185
|
+
In addition, msgpackr exports a `roundFloat32(number)` function that can be used to round floating point numbers to the maximum significant decimal digits that can be stored in 32-bit float, just as DECIMAL_ROUND does when decoding. This can be useful for determining how a number will be decoded prior to encoding it.
|
|
184
186
|
|
|
185
187
|
## Performance
|
|
188
|
+
### Native Acceleration
|
|
189
|
+
Msgpackr employs an optional native node-addon to accelerate the parsing of strings. This should be automatically installed and utilized on NodeJS. However, you can verify this by checking the `isNativeAccelerationEnabled` property that is exported from msgpackr. If this is `false`, the `msgpackr-extract` package may not have been properly installed, and you may want to verify that it is installed correctly:
|
|
190
|
+
```js
|
|
191
|
+
import { isNativeAccelerationEnabled } from 'msgpackr'
|
|
192
|
+
if (!isNativeAccelerationEnabled)
|
|
193
|
+
console.warn('Native acceleration not enabled, verify that install finished properly')
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Benchmarks
|
|
186
197
|
Msgpackr is fast. Really fast. Here is comparison with the next fastest JS projects using the benchmark tool from `msgpack-lite` (and the sample data is from some clinical research data we use that has a good mix of different value types and structures). It also includes comparison to V8 native JSON functionality, and JavaScript Avro (`avsc`, a very optimized Avro implementation):
|
|
187
198
|
|
|
188
199
|
operation | op | ms | op/s
|
package/SECURITY.md
ADDED
package/dist/index.js
CHANGED
|
@@ -58,8 +58,16 @@
|
|
|
58
58
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
59
59
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
60
60
|
// new ones
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
try {
|
|
62
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
|
|
63
|
+
} catch(error) {
|
|
64
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
65
|
+
src = null;
|
|
66
|
+
if (source instanceof Uint8Array)
|
|
67
|
+
throw error
|
|
68
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
69
|
+
}
|
|
70
|
+
if (this instanceof Unpackr) {
|
|
63
71
|
currentUnpackr = this;
|
|
64
72
|
if (this.structures) {
|
|
65
73
|
currentStructures = this.structures;
|
|
@@ -291,10 +299,11 @@
|
|
|
291
299
|
position += 4;
|
|
292
300
|
return value
|
|
293
301
|
case 0xcf:
|
|
294
|
-
if (currentUnpackr.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
302
|
+
if (currentUnpackr.int64AsNumber) {
|
|
303
|
+
value = dataView.getUint32(position) * 0x100000000;
|
|
304
|
+
value += dataView.getUint32(position + 4);
|
|
305
|
+
} else
|
|
306
|
+
value = dataView.getBigUint64(position);
|
|
298
307
|
position += 8;
|
|
299
308
|
return value
|
|
300
309
|
|
|
@@ -310,7 +319,11 @@
|
|
|
310
319
|
position += 4;
|
|
311
320
|
return value
|
|
312
321
|
case 0xd3:
|
|
313
|
-
|
|
322
|
+
if (currentUnpackr.int64AsNumber) {
|
|
323
|
+
value = dataView.getInt32(position) * 0x100000000;
|
|
324
|
+
value += dataView.getUint32(position + 4);
|
|
325
|
+
} else
|
|
326
|
+
value = dataView.getBigInt64(position);
|
|
314
327
|
position += 8;
|
|
315
328
|
return value
|
|
316
329
|
|
|
@@ -459,6 +472,7 @@
|
|
|
459
472
|
var readString8 = readStringJS;
|
|
460
473
|
var readString16 = readStringJS;
|
|
461
474
|
var readString32 = readStringJS;
|
|
475
|
+
let isNativeAccelerationEnabled = false;
|
|
462
476
|
function readStringJS(length) {
|
|
463
477
|
let result;
|
|
464
478
|
if (length < 16) {
|
|
@@ -983,7 +997,7 @@
|
|
|
983
997
|
let transitionsCount = 0;
|
|
984
998
|
let serializationsSinceTransitionRebuild = 0;
|
|
985
999
|
|
|
986
|
-
this.pack = this.encode = function(value) {
|
|
1000
|
+
this.pack = this.encode = function(value, encodeOptions) {
|
|
987
1001
|
if (!target) {
|
|
988
1002
|
target = new ByteArrayAllocate(8192);
|
|
989
1003
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -1048,6 +1062,11 @@
|
|
|
1048
1062
|
referenceMap = null;
|
|
1049
1063
|
return serialized
|
|
1050
1064
|
}
|
|
1065
|
+
if (encodeOptions === REUSE_BUFFER_MODE) {
|
|
1066
|
+
target.start = start;
|
|
1067
|
+
target.end = position$1;
|
|
1068
|
+
return target
|
|
1069
|
+
}
|
|
1051
1070
|
return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
1052
1071
|
} finally {
|
|
1053
1072
|
if (sharedStructures) {
|
|
@@ -1071,13 +1090,15 @@
|
|
|
1071
1090
|
if (sharedStructures.length > sharedLength) {
|
|
1072
1091
|
sharedStructures = sharedStructures.slice(0, sharedLength);
|
|
1073
1092
|
}
|
|
1074
|
-
|
|
1093
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1094
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
1075
1095
|
if (packr.saveStructures(sharedStructures, lastSharedStructuresLength) === false) {
|
|
1076
1096
|
// get updated structures and try again if the update failed
|
|
1077
1097
|
packr._mergeStructures(packr.getStructures());
|
|
1078
1098
|
return packr.pack(value)
|
|
1079
1099
|
}
|
|
1080
1100
|
lastSharedStructuresLength = sharedLength;
|
|
1101
|
+
return returnBuffer
|
|
1081
1102
|
}
|
|
1082
1103
|
}
|
|
1083
1104
|
}
|
|
@@ -1094,9 +1115,9 @@
|
|
|
1094
1115
|
// first we estimate the header size, so we can write to the correct location
|
|
1095
1116
|
if (strLength < 0x20) {
|
|
1096
1117
|
headerSize = 1;
|
|
1097
|
-
} else if (strLength <
|
|
1118
|
+
} else if (strLength < 0x100) {
|
|
1098
1119
|
headerSize = 2;
|
|
1099
|
-
} else if (strLength <
|
|
1120
|
+
} else if (strLength < 0x10000) {
|
|
1100
1121
|
headerSize = 3;
|
|
1101
1122
|
} else {
|
|
1102
1123
|
headerSize = 5;
|
|
@@ -1509,7 +1530,7 @@
|
|
|
1509
1530
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
1510
1531
|
throw new Error('Packed buffer would be larger than maximum buffer size')
|
|
1511
1532
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
1512
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
1533
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
|
|
1513
1534
|
} else // faster handling for smaller buffers
|
|
1514
1535
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
|
|
1515
1536
|
let newBuffer = new ByteArrayAllocate(newSize);
|
|
@@ -1733,7 +1754,8 @@
|
|
|
1733
1754
|
const pack = defaultPackr.pack;
|
|
1734
1755
|
const encode = defaultPackr.pack;
|
|
1735
1756
|
const Encoder = Packr;
|
|
1736
|
-
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1757
|
+
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1758
|
+
const REUSE_BUFFER_MODE = 1000;
|
|
1737
1759
|
|
|
1738
1760
|
/**
|
|
1739
1761
|
* Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
|
|
@@ -1832,6 +1854,7 @@
|
|
|
1832
1854
|
exports.FLOAT32_OPTIONS = FLOAT32_OPTIONS;
|
|
1833
1855
|
exports.NEVER = NEVER;
|
|
1834
1856
|
exports.Packr = Packr;
|
|
1857
|
+
exports.REUSE_BUFFER_MODE = REUSE_BUFFER_MODE;
|
|
1835
1858
|
exports.Unpackr = Unpackr;
|
|
1836
1859
|
exports.addExtension = addExtension$1;
|
|
1837
1860
|
exports.clearSource = clearSource;
|
|
@@ -1839,6 +1862,7 @@
|
|
|
1839
1862
|
exports.decodeIter = decodeIter;
|
|
1840
1863
|
exports.encode = encode;
|
|
1841
1864
|
exports.encodeIter = encodeIter;
|
|
1865
|
+
exports.isNativeAccelerationEnabled = isNativeAccelerationEnabled;
|
|
1842
1866
|
exports.mapsAsObjects = mapsAsObjects;
|
|
1843
1867
|
exports.pack = pack;
|
|
1844
1868
|
exports.roundFloat32 = roundFloat32;
|
package/dist/index.min.js
CHANGED
|
@@ -7,8 +7,8 @@ case 194:return!1;case 195:return!0;case 196:// bin 8
|
|
|
7
7
|
return m(A[G++]);case 197:return b=F.getUint16(G),G+=2,m(b);case 198:return b=F.getUint32(G),G+=4,m(b);case 199:// ext 8
|
|
8
8
|
return n(A[G++]);case 200:return b=F.getUint16(G),G+=2,n(b);case 201:return b=F.getUint32(G),G+=4,n(b);case 202:if(b=F.getFloat32(G),2<H.useFloat32){// this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
9
9
|
let a=_[(127&A[G])<<1|A[G+1]>>7];return G+=4,(a*b+(0<b?.5:-.5)>>0)/a}return G+=4,b;case 203:return b=F.getFloat64(G),G+=8,b;// uint handlers
|
|
10
|
-
case 204:return A[G++];case 205:return b=F.getUint16(G),G+=2,b;case 206:return b=F.getUint32(G),G+=4,b;case 207:return H.
|
|
11
|
-
case 208:return F.getInt8(G++);case 209:return b=F.getInt16(G),G+=2,b;case 210:return b=F.getInt32(G),G+=4,b;case 211:return b=F.getBigInt64(G),G+=8,b;case 212:if(b=A[G++],114==b)return Y(63&A[G++]);else{let a=K[b];if(a)return a.read?(G++,a.read(e())):a.noBuffer?(G++,a()):a(A.subarray(G,++G));throw new Error("Unknown extension "+b)}case 213:return b=A[G],114==b?(G++,Y(63&A[G++],A[G++])):n(2);case 214:// fixext 4
|
|
10
|
+
case 204:return A[G++];case 205:return b=F.getUint16(G),G+=2,b;case 206:return b=F.getUint32(G),G+=4,b;case 207:return H.int64AsNumber?(b=4294967296*F.getUint32(G),b+=F.getUint32(G+4)):b=F.getBigUint64(G),G+=8,b;// int handlers
|
|
11
|
+
case 208:return F.getInt8(G++);case 209:return b=F.getInt16(G),G+=2,b;case 210:return b=F.getInt32(G),G+=4,b;case 211:return H.int64AsNumber?(b=4294967296*F.getInt32(G),b+=F.getUint32(G+4)):b=F.getBigInt64(G),G+=8,b;case 212:if(b=A[G++],114==b)return Y(63&A[G++]);else{let a=K[b];if(a)return a.read?(G++,a.read(e())):a.noBuffer?(G++,a()):a(A.subarray(G,++G));throw new Error("Unknown extension "+b)}case 213:return b=A[G],114==b?(G++,Y(63&A[G++],A[G++])):n(2);case 214:// fixext 4
|
|
12
12
|
return n(4);case 215:// fixext 8
|
|
13
13
|
return n(8);case 216:// fixext 16
|
|
14
14
|
return n(16);case 217:return b=A[G++],J>=G?D.slice(G-I,(G+=b)-I):T(b);case 218:return b=F.getUint16(G),G+=2,J>=G?D.slice(G-I,(G+=b)-I):U(b);case 219:return b=F.getUint32(G),G+=4,J>=G?D.slice(G-I,(G+=b)-I):V(b);case 220:return b=F.getUint16(G),G+=2,i(b);case 221:return b=F.getUint32(G),G+=4,i(b);case 222:return b=F.getUint16(G),G+=2,j(b);case 223:return b=F.getUint32(G),G+=4,j(b);default:// negative int
|
|
@@ -35,7 +35,10 @@ a[g++]=214,a[g++]=105,a[g++]=f>>24,a[g++]=255&f>>16,a[g++]=255&f>>8,a[g++]=255&f
|
|
|
35
35
|
* @param {object} [options] - unpackr options
|
|
36
36
|
* @returns {IterableIterator|Promise.<AsyncIterableIterator}
|
|
37
37
|
*/var z;try{z=new TextDecoder}catch(a){}var A,B,C,D,E,F,G=0,H={},I=0,J=0,K=[],L={useRecords:!1,mapsAsObjects:!0};class M{}const N=new M;N.name="MessagePack 0xC1";var O=!1;class P{constructor(a){a&&(!1===a.useRecords&&a.mapsAsObjects===void 0&&(a.mapsAsObjects=!0),a.structures?a.structures.sharedLength=a.structures.length:a.getStructures&&((a.structures=[]).uninitialized=!0,a.structures.sharedLength=0)),Object.assign(this,a)}unpack(a,b){if(A)// re-entrant execution, save the state and restore it after we do this unpack
|
|
38
|
-
return p(()=>(q(),this?this.unpack(a,b):P.prototype.unpack.call(L,a,b)));
|
|
38
|
+
return p(()=>(q(),this?this.unpack(a,b):P.prototype.unpack.call(L,a,b)));B=-1<b?b:a.length,G=0,J=0,D=null,A=a;// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
39
|
+
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
40
|
+
// new ones
|
|
41
|
+
try{F=a.dataView||(a.dataView=new DataView(a.buffer,a.byteOffset,a.byteLength))}catch(b){if(A=null,a instanceof Uint8Array)throw b;throw new Error("Source must be a Uint8Array or Buffer but was a "+(a&&"object"==typeof a?a.constructor.name:typeof a))}if(this instanceof P){if(H=this,this.structures)return C=this.structures,c();(!C||0<C.length)&&(C=[])}else H=L,(!C||0<C.length)&&(C=[]);return c()}unpackMultiple(a,b){let d,e=0;try{O=!0;let f=a.length,g=this?this.unpack(a,f):aa.unpack(a,f);if(b){for(b(g);G<f;)if(e=G,!1===b(c()))return;}else{for(d=[g];G<f;)e=G,d.push(c());return d}}catch(a){throw a.lastPosition=e,a.values=d,a}finally{O=!1,q()}}_mergeStructures(a,b){a=a||[];for(let c,d=0,e=a.length;d<e;d++)c=a[d],c&&(c.isShared=!0,32<=d&&(c.highByte=d-32>>5));for(let c in a.sharedLength=a.length,b||[])if(0<=c){let d=a[c],e=b[c];e&&(d&&((a.restoreStructures||(a.restoreStructures=[]))[c]=d),a[c]=e)}return this.structures=a}decode(a,b){return this.unpack(a,b)}}const Q=/^[a-zA-Z_$][a-zA-Z\d_$]*$/,R=(a,b)=>function(){let c=A[G++];if(0===c)return b();let d=32>a?-(a+(c<<5)):a+(c<<5),e=C[d]||g()[d];if(!e)throw new Error("Record id is not defined for "+d);return e.read||(e.read=f(e,a)),e.read()};var S=h,T=h,U=h,V=h;var W=String.fromCharCode,X=Array(4096);const Y=(a,b)=>{var c=e();let d=a;void 0!==b&&(a=32>a?-((b<<5)+a):(b<<5)+a,c.highByte=b);let g=C[a];return g&&g.isShared&&((C.restoreStructures||(C.restoreStructures=[]))[a]=g),C[a]=c,c.read=f(c,d),c.read()};var Z="object"==typeof self?self:global;K[0]=()=>{},K[0].noBuffer=!0,K[101]=()=>{let a=e();return(Z[a[0]]||Error)(a[1])},K[105]=()=>{// id extension (for structured clones)
|
|
39
42
|
let a=F.getUint32(G-4);E||(E=new Map);let b,c=A[G];b=144<=c&&160>c||220==c||221==c?[]:{};let d={target:b};// a placeholder object
|
|
40
43
|
E.set(a,d);let f=e();// read the next value as the target object to id
|
|
41
44
|
return d.used?Object.assign(b,f):(d.target=f,f);// no cycle, can just use the returned read object
|
|
@@ -45,10 +48,11 @@ return new Z[c](Uint8Array.prototype.slice.call(a,1).buffer)},K[120]=()=>{let a=
|
|
|
45
48
|
if(4==a.length)return new Date(1e3*(16777216*a[0]+(a[1]<<16)+(a[2]<<8)+a[3]));if(8==a.length)return new Date(((a[0]<<22)+(a[1]<<14)+(a[2]<<6)+(a[3]>>2))/1e6+1e3*(4294967296*(3&a[3])+16777216*a[4]+(a[5]<<16)+(a[6]<<8)+a[7]));if(12==a.length)// TODO: Implement support for negative
|
|
46
49
|
return new Date(((a[0]<<24)+(a[1]<<16)+(a[2]<<8)+a[3])/1e6+1e3*((128&a[4]?-281474976710656:0)+1099511627776*a[6]+4294967296*a[7]+16777216*a[8]+(a[9]<<16)+(a[10]<<8)+a[11]));throw new Error("Invalid timestamp length")};const _=Array(147);// this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
47
50
|
for(let c=0;256>c;c++)_[c]=+("1e"+b(45.15-.30103*c));var aa=new P({useRecords:!1});const ba=aa.unpack,ca=aa.unpackMultiple,da=aa.unpack,ea={NEVER:0,ALWAYS:1,DECIMAL_ROUND:3,DECIMAL_FIT:4};let fa,ga=new Float32Array(1),ha=new Uint8Array(ga.buffer,0,4);try{fa=new TextEncoder}catch(a){}let ia,ja;const ka="undefined"!=typeof Buffer,la=ka?Buffer.allocUnsafeSlow:Uint8Array,ma=ka?Buffer:Uint8Array,na=ka?4294967296:2144337920;let oa,pa,qa,ra=0;const sa=Symbol("record-id");class ta extends P{constructor(a){super(a),this.offset=0;let b,c,d,e,f,g=0,h=ma.prototype.utf8Write?function(a,b,c){return oa.utf8Write(a,b,c)}:!!(fa&&fa.encodeInto)&&function(a,b){return fa.encodeInto(a,oa.subarray(b)).written},i=this;a||(a={});let j=a&&a.sequential,k=a.structures||a.saveStructures,l=a.maxSharedStructures;if(null==l&&(l=k?32:0),8160<l)throw new Error("Maximum maxSharedStructure is 8160");let m=a.maxOwnStructures;null==m&&(m=k?32:64),j&&!a.saveStructures&&(this.structures=[]);// two byte record ids for shared structures
|
|
48
|
-
let n=32<l||64<m+l,o=l+64,p=l+m+64;if(8256<p)throw new Error("Maximum maxSharedStructure + maxOwnStructure is 8192");let q=[],r=0,s=0;this.pack=this.encode=function(a){if(oa||(oa=new la(8192),pa=new DataView(oa.buffer,0,8192),ra=0),qa=oa.length-10,2048>qa-ra?(oa=new la(oa.length),pa=new DataView(oa.buffer,0,oa.length),qa=oa.length-10,ra=0):ra=2147483640&ra+7,b=ra,f=i.structuredClone?new Map:null,c=i.structures,c){c.uninitialized&&(c=i._mergeStructures(i.getStructures()));let a=c.sharedLength||0;if(a>l)//if (maxSharedStructures <= 32 && sharedStructures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
|
|
51
|
+
let n=32<l||64<m+l,o=l+64,p=l+m+64;if(8256<p)throw new Error("Maximum maxSharedStructure + maxOwnStructure is 8192");let q=[],r=0,s=0;this.pack=this.encode=function(a,h){if(oa||(oa=new la(8192),pa=new DataView(oa.buffer,0,8192),ra=0),qa=oa.length-10,2048>qa-ra?(oa=new la(oa.length),pa=new DataView(oa.buffer,0,oa.length),qa=oa.length-10,ra=0):ra=2147483640&ra+7,b=ra,f=i.structuredClone?new Map:null,c=i.structures,c){c.uninitialized&&(c=i._mergeStructures(i.getStructures()));let a=c.sharedLength||0;if(a>l)//if (maxSharedStructures <= 32 && sharedStructures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
|
|
49
52
|
throw new Error("Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to "+c.sharedLength);if(!c.transitions){c.transitions=Object.create(null);for(let b,d=0;d<a;d++){if(b=c[d],!b)continue;let a,e=c.transitions;for(let c,d=0,f=b.length;d<f;d++)c=b[d],a=e[c],a||(a=e[c]=Object.create(null)),e=a;e[sa]=d+64}g=a}j||(c.nextId=a+64)}d&&(d=!1),e=c||[];try{// update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
50
|
-
if(t(a),i.offset=ra,f&&f.idsToInsert){ra+=6*f.idsToInsert.length,ra>qa&&x(ra),i.offset=ra;let a=v(oa.subarray(b,ra),f.idsToInsert);return f=null,a}return oa.subarray(b,ra);// position can change if we call pack again in saveStructures, so we get the buffer now
|
|
51
|
-
}finally{if(c){if(10>s&&s++,1e4<r)c.transitions=null,s=0,r=0,0<q.length&&(q=[]);else if(0<q.length&&!j){for(let a=0,b=q.length;a<b;a++)q[a][sa]=0;q=[]}if(d&&i.saveStructures){let
|
|
53
|
+
if(t(a),i.offset=ra,f&&f.idsToInsert){ra+=6*f.idsToInsert.length,ra>qa&&x(ra),i.offset=ra;let a=v(oa.subarray(b,ra),f.idsToInsert);return f=null,a}return h===Ba?(oa.start=b,oa.end=ra,oa):oa.subarray(b,ra);// position can change if we call pack again in saveStructures, so we get the buffer now
|
|
54
|
+
}finally{if(c){if(10>s&&s++,1e4<r)c.transitions=null,s=0,r=0,0<q.length&&(q=[]);else if(0<q.length&&!j){for(let a=0,b=q.length;a<b;a++)q[a][sa]=0;q=[]}if(d&&i.saveStructures){let d=c.sharedLength||l;c.length>d&&(c=c.slice(0,d));// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
55
|
+
let e=oa.subarray(b,ra);return!1===i.saveStructures(c,g)?(i._mergeStructures(i.getStructures()),i.pack(a)):(g=d,e)}}}};const t=a=>{ra>qa&&(oa=x(ra));var c,d=typeof a;if("string"==d){let b,d=a.length;b=32>d?1:256>d?2:65536>d?3:5;let e=3*d;if(ra+e>qa&&(oa=x(ra+e)),64>d||!h){let e,f,g,h=ra+b;for(e=0;e<d;e++)f=a.charCodeAt(e),128>f?oa[h++]=f:2048>f?(oa[h++]=192|f>>6,oa[h++]=128|63&f):55296==(64512&f)&&56320==(64512&(g=a.charCodeAt(e+1)))?(f=65536+((1023&f)<<10)+(1023&g),e++,oa[h++]=240|f>>18,oa[h++]=128|63&f>>12,oa[h++]=128|63&f>>6,oa[h++]=128|63&f):(oa[h++]=224|f>>12,oa[h++]=128|63&f>>6,oa[h++]=128|63&f);c=h-ra-b}else c=h(a,ra+b,e);32>c?oa[ra++]=160|c:256>c?(2>b&&oa.copyWithin(ra+2,ra+1,ra+1+c),oa[ra++]=217,oa[ra++]=c):65536>c?(3>b&&oa.copyWithin(ra+3,ra+2,ra+2+c),oa[ra++]=218,oa[ra++]=c>>8,oa[ra++]=255&c):(5>b&&oa.copyWithin(ra+5,ra+3,ra+3+c),oa[ra++]=219,pa.setUint32(ra,c),ra+=4),ra+=c}else if("number"===d){if(a>>>0===a)64>a?oa[ra++]=a:256>a?(oa[ra++]=204,oa[ra++]=a):65536>a?(oa[ra++]=205,oa[ra++]=a>>8,oa[ra++]=255&a):(oa[ra++]=206,pa.setUint32(ra,a),ra+=4);else if(a>>0===a)-32<=a?oa[ra++]=256+a:-128<=a?(oa[ra++]=208,oa[ra++]=a+256):-32768<=a?(oa[ra++]=209,pa.setInt16(ra,a),ra+=2):(oa[ra++]=210,pa.setInt32(ra,a),ra+=4);else{let b;if(0<(b=this.useFloat32)&&4294967296>a&&-2147483648<=a){oa[ra++]=202,pa.setFloat32(ra,a);let c;if(4>b||// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
52
56
|
(c=a*_[(127&oa[ra])<<1|oa[ra+1]>>7])>>0===c)return void(ra+=4);// move back into position for writing a double
|
|
53
57
|
ra--}oa[ra++]=203,pa.setFloat64(ra,a),ra+=8}}else if("object"===d){if(!a)oa[ra++]=192;else{if(f){let c=f.get(a);if(c){if(!c.id){let a=f.idsToInsert||(f.idsToInsert=[]);c.id=a.push(c)}return oa[ra++]=214,oa[ra++]=112,pa.setUint32(ra,c.id),void(ra+=4)}f.set(a,{offset:ra-b})}let d=a.constructor;if(d===Object)w(a,!0);else if(d===Array){c=a.length,16>c?oa[ra++]=144|c:65536>c?(oa[ra++]=220,oa[ra++]=c>>8,oa[ra++]=255&c):(oa[ra++]=221,pa.setUint32(ra,c),ra+=4);for(let b=0;b<c;b++)t(a[b])}else if(d===Map){c=a.size,16>c?oa[ra++]=128|c:65536>c?(oa[ra++]=222,oa[ra++]=c>>8,oa[ra++]=255&c):(oa[ra++]=223,pa.setUint32(ra,c),ra+=4);for(let[b,c]of a)t(b),t(c)}else{for(let b,c=0,d=ia.length;c<d;c++)if(b=ja[c],a instanceof b){let b=ia[c];if(b.write)return b.type&&(oa[ra++]=212,oa[ra++]=b.type,oa[ra++]=0),void t(b.write.call(this,a));let d=oa,e=pa,f=ra;oa=null;let g;try{g=b.pack.call(this,a,a=>(oa=d,d=null,ra+=a,ra>qa&&x(ra),{target:oa,targetView:pa,position:ra-a}),t)}finally{d&&(oa=d,pa=e,ra=f,qa=oa.length-10)}return void(g&&(g.length+ra>qa&&x(g.length+ra),ra=u(g,oa,ra,b.type)))}// no extension found, write as object
|
|
54
58
|
w(a,!a.hasOwnProperty)}}}else if("boolean"===d)oa[ra++]=a?195:194;else if("bigint"===d){if(a<BigInt(1)<<BigInt(63)&&a>=-(BigInt(1)<<BigInt(63)))oa[ra++]=211,pa.setBigInt64(ra,a);else if(a<BigInt(1)<<BigInt(64)&&0<a)oa[ra++]=207,pa.setBigUint64(ra,a);else// overflow
|
|
@@ -96,17 +100,17 @@ let d=ra-b;ra+=2;let e=0;for(let b in a)(c||a.hasOwnProperty(b))&&(t(b),t(a[b]),
|
|
|
96
100
|
}*/a=>{let b,c=Object.keys(a),f=e.transitions||(e.transitions=Object.create(null)),g=0;for(let d,e=0,h=c.length;e<h;e++)d=c[e],b=f[d],b||(b=f[d]=Object.create(null),g++),f=b;let h=f[sa];if(h)96<=h&&n?(oa[ra++]=(31&(h-=96))+96,oa[ra++]=h>>5):oa[ra++]=h;else{h=e.nextId,h||(h=64),h<o&&this.shouldShareStructure&&!this.shouldShareStructure(c)?(h=e.nextOwnId,!(h<p)&&(h=o),e.nextOwnId=h+1):(h>=p&&(// cycle back around
|
|
97
101
|
h=o),e.nextId=h+1);let a=c.highByte=96<=h&&n?h-96>>5:-1;f[sa]=h,e[h-64]=c,h<o?(c.isShared=!0,e.sharedLength=h-63,d=!0,0<=a?(oa[ra++]=(31&h)+96,oa[ra++]=a):oa[ra++]=h):(0<=a?(oa[ra++]=213,oa[ra++]=114,oa[ra++]=(31&h)+96,oa[ra++]=a):(oa[ra++]=212,oa[ra++]=114,oa[ra++]=h),g&&(r+=s*g),q.length>=m&&(q.shift()[sa]=0),q.push(f),t(c))}// now write the values
|
|
98
102
|
for(let b=0,d=c.length;b<d;b++)t(a[c[b]])},x=a=>{var c=Math.min,d=Math.round,e=Math.max;let f;if(16777216<a){// special handling for really large buffers
|
|
99
|
-
if(a-b>na)throw new Error("Packed buffer would be larger than maximum buffer size");f=c(na,4096*d(e((a-b)*(67108864<a?1.25:2),
|
|
103
|
+
if(a-b>na)throw new Error("Packed buffer would be larger than maximum buffer size");f=c(na,4096*d(e((a-b)*(67108864<a?1.25:2),4194304)/4096))}else// faster handling for smaller buffers
|
|
100
104
|
f=(e(a-b<<2,oa.length-1)>>12)+1<<12;let g=new la(f);return pa=new DataView(g.buffer,0,f),oa.copy?oa.copy(g,0,b,a):g.set(oa.slice(b,a)),ra-=b,b=0,qa=g.length-10,oa=g}}useBuffer(a){// this means we are finished using our own buffer and we can write over it safely
|
|
101
105
|
oa=a,pa=new DataView(oa.buffer,oa.byteOffset,oa.byteLength),ra=0}}ja=[Date,Set,Error,RegExp,ArrayBuffer,Object.getPrototypeOf(Uint8Array.prototype).constructor/*TypedArray*/,M],ia=[{pack(a,c){let d=a.getTime()/1e3;if((this.useTimestamp32||0===a.getMilliseconds())&&0<=d&&4294967296>d){// Timestamp 32
|
|
102
106
|
let{target:a,targetView:b,position:e}=c(6);a[e++]=214,a[e++]=255,b.setUint32(e,d)}else if(0<d&&17179869184>d){// Timestamp 64
|
|
103
107
|
let{target:b,targetView:e,position:f}=c(10);b[f++]=215,b[f++]=255,e.setUint32(f,4e6*a.getMilliseconds()+(d/1e3/4294967296>>0)),e.setUint32(f+4,d)}else{// Timestamp 96
|
|
104
108
|
let{target:e,targetView:f,position:g}=c(15);e[g++]=199,e[g++]=12,e[g++]=255,f.setUint32(g,1e6*a.getMilliseconds()),f.setBigInt64(g+4,BigInt(b(d)))}}},{pack(a,b,c){let d=Array.from(a),{target:e,position:f}=b(this.structuredClone?3:0);this.structuredClone&&(e[f++]=212,e[f++]=115,e[f++]=0),c(d)}},{pack(a,b,c){let{target:d,position:e}=b(this.structuredClone?3:0);this.structuredClone&&(d[e++]=212,d[e++]=101,d[e++]=0),c([a.name,a.message])}},{pack(a,b,c){let{target:d,position:e}=b(this.structuredClone?3:0);this.structuredClone&&(d[e++]=212,d[e++]=120,d[e++]=0),c([a.source,a.flags])}},{pack(a,b){this.structuredClone?s(a,16,b):t(ka?Buffer.from(a):new Uint8Array(a),b)}},{pack(a,b){let c=a.constructor;c!==ma&&this.structuredClone?s(a,$.indexOf(c.name),b):t(a,b)}},{pack(a,b){// specific 0xC1 object
|
|
105
|
-
let{target:c,position:d}=b(1);c[d]=193}}];let ua=new ta({useRecords:!1});const va=ua.pack,wa=ua.pack,{NEVER:xa,ALWAYS:ya,DECIMAL_ROUND:za,DECIMAL_FIT:Aa}=ea;a.ALWAYS=ya,a.C1=N,a.DECIMAL_FIT=Aa,a.DECIMAL_ROUND=za,a.Decoder=P,a.Encoder=ta,a.FLOAT32_OPTIONS=ea,a.NEVER=xa,a.Packr=ta,a.Unpackr=P,a.addExtension=w,a.clearSource=q,a.decode=da,a.decodeIter=function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise");const c=new P(b);let d;const e=a=>{let b;// if there's incomplete data from previous chunk, concatinate and try again
|
|
109
|
+
let{target:c,position:d}=b(1);c[d]=193}}];let ua=new ta({useRecords:!1});const va=ua.pack,wa=ua.pack,{NEVER:xa,ALWAYS:ya,DECIMAL_ROUND:za,DECIMAL_FIT:Aa}=ea,Ba=1e3;a.ALWAYS=ya,a.C1=N,a.DECIMAL_FIT=Aa,a.DECIMAL_ROUND=za,a.Decoder=P,a.Encoder=ta,a.FLOAT32_OPTIONS=ea,a.NEVER=xa,a.Packr=ta,a.REUSE_BUFFER_MODE=Ba,a.Unpackr=P,a.addExtension=w,a.clearSource=q,a.decode=da,a.decodeIter=function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise");const c=new P(b);let d;const e=a=>{let b;// if there's incomplete data from previous chunk, concatinate and try again
|
|
106
110
|
d&&(a=Buffer.concat([d,a]),d=void 0);try{b=c.unpackMultiple(a)}catch(c){if(c.incomplete)d=a.slice(c.lastPosition),b=c.values;else throw c}return b};if("function"==typeof a[Symbol.iterator])return function*(){for(const b of a)yield*e(b)}();return"function"==typeof a[Symbol.asyncIterator]?async function*(){for await(const b of a)yield*e(b)}():void 0},a.encode=wa,a.encodeIter=/**
|
|
107
111
|
* Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
|
|
108
112
|
* If the argument is only Async Iterable, the return value will be an Async Iterable.
|
|
109
113
|
* @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
|
|
110
114
|
* @param {options} [options] - msgpackr pack options
|
|
111
115
|
* @returns {IterableIterator|Promise.<AsyncIterableIterator>}
|
|
112
|
-
*/function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable");else{if("function"==typeof a[Symbol.iterator])return x(a,b);if("function"==typeof a.then||"function"==typeof a[Symbol.asyncIterator])return y(a,b);throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise")}},a.mapsAsObjects=!0,a.pack=va,a.roundFloat32=function(a){ga[0]=a;let b=_[(127&ha[3])<<1|ha[2]>>7];return(b*a+(0<a?.5:-.5)>>0)/b},a.unpack=ba,a.unpackMultiple=ca,a.useRecords=!1,Object.defineProperty(a,"__esModule",{value:!0})});
|
|
116
|
+
*/function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable");else{if("function"==typeof a[Symbol.iterator])return x(a,b);if("function"==typeof a.then||"function"==typeof a[Symbol.asyncIterator])return y(a,b);throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise")}},a.isNativeAccelerationEnabled=!1,a.mapsAsObjects=!0,a.pack=va,a.roundFloat32=function(a){ga[0]=a;let b=_[(127&ha[3])<<1|ha[2]>>7];return(b*a+(0<a?.5:-.5)>>0)/b},a.unpack=ba,a.unpackMultiple=ca,a.useRecords=!1,Object.defineProperty(a,"__esModule",{value:!0})});
|
package/dist/node.cjs
CHANGED
|
@@ -64,8 +64,16 @@ class Unpackr {
|
|
|
64
64
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
65
65
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
66
66
|
// new ones
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
try {
|
|
68
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
|
|
69
|
+
} catch(error) {
|
|
70
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
71
|
+
src = null;
|
|
72
|
+
if (source instanceof Uint8Array)
|
|
73
|
+
throw error
|
|
74
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
75
|
+
}
|
|
76
|
+
if (this instanceof Unpackr) {
|
|
69
77
|
currentUnpackr = this;
|
|
70
78
|
if (this.structures) {
|
|
71
79
|
currentStructures = this.structures;
|
|
@@ -297,10 +305,11 @@ function read() {
|
|
|
297
305
|
position += 4;
|
|
298
306
|
return value
|
|
299
307
|
case 0xcf:
|
|
300
|
-
if (currentUnpackr.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
308
|
+
if (currentUnpackr.int64AsNumber) {
|
|
309
|
+
value = dataView.getUint32(position) * 0x100000000;
|
|
310
|
+
value += dataView.getUint32(position + 4);
|
|
311
|
+
} else
|
|
312
|
+
value = dataView.getBigUint64(position);
|
|
304
313
|
position += 8;
|
|
305
314
|
return value
|
|
306
315
|
|
|
@@ -316,7 +325,11 @@ function read() {
|
|
|
316
325
|
position += 4;
|
|
317
326
|
return value
|
|
318
327
|
case 0xd3:
|
|
319
|
-
|
|
328
|
+
if (currentUnpackr.int64AsNumber) {
|
|
329
|
+
value = dataView.getInt32(position) * 0x100000000;
|
|
330
|
+
value += dataView.getUint32(position + 4);
|
|
331
|
+
} else
|
|
332
|
+
value = dataView.getBigInt64(position);
|
|
320
333
|
position += 8;
|
|
321
334
|
return value
|
|
322
335
|
|
|
@@ -465,8 +478,10 @@ var readFixedString = readStringJS;
|
|
|
465
478
|
var readString8 = readStringJS;
|
|
466
479
|
var readString16 = readStringJS;
|
|
467
480
|
var readString32 = readStringJS;
|
|
481
|
+
exports.isNativeAccelerationEnabled = false;
|
|
468
482
|
|
|
469
483
|
function setExtractor(extractStrings) {
|
|
484
|
+
exports.isNativeAccelerationEnabled = true;
|
|
470
485
|
readFixedString = readString(1);
|
|
471
486
|
readString8 = readString(2);
|
|
472
487
|
readString16 = readString(3);
|
|
@@ -1029,7 +1044,7 @@ class Packr extends Unpackr {
|
|
|
1029
1044
|
let transitionsCount = 0;
|
|
1030
1045
|
let serializationsSinceTransitionRebuild = 0;
|
|
1031
1046
|
|
|
1032
|
-
this.pack = this.encode = function(value) {
|
|
1047
|
+
this.pack = this.encode = function(value, encodeOptions) {
|
|
1033
1048
|
if (!target) {
|
|
1034
1049
|
target = new ByteArrayAllocate(8192);
|
|
1035
1050
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -1094,6 +1109,11 @@ class Packr extends Unpackr {
|
|
|
1094
1109
|
referenceMap = null;
|
|
1095
1110
|
return serialized
|
|
1096
1111
|
}
|
|
1112
|
+
if (encodeOptions === REUSE_BUFFER_MODE) {
|
|
1113
|
+
target.start = start;
|
|
1114
|
+
target.end = position$1;
|
|
1115
|
+
return target
|
|
1116
|
+
}
|
|
1097
1117
|
return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
1098
1118
|
} finally {
|
|
1099
1119
|
if (sharedStructures) {
|
|
@@ -1117,13 +1137,15 @@ class Packr extends Unpackr {
|
|
|
1117
1137
|
if (sharedStructures.length > sharedLength) {
|
|
1118
1138
|
sharedStructures = sharedStructures.slice(0, sharedLength);
|
|
1119
1139
|
}
|
|
1120
|
-
|
|
1140
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1141
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
1121
1142
|
if (packr.saveStructures(sharedStructures, lastSharedStructuresLength) === false) {
|
|
1122
1143
|
// get updated structures and try again if the update failed
|
|
1123
1144
|
packr._mergeStructures(packr.getStructures());
|
|
1124
1145
|
return packr.pack(value)
|
|
1125
1146
|
}
|
|
1126
1147
|
lastSharedStructuresLength = sharedLength;
|
|
1148
|
+
return returnBuffer
|
|
1127
1149
|
}
|
|
1128
1150
|
}
|
|
1129
1151
|
}
|
|
@@ -1140,9 +1162,9 @@ class Packr extends Unpackr {
|
|
|
1140
1162
|
// first we estimate the header size, so we can write to the correct location
|
|
1141
1163
|
if (strLength < 0x20) {
|
|
1142
1164
|
headerSize = 1;
|
|
1143
|
-
} else if (strLength <
|
|
1165
|
+
} else if (strLength < 0x100) {
|
|
1144
1166
|
headerSize = 2;
|
|
1145
|
-
} else if (strLength <
|
|
1167
|
+
} else if (strLength < 0x10000) {
|
|
1146
1168
|
headerSize = 3;
|
|
1147
1169
|
} else {
|
|
1148
1170
|
headerSize = 5;
|
|
@@ -1555,7 +1577,7 @@ class Packr extends Unpackr {
|
|
|
1555
1577
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
1556
1578
|
throw new Error('Packed buffer would be larger than maximum buffer size')
|
|
1557
1579
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
1558
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
1580
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
|
|
1559
1581
|
} else // faster handling for smaller buffers
|
|
1560
1582
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
|
|
1561
1583
|
let newBuffer = new ByteArrayAllocate(newSize);
|
|
@@ -1779,7 +1801,8 @@ let defaultPackr = new Packr({ useRecords: false });
|
|
|
1779
1801
|
const pack = defaultPackr.pack;
|
|
1780
1802
|
const encode = defaultPackr.pack;
|
|
1781
1803
|
const Encoder = Packr;
|
|
1782
|
-
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1804
|
+
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1805
|
+
const REUSE_BUFFER_MODE = 1000;
|
|
1783
1806
|
|
|
1784
1807
|
class PackrStream extends stream.Transform {
|
|
1785
1808
|
constructor(options) {
|
|
@@ -1931,9 +1954,7 @@ function tryRequire(moduleId) {
|
|
|
1931
1954
|
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)));
|
|
1932
1955
|
return require$1(moduleId)
|
|
1933
1956
|
} catch (error) {
|
|
1934
|
-
if (typeof window
|
|
1935
|
-
console.warn('Native extraction module not loaded, msgpackr will still run, but with decreased performance. ' + error.message.split('\n')[0]);
|
|
1936
|
-
else
|
|
1957
|
+
if (typeof window != 'undefined')
|
|
1937
1958
|
console.warn('For browser usage, directly use msgpackr/unpack or msgpackr/pack modules. ' + error.message.split('\n')[0]);
|
|
1938
1959
|
}
|
|
1939
1960
|
}
|
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);
|
|
@@ -1064,7 +1071,17 @@
|
|
|
1064
1071
|
var deserialized = packr.unpack(serialized);
|
|
1065
1072
|
assert.deepEqual(deserialized, data);
|
|
1066
1073
|
});
|
|
1067
|
-
|
|
1074
|
+
test('bigint to float', function() {
|
|
1075
|
+
var data = {
|
|
1076
|
+
a: 325283295382932843n
|
|
1077
|
+
};
|
|
1078
|
+
let packr = new Packr({
|
|
1079
|
+
int64AsNumber: true
|
|
1080
|
+
});
|
|
1081
|
+
var serialized = packr.pack(data);
|
|
1082
|
+
var deserialized = packr.unpack(serialized);
|
|
1083
|
+
assert.deepEqual(deserialized.a, 325283295382932843);
|
|
1084
|
+
});
|
|
1068
1085
|
test('numbers', function(){
|
|
1069
1086
|
var data = {
|
|
1070
1087
|
bigEncodable: 48978578104322,
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Unpackr, Decoder, unpack, decode, addExtension, FLOAT32_OPTIONS, clearSource } 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
|
-
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'
|
|
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, 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
|
@@ -58,7 +58,7 @@ export class Packr extends Unpackr {
|
|
|
58
58
|
let transitionsCount = 0
|
|
59
59
|
let serializationsSinceTransitionRebuild = 0
|
|
60
60
|
|
|
61
|
-
this.pack = this.encode = function(value) {
|
|
61
|
+
this.pack = this.encode = function(value, encodeOptions) {
|
|
62
62
|
if (!target) {
|
|
63
63
|
target = new ByteArrayAllocate(8192)
|
|
64
64
|
targetView = new DataView(target.buffer, 0, 8192)
|
|
@@ -123,6 +123,11 @@ export class Packr extends Unpackr {
|
|
|
123
123
|
referenceMap = null
|
|
124
124
|
return serialized
|
|
125
125
|
}
|
|
126
|
+
if (encodeOptions === REUSE_BUFFER_MODE) {
|
|
127
|
+
target.start = start
|
|
128
|
+
target.end = position
|
|
129
|
+
return target
|
|
130
|
+
}
|
|
126
131
|
return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
127
132
|
} finally {
|
|
128
133
|
if (sharedStructures) {
|
|
@@ -146,13 +151,15 @@ export class Packr extends Unpackr {
|
|
|
146
151
|
if (sharedStructures.length > sharedLength) {
|
|
147
152
|
sharedStructures = sharedStructures.slice(0, sharedLength)
|
|
148
153
|
}
|
|
149
|
-
|
|
154
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
155
|
+
let returnBuffer = target.subarray(start, position)
|
|
150
156
|
if (packr.saveStructures(sharedStructures, lastSharedStructuresLength) === false) {
|
|
151
157
|
// get updated structures and try again if the update failed
|
|
152
158
|
packr._mergeStructures(packr.getStructures())
|
|
153
159
|
return packr.pack(value)
|
|
154
160
|
}
|
|
155
161
|
lastSharedStructuresLength = sharedLength
|
|
162
|
+
return returnBuffer
|
|
156
163
|
}
|
|
157
164
|
}
|
|
158
165
|
}
|
|
@@ -169,9 +176,9 @@ export class Packr extends Unpackr {
|
|
|
169
176
|
// first we estimate the header size, so we can write to the correct location
|
|
170
177
|
if (strLength < 0x20) {
|
|
171
178
|
headerSize = 1
|
|
172
|
-
} else if (strLength <
|
|
179
|
+
} else if (strLength < 0x100) {
|
|
173
180
|
headerSize = 2
|
|
174
|
-
} else if (strLength <
|
|
181
|
+
} else if (strLength < 0x10000) {
|
|
175
182
|
headerSize = 3
|
|
176
183
|
} else {
|
|
177
184
|
headerSize = 5
|
|
@@ -584,7 +591,7 @@ export class Packr extends Unpackr {
|
|
|
584
591
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
585
592
|
throw new Error('Packed buffer would be larger than maximum buffer size')
|
|
586
593
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
587
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
594
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000)
|
|
588
595
|
} else // faster handling for smaller buffers
|
|
589
596
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12
|
|
590
597
|
let newBuffer = new ByteArrayAllocate(newSize)
|
|
@@ -817,3 +824,4 @@ export const Encoder = Packr
|
|
|
817
824
|
export { FLOAT32_OPTIONS } from './unpack.js'
|
|
818
825
|
import { FLOAT32_OPTIONS } from './unpack.js'
|
|
819
826
|
export const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS
|
|
827
|
+
export const REUSE_BUFFER_MODE = 1000
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msgpackr",
|
|
3
3
|
"author": "Kris Zyp",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"types": "./index.d.ts",
|
|
8
|
+
"main": "./dist/node.cjs",
|
|
9
|
+
"module": "./index.js",
|
|
8
10
|
"keywords": [
|
|
9
11
|
"MessagePack",
|
|
10
12
|
"msgpack",
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
"scripts": {
|
|
20
22
|
"benchmark": "node ./tests/benchmark.cjs",
|
|
21
23
|
"build": "rollup -c",
|
|
24
|
+
"dry-run": "npm publish --dry-run",
|
|
22
25
|
"prepare": "npm run build",
|
|
23
26
|
"test": "mocha tests/test**.*js -u tdd --experimental-json-modules"
|
|
24
27
|
},
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const data = require('./example4.json');
|
|
2
|
-
const { pack, unpack } = require('msgpackr/pack');
|
|
2
|
+
const { pack, unpack, Packr } = require('msgpackr/pack');
|
|
3
3
|
const chai = require('chai');
|
|
4
4
|
|
|
5
5
|
function tryRequire(module) {
|
|
6
6
|
try {
|
|
7
7
|
return require(module)
|
|
8
8
|
} catch(error) {
|
|
9
|
+
console.log(error)
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
//if (typeof chai === 'undefined') { chai = require('chai') }
|
|
@@ -13,6 +14,7 @@ const assert = chai.assert
|
|
|
13
14
|
//if (typeof msgpackr === 'undefined') { msgpackr = require('..') }
|
|
14
15
|
var msgpack_msgpack = tryRequire('@msgpack/msgpack');
|
|
15
16
|
var msgpack_lite = tryRequire('msgpack-lite');
|
|
17
|
+
var msgpack = tryRequire('msgpack');
|
|
16
18
|
|
|
17
19
|
const addCompatibilitySuite = (data) => () => {
|
|
18
20
|
if (msgpack_msgpack) {
|
|
@@ -41,8 +43,22 @@ const addCompatibilitySuite = (data) => () => {
|
|
|
41
43
|
assert.deepEqual(deserialized, data)
|
|
42
44
|
})
|
|
43
45
|
}
|
|
46
|
+
if (msgpack) {
|
|
47
|
+
test.skip('from msgpack', function(){
|
|
48
|
+
var serialized = msgpack.pack(data)
|
|
49
|
+
var deserialized = unpack(serialized)
|
|
50
|
+
assert.deepEqual(deserialized, data)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('to msgpack', function(){
|
|
54
|
+
var serialized = pack(data)
|
|
55
|
+
var deserialized = msgpack.unpack(serialized)
|
|
56
|
+
assert.deepEqual(deserialized, data)
|
|
57
|
+
})
|
|
58
|
+
}
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
suite('msgpackr compatibility tests (example)', addCompatibilitySuite(require('./example.json')))
|
|
47
62
|
suite('msgpackr compatibility tests (example4)', addCompatibilitySuite(require('./example4.json')))
|
|
48
|
-
suite('msgpackr compatibility tests (example5)', addCompatibilitySuite(require('./example5.json')))
|
|
63
|
+
suite('msgpackr compatibility tests (example5)', addCompatibilitySuite(require('./example5.json')))
|
|
64
|
+
suite.skip('msgpackr compatibility tests with dates', addCompatibilitySuite({ date: new Date() }))
|
package/tests/test.js
CHANGED
|
@@ -84,6 +84,13 @@ suite('msgpackr basic tests', function(){
|
|
|
84
84
|
assert.deepEqual(deserialized, data)
|
|
85
85
|
})
|
|
86
86
|
|
|
87
|
+
test('255 chars', function() {
|
|
88
|
+
const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W'
|
|
89
|
+
var serialized = pack(data)
|
|
90
|
+
var deserialized = unpack(serialized)
|
|
91
|
+
assert.equal(deserialized, data)
|
|
92
|
+
})
|
|
93
|
+
|
|
87
94
|
test('pack/unpack sample data', function(){
|
|
88
95
|
var data = sampleData
|
|
89
96
|
let structures = []
|
|
@@ -491,7 +498,17 @@ suite('msgpackr basic tests', function(){
|
|
|
491
498
|
var deserialized = packr.unpack(serialized)
|
|
492
499
|
assert.deepEqual(deserialized, data)
|
|
493
500
|
})
|
|
494
|
-
|
|
501
|
+
test('bigint to float', function() {
|
|
502
|
+
var data = {
|
|
503
|
+
a: 325283295382932843n
|
|
504
|
+
}
|
|
505
|
+
let packr = new Packr({
|
|
506
|
+
int64AsNumber: true
|
|
507
|
+
})
|
|
508
|
+
var serialized = packr.pack(data)
|
|
509
|
+
var deserialized = packr.unpack(serialized)
|
|
510
|
+
assert.deepEqual(deserialized.a, 325283295382932843)
|
|
511
|
+
})
|
|
495
512
|
test('numbers', function(){
|
|
496
513
|
var data = {
|
|
497
514
|
bigEncodable: 48978578104322,
|
package/unpack.d.ts
CHANGED
|
@@ -25,8 +25,10 @@ export interface Options {
|
|
|
25
25
|
interface Extension {
|
|
26
26
|
Class: Function
|
|
27
27
|
type: number
|
|
28
|
-
pack(value: any): Buffer | Uint8Array
|
|
29
|
-
unpack(messagePack: Buffer | Uint8Array): any
|
|
28
|
+
pack?(value: any): Buffer | Uint8Array
|
|
29
|
+
unpack?(messagePack: Buffer | Uint8Array): any
|
|
30
|
+
read?(datum: any): any
|
|
31
|
+
write?(instance: any): any
|
|
30
32
|
}
|
|
31
33
|
export class Unpackr {
|
|
32
34
|
constructor(options?: Options)
|
|
@@ -42,3 +44,4 @@ export function addExtension(extension: Extension): void
|
|
|
42
44
|
export function clearSource(): void
|
|
43
45
|
export function roundFloat32(float32Number: number): number
|
|
44
46
|
export const C1: {}
|
|
47
|
+
export let isNativeAccelerationEnabled: boolean
|
package/unpack.js
CHANGED
|
@@ -59,8 +59,16 @@ export class Unpackr {
|
|
|
59
59
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
60
60
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
61
61
|
// new ones
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
try {
|
|
63
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))
|
|
64
|
+
} catch(error) {
|
|
65
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
66
|
+
src = null
|
|
67
|
+
if (source instanceof Uint8Array)
|
|
68
|
+
throw error
|
|
69
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
70
|
+
}
|
|
71
|
+
if (this instanceof Unpackr) {
|
|
64
72
|
currentUnpackr = this
|
|
65
73
|
if (this.structures) {
|
|
66
74
|
currentStructures = this.structures
|
|
@@ -295,10 +303,11 @@ export function read() {
|
|
|
295
303
|
position += 4
|
|
296
304
|
return value
|
|
297
305
|
case 0xcf:
|
|
298
|
-
if (currentUnpackr.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
306
|
+
if (currentUnpackr.int64AsNumber) {
|
|
307
|
+
value = dataView.getUint32(position) * 0x100000000
|
|
308
|
+
value += dataView.getUint32(position + 4)
|
|
309
|
+
} else
|
|
310
|
+
value = dataView.getBigUint64(position)
|
|
302
311
|
position += 8
|
|
303
312
|
return value
|
|
304
313
|
|
|
@@ -314,7 +323,11 @@ export function read() {
|
|
|
314
323
|
position += 4
|
|
315
324
|
return value
|
|
316
325
|
case 0xd3:
|
|
317
|
-
|
|
326
|
+
if (currentUnpackr.int64AsNumber) {
|
|
327
|
+
value = dataView.getInt32(position) * 0x100000000
|
|
328
|
+
value += dataView.getUint32(position + 4)
|
|
329
|
+
} else
|
|
330
|
+
value = dataView.getBigInt64(position)
|
|
318
331
|
position += 8
|
|
319
332
|
return value
|
|
320
333
|
|
|
@@ -463,8 +476,10 @@ var readFixedString = readStringJS
|
|
|
463
476
|
var readString8 = readStringJS
|
|
464
477
|
var readString16 = readStringJS
|
|
465
478
|
var readString32 = readStringJS
|
|
479
|
+
export let isNativeAccelerationEnabled = false
|
|
466
480
|
|
|
467
481
|
export function setExtractor(extractStrings) {
|
|
482
|
+
isNativeAccelerationEnabled = true
|
|
468
483
|
readFixedString = readString(1)
|
|
469
484
|
readString8 = readString(2)
|
|
470
485
|
readString16 = readString(3)
|
|
@@ -951,8 +966,6 @@ export const mult10 = new Array(147) // this is a table matching binary exponent
|
|
|
951
966
|
for (let i = 0; i < 256; i++) {
|
|
952
967
|
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))
|
|
953
968
|
}
|
|
954
|
-
export const useRecords = false
|
|
955
|
-
export const mapsAsObjects = true
|
|
956
969
|
export const Decoder = Unpackr
|
|
957
970
|
var defaultUnpackr = new Unpackr({ useRecords: false })
|
|
958
971
|
export const unpack = defaultUnpackr.unpack
|