msgpackr 1.4.3 → 1.4.7

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
@@ -176,10 +176,12 @@ const { ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
176
176
 
177
177
  * `ALWAYS` (1) - Always will encode non-integers (absolute less than 2147483648) as 32-bit float.
178
178
  * `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.
179
+ * `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
180
 
181
181
  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
182
 
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 decoding. This can be useful for determining how a number will be decoded prior to encoding it.
184
+
183
185
  ## Performance
184
186
  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):
185
187
 
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
@@ -917,7 +917,14 @@
917
917
  ALWAYS: 1,
918
918
  DECIMAL_ROUND: 3,
919
919
  DECIMAL_FIT: 4
920
- };
920
+ };
921
+ let f32Array = new Float32Array(1);
922
+ let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
923
+ function roundFloat32(float32Number) {
924
+ f32Array[0] = float32Number;
925
+ let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
926
+ return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
927
+ }
921
928
 
922
929
  let textEncoder;
923
930
  try {
@@ -976,7 +983,7 @@
976
983
  let transitionsCount = 0;
977
984
  let serializationsSinceTransitionRebuild = 0;
978
985
 
979
- this.pack = this.encode = function(value) {
986
+ this.pack = this.encode = function(value, encodeOptions) {
980
987
  if (!target) {
981
988
  target = new ByteArrayAllocate(8192);
982
989
  targetView = new DataView(target.buffer, 0, 8192);
@@ -1041,6 +1048,11 @@
1041
1048
  referenceMap = null;
1042
1049
  return serialized
1043
1050
  }
1051
+ if (encodeOptions === REUSE_BUFFER_MODE) {
1052
+ target.start = start;
1053
+ target.end = position$1;
1054
+ return target
1055
+ }
1044
1056
  return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
1045
1057
  } finally {
1046
1058
  if (sharedStructures) {
@@ -1064,13 +1076,15 @@
1064
1076
  if (sharedStructures.length > sharedLength) {
1065
1077
  sharedStructures = sharedStructures.slice(0, sharedLength);
1066
1078
  }
1067
-
1079
+ // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1080
+ let returnBuffer = target.subarray(start, position$1);
1068
1081
  if (packr.saveStructures(sharedStructures, lastSharedStructuresLength) === false) {
1069
1082
  // get updated structures and try again if the update failed
1070
1083
  packr._mergeStructures(packr.getStructures());
1071
1084
  return packr.pack(value)
1072
1085
  }
1073
1086
  lastSharedStructuresLength = sharedLength;
1087
+ return returnBuffer
1074
1088
  }
1075
1089
  }
1076
1090
  }
@@ -1191,7 +1205,7 @@
1191
1205
  targetView.setFloat32(position$1, value);
1192
1206
  let xShifted;
1193
1207
  if (useFloat32 < 4 ||
1194
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1208
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1195
1209
  ((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
1196
1210
  position$1 += 4;
1197
1211
  return
@@ -1726,7 +1740,8 @@
1726
1740
  const pack = defaultPackr.pack;
1727
1741
  const encode = defaultPackr.pack;
1728
1742
  const Encoder = Packr;
1729
- const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1743
+ const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1744
+ const REUSE_BUFFER_MODE = 1000;
1730
1745
 
1731
1746
  /**
1732
1747
  * Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
@@ -1825,6 +1840,7 @@
1825
1840
  exports.FLOAT32_OPTIONS = FLOAT32_OPTIONS;
1826
1841
  exports.NEVER = NEVER;
1827
1842
  exports.Packr = Packr;
1843
+ exports.REUSE_BUFFER_MODE = REUSE_BUFFER_MODE;
1828
1844
  exports.Unpackr = Unpackr;
1829
1845
  exports.addExtension = addExtension$1;
1830
1846
  exports.clearSource = clearSource;
@@ -1834,6 +1850,7 @@
1834
1850
  exports.encodeIter = encodeIter;
1835
1851
  exports.mapsAsObjects = mapsAsObjects;
1836
1852
  exports.pack = pack;
1853
+ exports.roundFloat32 = roundFloat32;
1837
1854
  exports.unpack = unpack;
1838
1855
  exports.unpackMultiple = unpackMultiple;
1839
1856
  exports.useRecords = useRecords;
package/dist/index.min.js CHANGED
@@ -28,7 +28,7 @@ function p(a){let b=B,c=G,d=I,e=J,f=D,g=E,h=new Uint8Array(A.slice(0,B)),i=C,j=C
28
28
  e[f++]=201,g.setUint32(f,d+1),f+=4}// "t" for typed array
29
29
  e[f++]=116,e[f++]=b,e.set(new Uint8Array(a.buffer,a.byteOffset,a.byteLength),f)}function t(a,b){let c=a.byteLength;var d,e;if(256>c){var{target:d,position:e}=b(c+2);d[e++]=196,d[e++]=c}else if(65536>c){var{target:d,position:e}=b(c+3);d[e++]=197,d[e++]=c>>8,d[e++]=255&c}else{var{target:d,position:e,targetView:f}=b(c+5);d[e++]=198,f.setUint32(e,c),e+=4}d.set(a,e)}function u(a,b,c,d){let e=a.length;return 1===e?b[c++]=212:2===e?b[c++]=213:4===e?b[c++]=214:8===e?b[c++]=215:16===e?b[c++]=216:256>e?(b[c++]=199,b[c++]=e):65536>e?(b[c++]=200,b[c++]=e>>8,b[c++]=255&e):(b[c++]=201,b[c++]=e>>24,b[c++]=255&e>>16,b[c++]=255&e>>8,b[c++]=255&e),b[c++]=d,b.set(a,c),c+=e,c}function v(a,b){// insert the ids that need to be referenced for structured clones
30
30
  let c,d=6*b.length,e=a.length-d;for(b.sort((c,a)=>c.offset>a.offset?1:-1);c=b.pop();){let b=c.offset,f=c.id;a.copyWithin(b+d,b,e),d-=6;let g=b+d;// 'i'
31
- a[g++]=214,a[g++]=105,a[g++]=f>>24,a[g++]=255&f>>16,a[g++]=255&f>>8,a[g++]=255&f,e=b}return a}function w(a){if(a.Class){if(!a.pack&&!a.write)throw new Error("Extension has no pack or write function");if(a.pack&&!a.type)throw new Error("Extension has no type (numeric code to identify the extension)");ha.unshift(a.Class),ga.unshift(a)}r(a)}function*x(a,b){const c=new ra(b);for(const d of a)yield c.pack(d)}async function*y(a,b){const c=new ra(b);for await(const d of a)yield c.pack(d)}/**
31
+ a[g++]=214,a[g++]=105,a[g++]=f>>24,a[g++]=255&f>>16,a[g++]=255&f>>8,a[g++]=255&f,e=b}return a}function w(a){if(a.Class){if(!a.pack&&!a.write)throw new Error("Extension has no pack or write function");if(a.pack&&!a.type)throw new Error("Extension has no type (numeric code to identify the extension)");ja.unshift(a.Class),ia.unshift(a)}r(a)}function*x(a,b){const c=new ta(b);for(const d of a)yield c.pack(d)}async function*y(a,b){const c=new ta(b);for await(const d of a)yield c.pack(d)}/**
32
32
  * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
33
33
  * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
34
34
  * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
@@ -44,17 +44,18 @@ let a=F.getUint32(G-4),b=E.get(a);return b.used=!0,b.target},K[115]=()=>new Set(
44
44
  return new Z[c](Uint8Array.prototype.slice.call(a,1).buffer)},K[120]=()=>{let a=e();return new RegExp(a[0],a[1])},K[255]=a=>{// 32-bit date extension
45
45
  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
46
  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
- 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;try{fa=new TextEncoder}catch(a){}let ga,ha;const ia="undefined"!=typeof Buffer,ja=ia?Buffer.allocUnsafeSlow:Uint8Array,ka=ia?Buffer:Uint8Array,la=ia?4294967296:2144337920;let ma,na,oa,pa=0;const qa=Symbol("record-id");class ra extends P{constructor(a){super(a),this.offset=0;let b,c,d,e,f,g=0,h=ka.prototype.utf8Write?function(a,b,c){return ma.utf8Write(a,b,c)}:!!(fa&&fa.encodeInto)&&function(a,b){return fa.encodeInto(a,ma.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(ma||(ma=new ja(8192),na=new DataView(ma.buffer,0,8192),pa=0),oa=ma.length-10,2048>oa-pa?(ma=new ja(ma.length),na=new DataView(ma.buffer,0,ma.length),oa=ma.length-10,pa=0):pa=2147483640&pa+7,b=pa,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
- 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[qa]=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=pa,f&&f.idsToInsert){pa+=6*f.idsToInsert.length,pa>oa&&x(pa),i.offset=pa;let a=v(ma.subarray(b,pa),f.idsToInsert);return f=null,a}return ma.subarray(b,pa);// 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][qa]=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=>{pa>oa&&(ma=x(pa));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(pa+e>oa&&(ma=x(pa+e)),64>d||!h){let e,f,g,h=pa+b;for(e=0;e<d;e++)f=a.charCodeAt(e),128>f?ma[h++]=f:2048>f?(ma[h++]=192|f>>6,ma[h++]=128|63&f):55296==(64512&f)&&56320==(64512&(g=a.charCodeAt(e+1)))?(f=65536+((1023&f)<<10)+(1023&g),e++,ma[h++]=240|f>>18,ma[h++]=128|63&f>>12,ma[h++]=128|63&f>>6,ma[h++]=128|63&f):(ma[h++]=224|f>>12,ma[h++]=128|63&f>>6,ma[h++]=128|63&f);c=h-pa-b}else c=h(a,pa+b,e);32>c?ma[pa++]=160|c:256>c?(2>b&&ma.copyWithin(pa+2,pa+1,pa+1+c),ma[pa++]=217,ma[pa++]=c):65536>c?(3>b&&ma.copyWithin(pa+3,pa+2,pa+2+c),ma[pa++]=218,ma[pa++]=c>>8,ma[pa++]=255&c):(5>b&&ma.copyWithin(pa+5,pa+3,pa+3+c),ma[pa++]=219,na.setUint32(pa,c),pa+=4),pa+=c}else if("number"===d){if(a>>>0===a)64>a?ma[pa++]=a:256>a?(ma[pa++]=204,ma[pa++]=a):65536>a?(ma[pa++]=205,ma[pa++]=a>>8,ma[pa++]=255&a):(ma[pa++]=206,na.setUint32(pa,a),pa+=4);else if(a>>0===a)-32<=a?ma[pa++]=256+a:-128<=a?(ma[pa++]=208,ma[pa++]=a+256):-32768<=a?(ma[pa++]=209,na.setInt16(pa,a),pa+=2):(ma[pa++]=210,na.setInt32(pa,a),pa+=4);else{let b;if(0<(b=this.useFloat32)&&4294967296>a&&-2147483648<=a){ma[pa++]=202,na.setFloat32(pa,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
- (c=a*_[(127&ma[pa])<<1|ma[pa+1]>>7])>>0===c)return void(pa+=4);// move back into position for writing a double
53
- pa--}ma[pa++]=203,na.setFloat64(pa,a),pa+=8}}else if("object"===d){if(!a)ma[pa++]=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 ma[pa++]=214,ma[pa++]=112,na.setUint32(pa,c.id),void(pa+=4)}f.set(a,{offset:pa-b})}let d=a.constructor;if(d===Object)w(a,!0);else if(d===Array){c=a.length,16>c?ma[pa++]=144|c:65536>c?(ma[pa++]=220,ma[pa++]=c>>8,ma[pa++]=255&c):(ma[pa++]=221,na.setUint32(pa,c),pa+=4);for(let b=0;b<c;b++)t(a[b])}else if(d===Map){c=a.size,16>c?ma[pa++]=128|c:65536>c?(ma[pa++]=222,ma[pa++]=c>>8,ma[pa++]=255&c):(ma[pa++]=223,na.setUint32(pa,c),pa+=4);for(let[b,c]of a)t(b),t(c)}else{for(let b,c=0,d=ga.length;c<d;c++)if(b=ha[c],a instanceof b){let b=ga[c];if(b.write)return b.type&&(ma[pa++]=212,ma[pa++]=b.type,ma[pa++]=0),void t(b.write.call(this,a));let d=ma,e=na,f=pa;ma=null;let g;try{g=b.pack.call(this,a,a=>(ma=d,d=null,pa+=a,pa>oa&&x(pa),{target:ma,targetView:na,position:pa-a}),t)}finally{d&&(ma=d,na=e,pa=f,oa=ma.length-10)}return void(g&&(g.length+pa>oa&&x(g.length+pa),pa=u(g,ma,pa,b.type)))}// no extension found, write as object
54
- w(a,!a.hasOwnProperty)}}}else if("boolean"===d)ma[pa++]=a?195:194;else if("bigint"===d){if(a<BigInt(1)<<BigInt(63)&&a>=-(BigInt(1)<<BigInt(63)))ma[pa++]=211,na.setBigInt64(pa,a);else if(a<BigInt(1)<<BigInt(64)&&0<a)ma[pa++]=207,na.setBigUint64(pa,a);else// overflow
55
- if(this.largeBigIntToFloat)ma[pa++]=203,na.setFloat64(pa,+a);else throw new RangeError(a+" was too large to fit in MessagePack 64-bit integer format, set largeBigIntToFloat to convert to float-64");pa+=8}else if("undefined"===d)this.encodeUndefinedAsNil?ma[pa++]=192:(ma[pa++]=212,ma[pa++]=0,ma[pa++]=0);else if("function"===d)t(this.writeFunction&&this.writeFunction());else throw new Error("Unknown type: "+d)},w=!1===this.useRecords?this.variableMapSize?a=>{// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
56
- let b=Object.keys(a),c=b.length;16>c?ma[pa++]=128|c:65536>c?(ma[pa++]=222,ma[pa++]=c>>8,ma[pa++]=255&c):(ma[pa++]=223,na.setUint32(pa,c),pa+=4);let d;for(let e=0;e<c;e++)t(d=b[e]),t(a[d])}:(a,c)=>{ma[pa++]=222;// always using map 16, so we can preallocate and set the length afterwards
57
- let d=pa-b;pa+=2;let e=0;for(let b in a)(c||a.hasOwnProperty(b))&&(t(b),t(a[b]),e++);ma[d++ +b]=e>>8,ma[d+b]=255&e}:/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
47
+ 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,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
+ 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 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
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 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
52
+ 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
53
+ (c=a*_[(127&oa[ra])<<1|oa[ra+1]>>7])>>0===c)return void(ra+=4);// move back into position for writing a double
54
+ 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
55
+ 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
56
+ if(this.largeBigIntToFloat)oa[ra++]=203,pa.setFloat64(ra,+a);else throw new RangeError(a+" was too large to fit in MessagePack 64-bit integer format, set largeBigIntToFloat to convert to float-64");ra+=8}else if("undefined"===d)this.encodeUndefinedAsNil?oa[ra++]=192:(oa[ra++]=212,oa[ra++]=0,oa[ra++]=0);else if("function"===d)t(this.writeFunction&&this.writeFunction());else throw new Error("Unknown type: "+d)},w=!1===this.useRecords?this.variableMapSize?a=>{// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
57
+ let b=Object.keys(a),c=b.length;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);let d;for(let e=0;e<c;e++)t(d=b[e]),t(a[d])}:(a,c)=>{oa[ra++]=222;// always using map 16, so we can preallocate and set the length afterwards
58
+ let d=ra-b;ra+=2;let e=0;for(let b in a)(c||a.hasOwnProperty(b))&&(t(b),t(a[b]),e++);oa[d++ +b]=e>>8,oa[d+b]=255&e}:/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
58
59
  (object, safePrototype) => {
59
60
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
60
61
  let objectOffset = position++ - start
@@ -93,20 +94,20 @@ let d=pa-b;pa+=2;let e=0;for(let b in a)(c||a.hasOwnProperty(b))&&(t(b),t(a[b]),
93
94
  sharedStructures.onUpdate(id, transition.__keys__)
94
95
  }
95
96
  target[objectOffset + start] = id
96
- }*/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[qa];if(h)96<=h&&n?(ma[pa++]=(31&(h-=96))+96,ma[pa++]=h>>5):ma[pa++]=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
- h=o),e.nextId=h+1);let a=c.highByte=96<=h&&n?h-96>>5:-1;f[qa]=h,e[h-64]=c,h<o?(c.isShared=!0,e.sharedLength=h-63,d=!0,0<=a?(ma[pa++]=(31&h)+96,ma[pa++]=a):ma[pa++]=h):(0<=a?(ma[pa++]=213,ma[pa++]=114,ma[pa++]=(31&h)+96,ma[pa++]=a):(ma[pa++]=212,ma[pa++]=114,ma[pa++]=h),g&&(r+=s*g),q.length>=m&&(q.shift()[qa]=0),q.push(f),t(c))}// now write the values
97
+ }*/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
98
+ 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
99
  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>la)throw new Error("Packed buffer would be larger than maximum buffer size");f=c(la,4096*d(e((a-b)*(67108864<a?1.25:2),16777216)/4096))}else// faster handling for smaller buffers
