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 CHANGED
@@ -1,10 +1,11 @@
1
1
  # msgpackr
2
- [![license](https://img.shields.io/badge/license-MIT-brightgreen)](LICENSE)
3
2
  [![npm version](https://img.shields.io/npm/v/msgpackr.svg?style=flat-square)](https://www.npmjs.org/package/msgpackr)
3
+ [![npm version](https://img.shields.io/npm/dw/msgpackr)](https://www.npmjs.org/package/msgpackr)
4
4
  [![encode](https://img.shields.io/badge/encode-1.5GB%2Fs-yellow)](benchmark.md)
5
5
  [![decode](https://img.shields.io/badge/decode-2GB%2Fs-yellow)](benchmark.md)
6
6
  [![types](https://img.shields.io/npm/types/msgpackr)](README.md)
7
7
  [![module](https://img.shields.io/badge/module-ESM%2FCJS-blue)](README.md)
8
+ [![license](https://img.shields.io/badge/license-MIT-brightgreen)](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 unamiguously 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 use 32-bit when possible.
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 encoding. This can be useful for determine how a number will be stored prior to encoding it.
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
@@ -0,0 +1,11 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | ------------------ |
7
+ | 1.4.x | :white_check_mark: |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ Please report security vulnerabilities to kriszyp@gmail.com.
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
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
62
- if (this) {
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.uint64AsNumber)
295
- return src[position++] * 0x100000000000000 + src[position++] * 0x1000000000000 + src[position++] * 0x10000000000 + src[position++] * 0x100000000 +
296
- src[position++] * 0x1000000 + (src[position++] << 16) + (src[position++] << 8) + src[position++]
297
- value = dataView.getBigUint64(position);
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
- value = dataView.getBigInt64(position);
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 < 0xff) {
1118
+ } else if (strLength < 0x100) {
1098
1119
  headerSize = 2;
1099
- } else if (strLength < 0xff00) {
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), 0x1000000) / 0x1000) * 0x1000);
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.uint64AsNumber?72057594037927940*A[G++]+281474976710656*A[G++]+1099511627776*A[G++]+4294967296*A[G++]+16777216*A[G++]+(A[G++]<<16)+(A[G++]<<8)+A[G++]:(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 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)));if(B=-1<b?b:a.length,G=0,J=0,D=null,A=a,F=a.dataView||(a.dataView=new DataView(a.buffer,a.byteOffset,a.byteLength)),this){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,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)
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 b=c.sharedLength||l;if(c.length>b&&(c=c.slice(0,b)),!1===i.saveStructures(c,g))return i._mergeStructures(i.getStructures()),i.pack(a);g=b}}}};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:255>d?2:65280>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
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),16777216)/4096))}else// faster handling for smaller buffers
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
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
68
- if (this) {
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.uint64AsNumber)
301
- return src[position++] * 0x100000000000000 + src[position++] * 0x1000000000000 + src[position++] * 0x10000000000 + src[position++] * 0x100000000 +
302
- src[position++] * 0x1000000 + (src[position++] << 16) + (src[position++] << 8) + src[position++]
303
- value = dataView.getBigUint64(position);
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
- value = dataView.getBigInt64(position);
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 < 0xff) {
1165
+ } else if (strLength < 0x100) {
1144
1166
  headerSize = 2;
1145
- } else if (strLength < 0xff00) {
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), 0x1000000) / 0x1000) * 0x1000);
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 == 'undefined')
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 == 'undefined')
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 < 0xff) {
179
+ } else if (strLength < 0x100) {
173
180
  headerSize = 2
174
- } else if (strLength < 0xff00) {
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), 0x1000000) / 0x1000) * 0x1000)
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.4",
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
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))
63
- if (this) {
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.uint64AsNumber)
299
- return src[position++] * 0x100000000000000 + src[position++] * 0x1000000000000 + src[position++] * 0x10000000000 + src[position++] * 0x100000000 +
300
- src[position++] * 0x1000000 + (src[position++] << 16) + (src[position++] << 8) + src[position++]
301
- value = dataView.getBigUint64(position)
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
- value = dataView.getBigInt64(position)
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