100
- f=(e(a-b<<2,ma.length-1)>>12)+1<<12;let g=new ja(f);return na=new DataView(g.buffer,0,f),ma.copy?ma.copy(g,0,b,a):g.set(ma.slice(b,a)),pa-=b,b=0,oa=g.length-10,ma=g}}useBuffer(a){// this means we are finished using our own buffer and we can write over it safely
101
- ma=a,na=new DataView(ma.buffer,ma.byteOffset,ma.byteLength),pa=0}}ha=[Date,Set,Error,RegExp,ArrayBuffer,Object.getPrototypeOf(Uint8Array.prototype).constructor/*TypedArray*/,M],ga=[{pack(a,c){let d=a.getTime()/1e3;if((this.useTimestamp32||0===a.getMilliseconds())&&0<=d&&4294967296>d){// Timestamp 32
100
+ 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
101
+ 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
102
+ 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
103
  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
104
  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
- 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(ia?Buffer.from(a):new Uint8Array(a),b)}},{pack(a,b){let c=a.constructor;c!==ka&&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 sa=new ra({useRecords:!1});const ta=sa.pack,ua=sa.pack,{NEVER:va,ALWAYS:wa,DECIMAL_ROUND:xa,DECIMAL_FIT:ya}=ea;a.ALWAYS=wa,a.C1=N,a.DECIMAL_FIT=ya,a.DECIMAL_ROUND=xa,a.Decoder=P,a.Encoder=ra,a.FLOAT32_OPTIONS=ea,a.NEVER=va,a.Packr=ra,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
- 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=ua,a.encodeIter=/**
105
+ 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
106
+ 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
107
+ 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
108
  * Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
108
109
  * If the argument is only Async Iterable, the return value will be an Async Iterable.
109
110
  * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
110
111
  * @param {options} [options] - msgpackr pack options
111
112
  * @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=ta,a.unpack=ba,a.unpackMultiple=ca,a.useRecords=!1,Object.defineProperty(a,"__esModule",{value:!0})});
113
+ */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})});
package/dist/node.cjs CHANGED
@@ -963,7 +963,14 @@ const FLOAT32_OPTIONS = {
963
963
  ALWAYS: 1,
964
964
  DECIMAL_ROUND: 3,
965
965
  DECIMAL_FIT: 4
966
- };
966
+ };
967
+ let f32Array = new Float32Array(1);
968
+ let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
969
+ function roundFloat32(float32Number) {
970
+ f32Array[0] = float32Number;
971
+ let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
972
+ return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
973
+ }
967
974
 
968
975
  let textEncoder;
969
976
  try {
@@ -1022,7 +1029,7 @@ class Packr extends Unpackr {
1022
1029
  let transitionsCount = 0;
1023
1030
  let serializationsSinceTransitionRebuild = 0;
1024
1031
 
1025
- this.pack = this.encode = function(value) {
1032
+ this.pack = this.encode = function(value, encodeOptions) {
1026
1033
  if (!target) {
1027
1034
  target = new ByteArrayAllocate(8192);
1028
1035
  targetView = new DataView(target.buffer, 0, 8192);
@@ -1087,6 +1094,11 @@ class Packr extends Unpackr {
1087
1094
  referenceMap = null;
1088
1095
  return serialized
1089
1096
  }
1097
+ if (encodeOptions === REUSE_BUFFER_MODE) {
1098
+ target.start = start;
1099
+ target.end = position$1;
1100
+ return target
1101
+ }
1090
1102
  return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
1091
1103
  } finally {
1092
1104
  if (sharedStructures) {
@@ -1110,13 +1122,15 @@ class Packr extends Unpackr {
1110
1122
  if (sharedStructures.length > sharedLength) {
1111
1123
  sharedStructures = sharedStructures.slice(0, sharedLength);
1112
1124
  }
1113
-
1125
+ // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1126
+ let returnBuffer = target.subarray(start, position$1);
1114
1127
  if (packr.saveStructures(sharedStructures, lastSharedStructuresLength) === false) {
1115
1128
  // get updated structures and try again if the update failed
1116
1129
  packr._mergeStructures(packr.getStructures());
1117
1130
  return packr.pack(value)
1118
1131
  }
1119
1132
  lastSharedStructuresLength = sharedLength;
1133
+ return returnBuffer
1120
1134
  }
1121
1135
  }
1122
1136
  }
@@ -1237,7 +1251,7 @@ class Packr extends Unpackr {
1237
1251
  targetView.setFloat32(position$1, value);
1238
1252
  let xShifted;
1239
1253
  if (useFloat32 < 4 ||
1240
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1254
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1241
1255
  ((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
1242
1256
  position$1 += 4;
1243
1257
  return
@@ -1772,7 +1786,8 @@ let defaultPackr = new Packr({ useRecords: false });
1772
1786
  const pack = defaultPackr.pack;
1773
1787
  const encode = defaultPackr.pack;
1774
1788
  const Encoder = Packr;
1775
- const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1789
+ const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1790
+ const REUSE_BUFFER_MODE = 1000;
1776
1791
 
1777
1792
  class PackrStream extends stream.Transform {
1778
1793
  constructor(options) {
@@ -1953,6 +1968,7 @@ exports.encode = encode;
1953
1968
  exports.encodeIter = encodeIter;
1954
1969
  exports.mapsAsObjects = mapsAsObjects;
1955
1970
  exports.pack = pack;
1971
+ exports.roundFloat32 = roundFloat32;
1956
1972
  exports.unpack = unpack;
1957
1973
  exports.unpackMultiple = unpackMultiple;
1958
1974
  exports.useRecords = useRecords;
package/dist/test.js CHANGED
@@ -594,6 +594,7 @@
594
594
  var Packr = msgpackr.Packr;
595
595
  var unpack = msgpackr.unpack;
596
596
  var unpackMultiple = msgpackr.unpackMultiple;
597
+ var roundFloat32 = msgpackr.roundFloat32;
597
598
  var pack = msgpackr.pack;
598
599
  var DECIMAL_FIT = msgpackr.FLOAT32_OPTIONS.DECIMAL_FIT;
599
600
 
@@ -659,6 +660,13 @@
659
660
  assert.deepEqual(deserialized, data);
660
661
  });
661
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
+
662
670
  test('pack/unpack sample data', function(){
663
671
  var data = sampleData;
664
672
  var serialized = pack(data);
@@ -1104,6 +1112,11 @@
1104
1112
  assert.isTrue(deserialized.tooBig > 2n**65n);
1105
1113
  });
1106
1114
 
1115
+ test('roundFloat32', function() {
1116
+ assert.equal(roundFloat32(0.00333000003), 0.00333);
1117
+ assert.equal(roundFloat32(43.29999999993), 43.3);
1118
+ });
1119
+
1107
1120
  test('buffers', function(){
1108
1121
  var data = {
1109
1122
  buffer1: new Uint8Array([2,3,4]),
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 } 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 } 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 } 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} from './unpack.js'
2
+ export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } 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
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
  }
@@ -273,7 +280,7 @@ export class Packr extends Unpackr {
273
280
  targetView.setFloat32(position, value)
274
281
  let xShifted
275
282
  if (useFloat32 < 4 ||
276
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
283
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
277
284
  ((xShifted = value * mult10[((target[position] & 0x7f) << 1) | (target[position + 1] >> 7)]) >> 0) === xShifted) {
278
285
  position += 4
279
286
  return
@@ -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.3",
4
+ "version": "1.4.7",
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
  },
@@ -47,7 +50,7 @@
47
50
  }
48
51
  },
49
52
  "optionalDependencies": {
50
- "msgpackr-extract": "^1.0.13"
53
+ "msgpackr-extract": "^1.0.14"
51
54
  },
52
55
  "devDependencies": {
53
56
  "@rollup/plugin-json": "^4.1.0",
@@ -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
@@ -15,6 +15,7 @@ var assert = chai.assert
15
15
  var Packr = msgpackr.Packr
16
16
  var unpack = msgpackr.unpack
17
17
  var unpackMultiple = msgpackr.unpackMultiple
18
+ var roundFloat32 = msgpackr.roundFloat32
18
19
  var pack = msgpackr.pack
19
20
  var DECIMAL_FIT = msgpackr.FLOAT32_OPTIONS.DECIMAL_FIT
20
21
 
@@ -83,6 +84,13 @@ suite('msgpackr basic tests', function(){
83
84
  assert.deepEqual(deserialized, data)
84
85
  })
85
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
+
86
94
  test('pack/unpack sample data', function(){
87
95
  var data = sampleData
88
96
  let structures = []
@@ -531,6 +539,11 @@ suite('msgpackr basic tests', function(){
531
539
  assert.isTrue(deserialized.tooBig > 2n**65n)
532
540
  })
533
541
 
542
+ test('roundFloat32', function() {
543
+ assert.equal(roundFloat32(0.00333000003), 0.00333)
544
+ assert.equal(roundFloat32(43.29999999993), 43.3)
545
+ })
546
+
534
547
  test('buffers', function(){
535
548
  var data = {
536
549
  buffer1: new Uint8Array([2,3,4]),
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)
@@ -40,4 +42,5 @@ export function unpackMultiple(messagePack: Buffer | Uint8Array, forEach?: (valu
40
42
  export function decode(messagePack: Buffer | Uint8Array): any
41
43
  export function addExtension(extension: Extension): void
42
44
  export function clearSource(): void
45
+ export function roundFloat32(float32Number: number): number
43
46
  export const C1: {}
package/unpack.js CHANGED
@@ -964,3 +964,10 @@ export const FLOAT32_OPTIONS = {
964
964
  DECIMAL_ROUND: 3,
965
965
  DECIMAL_FIT: 4
966
966
  }
967
+ let f32Array = new Float32Array(1)
968
+ let u8Array = new Uint8Array(f32Array.buffer, 0, 4)
969
+ export function roundFloat32(float32Number) {
970
+ f32Array[0] = float32Number
971
+ let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
972
+ return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
973
+ }