msgpackr 1.4.6 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.cjs CHANGED
@@ -20,6 +20,7 @@ var currentStructures;
20
20
  var srcString;
21
21
  var srcStringStart = 0;
22
22
  var srcStringEnd = 0;
23
+ var bundledStrings;
23
24
  var referenceMap;
24
25
  var currentExtensions = [];
25
26
  var dataView;
@@ -60,12 +61,21 @@ class Unpackr {
60
61
  srcStringEnd = 0;
61
62
  srcString = null;
62
63
  strings = EMPTY_ARRAY;
64
+ bundledStrings = null;
63
65
  src = source;
64
66
  // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
65
67
  // technique for getting data from a database where it can be copied into an existing buffer instead of creating
66
68
  // new ones
67
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
68
- if (this) {
69
+ try {
70
+ dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
71
+ } catch(error) {
72
+ // if it doesn't have a buffer, maybe it is the wrong type of object
73
+ src = null;
74
+ if (source instanceof Uint8Array)
75
+ throw error
76
+ throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
77
+ }
78
+ if (this instanceof Unpackr) {
69
79
  currentUnpackr = this;
70
80
  if (this.structures) {
71
81
  currentStructures = this.structures;
@@ -242,7 +252,15 @@ function read() {
242
252
  let value;
243
253
  switch (token) {
244
254
  case 0xc0: return null
245
- case 0xc1: return C1; // "never-used", return special object to denote that
255
+ case 0xc1:
256
+ if (bundledStrings) {
257
+ value = read(); // followed by the length of the string in characters (not bytes!)
258
+ if (value > 0)
259
+ return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
260
+ else
261
+ return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 -= value)
262
+ }
263
+ return C1; // "never-used", return special object to denote that
246
264
  case 0xc2: return false
247
265
  case 0xc3: return true
248
266
  case 0xc4:
@@ -297,10 +315,11 @@ function read() {
297
315
  position += 4;
298
316
  return value
299
317
  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);
318
+ if (currentUnpackr.int64AsNumber) {
319
+ value = dataView.getUint32(position) * 0x100000000;
320
+ value += dataView.getUint32(position + 4);
321
+ } else
322
+ value = dataView.getBigUint64(position);
304
323
  position += 8;
305
324
  return value
306
325
 
@@ -316,7 +335,11 @@ function read() {
316
335
  position += 4;
317
336
  return value
318
337
  case 0xd3:
319
- value = dataView.getBigInt64(position);
338
+ if (currentUnpackr.int64AsNumber) {
339
+ value = dataView.getInt32(position) * 0x100000000;
340
+ value += dataView.getUint32(position + 4);
341
+ } else
342
+ value = dataView.getBigInt64(position);
320
343
  position += 8;
321
344
  return value
322
345
 
@@ -465,8 +488,10 @@ var readFixedString = readStringJS;
465
488
  var readString8 = readStringJS;
466
489
  var readString16 = readStringJS;
467
490
  var readString32 = readStringJS;
491
+ exports.isNativeAccelerationEnabled = false;
468
492
 
469
493
  function setExtractor(extractStrings) {
494
+ exports.isNativeAccelerationEnabled = true;
470
495
  readFixedString = readString(1);
471
496
  readString8 = readString(2);
472
497
  readString16 = readString(3);
@@ -885,6 +910,22 @@ currentExtensions[0x78] = () => {
885
910
  return new RegExp(data[0], data[1])
886
911
  };
887
912
 
913
+ currentExtensions[0x62] = (data) => {
914
+ let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
915
+ let dataPosition = position;
916
+ position += dataSize - 4;
917
+ bundledStrings = [read(), read()];
918
+ bundledStrings.position0 = 0;
919
+ bundledStrings.position1 = 0;
920
+ let postBundlePosition = position;
921
+ position = dataPosition;
922
+ try {
923
+ return read()
924
+ } finally {
925
+ position = postBundlePosition;
926
+ }
927
+ };
928
+
888
929
  currentExtensions[0xff] = (data) => {
889
930
  // 32-bit date extension
890
931
  if (data.length == 4)
@@ -898,7 +939,7 @@ currentExtensions[0xff] = (data) => {
898
939
  ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
899
940
  (((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
900
941
  else
901
- throw new Error('Invalid timestamp length')
942
+ return new Date('invalid')
902
943
  }; // notepack defines extension 0 to mean undefined, so use that as the default here
903
944
  // registration of bulk record definition?
904
945
  // currentExtensions[0x52] = () =>
@@ -912,6 +953,7 @@ function saveState(callback) {
912
953
  let savedSrcString = srcString;
913
954
  let savedStrings = strings;
914
955
  let savedReferenceMap = referenceMap;
956
+ let savedBundledStrings = bundledStrings;
915
957
 
916
958
  // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
917
959
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
@@ -928,6 +970,7 @@ function saveState(callback) {
928
970
  srcString = savedSrcString;
929
971
  strings = savedStrings;
930
972
  referenceMap = savedReferenceMap;
973
+ bundledStrings = savedBundledStrings;
931
974
  src = savedSrc;
932
975
  sequentialMode = savedSequentialMode;
933
976
  currentStructures = savedStructures;
@@ -985,6 +1028,8 @@ let target;
985
1028
  let targetView;
986
1029
  let position$1 = 0;
987
1030
  let safeEnd;
1031
+ let bundledStrings$1 = null;
1032
+ const hasNonLatin = /[\u0080-\uFFFF]/;
988
1033
  const RECORD_SYMBOL = Symbol('record-id');
989
1034
  class Packr extends Unpackr {
990
1035
  constructor(options) {
@@ -1046,6 +1091,14 @@ class Packr extends Unpackr {
1046
1091
  position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
1047
1092
  start = position$1;
1048
1093
  referenceMap = packr.structuredClone ? new Map() : null;
1094
+ if (packr.bundleStrings) {
1095
+ bundledStrings$1 = ['', ''];
1096
+ target[position$1++] = 0xd6;
1097
+ target[position$1++] = 0x62; // 'b'
1098
+ bundledStrings$1.position = position$1 - start;
1099
+ position$1 += 4;
1100
+ } else
1101
+ bundledStrings$1 = null;
1049
1102
  sharedStructures = packr.structures;
1050
1103
  if (sharedStructures) {
1051
1104
  if (sharedStructures.uninitialized)
@@ -1084,6 +1137,13 @@ class Packr extends Unpackr {
1084
1137
  structures = sharedStructures || [];
1085
1138
  try {
1086
1139
  pack(value);
1140
+ if (bundledStrings$1) {
1141
+ targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
1142
+ let writeStrings = bundledStrings$1;
1143
+ bundledStrings$1 = null;
1144
+ pack(writeStrings[0]);
1145
+ pack(writeStrings[1]);
1146
+ }
1087
1147
  packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
1088
1148
  if (referenceMap && referenceMap.idsToInsert) {
1089
1149
  position$1 += referenceMap.idsToInsert.length * 6;
@@ -1094,7 +1154,7 @@ class Packr extends Unpackr {
1094
1154
  referenceMap = null;
1095
1155
  return serialized
1096
1156
  }
1097
- if (encodeOptions === REUSE_BUFFER_MODE) {
1157
+ if (encodeOptions & REUSE_BUFFER_MODE) {
1098
1158
  target.start = start;
1099
1159
  target.end = position$1;
1100
1160
  return target
@@ -1133,6 +1193,8 @@ class Packr extends Unpackr {
1133
1193
  return returnBuffer
1134
1194
  }
1135
1195
  }
1196
+ if (encodeOptions & RESET_BUFFER_MODE)
1197
+ position$1 = start;
1136
1198
  }
1137
1199
  };
1138
1200
  const pack = (value) => {
@@ -1143,13 +1205,20 @@ class Packr extends Unpackr {
1143
1205
  var length;
1144
1206
  if (type === 'string') {
1145
1207
  let strLength = value.length;
1208
+ if (bundledStrings$1 && strLength >= 8 && strLength < 0x1000) {
1209
+ let twoByte = hasNonLatin.test(value);
1210
+ bundledStrings$1[twoByte ? 0 : 1] += value;
1211
+ target[position$1++] = 0xc1;
1212
+ pack(twoByte ? -strLength : strLength);
1213
+ return
1214
+ }
1146
1215
  let headerSize;
1147
1216
  // first we estimate the header size, so we can write to the correct location
1148
1217
  if (strLength < 0x20) {
1149
1218
  headerSize = 1;
1150
- } else if (strLength < 0xff) {
1219
+ } else if (strLength < 0x100) {
1151
1220
  headerSize = 2;
1152
- } else if (strLength < 0xff00) {
1221
+ } else if (strLength < 0x10000) {
1153
1222
  headerSize = 3;
1154
1223
  } else {
1155
1224
  headerSize = 5;
@@ -1562,7 +1631,7 @@ class Packr extends Unpackr {
1562
1631
  if ((end - start) > MAX_BUFFER_SIZE)
1563
1632
  throw new Error('Packed buffer would be larger than maximum buffer size')
1564
1633
  newSize = Math.min(MAX_BUFFER_SIZE,
1565
- Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x1000000) / 0x1000) * 0x1000);
1634
+ Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
1566
1635
  } else // faster handling for smaller buffers
1567
1636
  newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
1568
1637
  let newBuffer = new ByteArrayAllocate(newSize);
@@ -1587,7 +1656,7 @@ class Packr extends Unpackr {
1587
1656
 
1588
1657
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
1589
1658
  extensions = [{
1590
- pack(date, allocateForWrite) {
1659
+ pack(date, allocateForWrite, pack) {
1591
1660
  let seconds = date.getTime() / 1000;
1592
1661
  if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
1593
1662
  // Timestamp 32
@@ -1602,6 +1671,16 @@ extensions = [{
1602
1671
  target[position++] = 0xff;
1603
1672
  targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0));
1604
1673
  targetView.setUint32(position + 4, seconds);
1674
+ } else if (isNaN(seconds)) {
1675
+ if (this.onInvalidDate) {
1676
+ allocateForWrite(0);
1677
+ return pack(this.onInvalidDate())
1678
+ }
1679
+ // Intentionally invalid timestamp
1680
+ let { target, targetView, position} = allocateForWrite(3);
1681
+ target[position++] = 0xd4;
1682
+ target[position++] = 0xff;
1683
+ target[position++] = 0xff;
1605
1684
  } else {
1606
1685
  // Timestamp 96
1607
1686
  let { target, targetView, position} = allocateForWrite(15);
@@ -1787,7 +1866,8 @@ const pack = defaultPackr.pack;
1787
1866
  const encode = defaultPackr.pack;
1788
1867
  const Encoder = Packr;
1789
1868
  const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1790
- const REUSE_BUFFER_MODE = 1000;
1869
+ const REUSE_BUFFER_MODE = 512;
1870
+ const RESET_BUFFER_MODE = 1024;
1791
1871
 
1792
1872
  class PackrStream extends stream.Transform {
1793
1873
  constructor(options) {
@@ -1939,9 +2019,7 @@ function tryRequire(moduleId) {
1939
2019
  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)));
1940
2020
  return require$1(moduleId)
1941
2021
  } catch (error) {
1942
- if (typeof window == 'undefined')
1943
- console.warn('Native extraction module not loaded, msgpackr will still run, but with decreased performance. ' + error.message.split('\n')[0]);
1944
- else
2022
+ if (typeof window != 'undefined')
1945
2023
  console.warn('For browser usage, directly use msgpackr/unpack or msgpackr/pack modules. ' + error.message.split('\n')[0]);
1946
2024
  }
1947
2025
  }
package/dist/str.cjs ADDED
@@ -0,0 +1,100 @@
1
+ let utfz = require('../../msgpack-benchmark/node_modules/utfz-lib')
2
+
3
+ var safeEnd = 1000000;
4
+ var b = new Uint8Array(32768)
5
+ function writeString(value, target, position) {
6
+ var length, strLength = value.length;
7
+ let headerSize;
8
+ // first we estimate the header size, so we can write to the correct location
9
+ if (strLength < 0x20) {
10
+ headerSize = 1;
11
+ } else if (strLength < 0x100) {
12
+ headerSize = 2;
13
+ } else if (strLength < 0x10000) {
14
+ headerSize = 3;
15
+ } else {
16
+ headerSize = 5;
17
+ }
18
+ let maxBytes = strLength * 3;
19
+ //if (position + maxBytes > safeEnd)
20
+ // target = makeRoom(position + maxBytes);
21
+ for (let i = 0; i < 100; i++) {
22
+ length = pack(value, strLength, target, position + headerSize);
23
+ }
24
+ if (strLength < 0x40 || !encodeUtf8) {
25
+ var strPosition = position + headerSize;
26
+ var c2 = 0;
27
+ for (let i = 0; i < strLength; i++) {
28
+ const c1 = value.charCodeAt(i);
29
+ if (c1 < 0x80) {
30
+ target[strPosition++] = c1;
31
+ } else if (c1 < 0x800) {
32
+ target[strPosition++] = c1 >> 6 | 0xc0;
33
+ target[strPosition++] = c1 & 0x3f | 0x80;
34
+ } else if (
35
+ (c1 & 0xfc00) === 0xd800 &&
36
+ ((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
37
+ ) {
38
+ c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
39
+ i++;
40
+ target[strPosition++] = c1 >> 18 | 0xf0;
41
+ target[strPosition++] = c1 >> 12 & 0x3f | 0x80;
42
+ target[strPosition++] = c1 >> 6 & 0x3f | 0x80;
43
+ target[strPosition++] = c1 & 0x3f | 0x80;
44
+ } else {
45
+ target[strPosition++] = c1 >> 12 | 0xe0;
46
+ target[strPosition++] = c1 >> 6 & 0x3f | 0x80;
47
+ target[strPosition++] = c1 & 0x3f | 0x80;
48
+ }
49
+ }
50
+ length = strPosition - position - headerSize;
51
+ } else {
52
+ length = encodeUtf8(value, position + headerSize, maxBytes);
53
+ }
54
+
55
+
56
+ if (length < 0x20) {
57
+ target[position++] = 0xa0 | length;
58
+ } else if (length < 0x100) {
59
+ if (headerSize < 2) {
60
+ target.copyWithin(position + 2, position + 1, position + 1 + length);
61
+ }
62
+ target[position++] = 0xd9;
63
+ target[position++] = length;
64
+ } else if (length < 0x10000) {
65
+ if (headerSize < 3) {
66
+ target.copyWithin(position + 3, position + 2, position + 2 + length);
67
+ }
68
+ target[position++] = 0xda;
69
+ target[position++] = length >> 8;
70
+ target[position++] = length & 0xff;
71
+ } else {
72
+ if (headerSize < 5) {
73
+ target.copyWithin(position + 5, position + 3, position + 3 + length);
74
+ }
75
+ target[position++] = 0xdb;
76
+ targetView.setUint32(position, length);
77
+ position += 4;
78
+ }
79
+ return position + length
80
+ };
81
+ const pack = (str, length, buf, offset) => {
82
+ const start = offset;
83
+ let currHigh = 0;
84
+ for (let i = 0; i < length; i++) {
85
+ const code = str.charCodeAt(i);
86
+ const high = code >> 8;
87
+ if (high !== currHigh) {
88
+ buf[i + offset++] = 0;
89
+ buf[i + offset++] = high;
90
+ currHigh = high;
91
+ }
92
+ const low = code & 0xff;
93
+ buf[i + offset] = low;
94
+ if (!low) {
95
+ buf[i + ++offset] = currHigh;
96
+ }
97
+ }
98
+ return length + offset - start;
99
+ };
100
+ module.exports = writeString;
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);
@@ -677,6 +684,14 @@
677
684
  var deserialized = packr.unpack(serialized);
678
685
  assert.deepEqual(deserialized, data);
679
686
  });
687
+ test('pack/unpack sample data with bundled strings', function(){
688
+ var data = sampleData;
689
+ let structures = [];
690
+ let packr = new Packr({ structures, bundleStrings: true });
691
+ var serialized = packr.pack(data);
692
+ var deserialized = packr.unpack(serialized);
693
+ assert.deepEqual(deserialized, data);
694
+ });
680
695
  if (typeof Buffer != 'undefined')
681
696
  test('replace data', function(){
682
697
  var data1 = {
@@ -982,6 +997,7 @@
982
997
  date: new Date(1532219539733),
983
998
  farFutureDate: new Date(3532219539133),
984
999
  ancient: new Date(-3532219539133),
1000
+ invalidDate: new Date('invalid')
985
1001
  };
986
1002
  let packr = new Packr();
987
1003
  var serialized = packr.pack(data);
@@ -991,6 +1007,7 @@
991
1007
  assert.equal(deserialized.date.getTime(), 1532219539733);
992
1008
  assert.equal(deserialized.farFutureDate.getTime(), 3532219539133);
993
1009
  assert.equal(deserialized.ancient.getTime(), -3532219539133);
1010
+ assert.equal(deserialized.invalidDate.toString(), 'Invalid Date');
994
1011
  });
995
1012
  test('map/date with options', function(){
996
1013
  var map = new Map();
@@ -1001,16 +1018,19 @@
1001
1018
  var data = {
1002
1019
  map: map,
1003
1020
  date: new Date(1532219539011),
1021
+ invalidDate: new Date('invalid')
1004
1022
  };
1005
1023
  let packr = new Packr({
1006
1024
  mapsAsObjects: true,
1007
1025
  useTimestamp32: true,
1026
+ onInvalidDate: () => 'Custom invalid date'
1008
1027
  });
1009
1028
  var serialized = packr.pack(data);
1010
1029
  var deserialized = packr.unpack(serialized);
1011
1030
  assert.equal(deserialized.map[4], 'four');
1012
1031
  assert.equal(deserialized.map.three, 3);
1013
1032
  assert.equal(deserialized.date.getTime(), 1532219539000);
1033
+ assert.equal(deserialized.invalidDate, 'Custom invalid date');
1014
1034
  });
1015
1035
  test('key caching', function() {
1016
1036
  var data = {
@@ -1064,7 +1084,17 @@
1064
1084
  var deserialized = packr.unpack(serialized);
1065
1085
  assert.deepEqual(deserialized, data);
1066
1086
  });
1067
-
1087
+ test('bigint to float', function() {
1088
+ var data = {
1089
+ a: 325283295382932843n
1090
+ };
1091
+ let packr = new Packr({
1092
+ int64AsNumber: true
1093
+ });
1094
+ var serialized = packr.pack(data);
1095
+ var deserialized = packr.unpack(serialized);
1096
+ assert.deepEqual(deserialized.a, 325283295382932843);
1097
+ });
1068
1098
  test('numbers', function(){
1069
1099
  var data = {
1070
1100
  bigEncodable: 48978578104322,
@@ -1180,7 +1210,7 @@
1180
1210
  let structures = [];
1181
1211
  var serialized = pack(data);
1182
1212
  console.log('MessagePack size', serialized.length);
1183
- let packr = new Packr({ structures });
1213
+ let packr = new Packr({ structures, bundleStrings: false });
1184
1214
  var serialized = packr.pack(data);
1185
1215
  console.log('msgpackr w/ record ext size', serialized.length);
1186
1216
  for (var i = 0; i < ITERATIONS; i++) {
@@ -1191,7 +1221,7 @@
1191
1221
  var data = sampleData;
1192
1222
  this.timeout(10000);
1193
1223
  let structures = [];
1194
- let packr = new Packr({ structures });
1224
+ let packr = new Packr({ structures, bundleStrings: false });
1195
1225
  let buffer = typeof Buffer != 'undefined' ? Buffer.alloc(0x10000) : new Uint8Array(0x10000);
1196
1226
 
1197
1227
  for (var i = 0; i < ITERATIONS; i++) {
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Unpackr, Decoder, unpack, decode, addExtension, FLOAT32_OPTIONS, clearSource, roundFloat32 } 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
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'
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
@@ -13,6 +13,8 @@ let target
13
13
  let targetView
14
14
  let position = 0
15
15
  let safeEnd
16
+ let bundledStrings = null
17
+ const hasNonLatin = /[\u0080-\uFFFF]/
16
18
  const RECORD_SYMBOL = Symbol('record-id')
17
19
  export class Packr extends Unpackr {
18
20
  constructor(options) {
@@ -75,6 +77,14 @@ export class Packr extends Unpackr {
75
77
  position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster
76
78
  start = position
77
79
  referenceMap = packr.structuredClone ? new Map() : null
80
+ if (packr.bundleStrings) {
81
+ bundledStrings = ['', '']
82
+ target[position++] = 0xd6
83
+ target[position++] = 0x62 // 'b'
84
+ bundledStrings.position = position - start
85
+ position += 4
86
+ } else
87
+ bundledStrings = null
78
88
  sharedStructures = packr.structures
79
89
  if (sharedStructures) {
80
90
  if (sharedStructures.uninitialized)
@@ -113,6 +123,13 @@ export class Packr extends Unpackr {
113
123
  structures = sharedStructures || []
114
124
  try {
115
125
  pack(value)
126
+ if (bundledStrings) {
127
+ targetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start)
128
+ let writeStrings = bundledStrings
129
+ bundledStrings = null
130
+ pack(writeStrings[0])
131
+ pack(writeStrings[1])
132
+ }
116
133
  packr.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
117
134
  if (referenceMap && referenceMap.idsToInsert) {
118
135
  position += referenceMap.idsToInsert.length * 6
@@ -123,7 +140,7 @@ export class Packr extends Unpackr {
123
140
  referenceMap = null
124
141
  return serialized
125
142
  }
126
- if (encodeOptions === REUSE_BUFFER_MODE) {
143
+ if (encodeOptions & REUSE_BUFFER_MODE) {
127
144
  target.start = start
128
145
  target.end = position
129
146
  return target
@@ -162,6 +179,8 @@ export class Packr extends Unpackr {
162
179
  return returnBuffer
163
180
  }
164
181
  }
182
+ if (encodeOptions & RESET_BUFFER_MODE)
183
+ position = start
165
184
  }
166
185
  }
167
186
  const pack = (value) => {
@@ -172,13 +191,20 @@ export class Packr extends Unpackr {
172
191
  var length
173
192
  if (type === 'string') {
174
193
  let strLength = value.length
194
+ if (bundledStrings && strLength >= 8 && strLength < 0x1000) {
195
+ let twoByte = hasNonLatin.test(value)
196
+ bundledStrings[twoByte ? 0 : 1] += value
197
+ target[position++] = 0xc1
198
+ pack(twoByte ? -strLength : strLength);
199
+ return
200
+ }
175
201
  let headerSize
176
202
  // first we estimate the header size, so we can write to the correct location
177
203
  if (strLength < 0x20) {
178
204
  headerSize = 1
179
- } else if (strLength < 0xff) {
205
+ } else if (strLength < 0x100) {
180
206
  headerSize = 2
181
- } else if (strLength < 0xff00) {
207
+ } else if (strLength < 0x10000) {
182
208
  headerSize = 3
183
209
  } else {
184
210
  headerSize = 5
@@ -591,7 +617,7 @@ export class Packr extends Unpackr {
591
617
  if ((end - start) > MAX_BUFFER_SIZE)
592
618
  throw new Error('Packed buffer would be larger than maximum buffer size')
593
619
  newSize = Math.min(MAX_BUFFER_SIZE,
594
- Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x1000000) / 0x1000) * 0x1000)
620
+ Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000)
595
621
  } else // faster handling for smaller buffers
596
622
  newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12
597
623
  let newBuffer = new ByteArrayAllocate(newSize)
@@ -622,7 +648,7 @@ function copyBinary(source, target, targetOffset, offset, endOffset) {
622
648
 
623
649
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ]
624
650
  extensions = [{
625
- pack(date, allocateForWrite) {
651
+ pack(date, allocateForWrite, pack) {
626
652
  let seconds = date.getTime() / 1000
627
653
  if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
628
654
  // Timestamp 32
@@ -637,6 +663,16 @@ extensions = [{
637
663
  target[position++] = 0xff
638
664
  targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0))
639
665
  targetView.setUint32(position + 4, seconds)
666
+ } else if (isNaN(seconds)) {
667
+ if (this.onInvalidDate) {
668
+ allocateForWrite(0)
669
+ return pack(this.onInvalidDate())
670
+ }
671
+ // Intentionally invalid timestamp
672
+ let { target, targetView, position} = allocateForWrite(3)
673
+ target[position++] = 0xd4
674
+ target[position++] = 0xff
675
+ target[position++] = 0xff
640
676
  } else {
641
677
  // Timestamp 96
642
678
  let { target, targetView, position} = allocateForWrite(15)
@@ -824,4 +860,5 @@ export const Encoder = Packr
824
860
  export { FLOAT32_OPTIONS } from './unpack.js'
825
861
  import { FLOAT32_OPTIONS } from './unpack.js'
826
862
  export const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS
827
- export const REUSE_BUFFER_MODE = 1000
863
+ export const REUSE_BUFFER_MODE = 512
864
+ export const RESET_BUFFER_MODE = 1024
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "msgpackr",
3
3
  "author": "Kris Zyp",
4
- "version": "1.4.6",
4
+ "version": "1.5.2",
5
5
  "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
6
  "license": "MIT",
7
7
  "types": "./index.d.ts",
@@ -49,6 +49,12 @@
49
49
  "default": "./unpack.js"
50
50
  }
51
51
  },
52
+ "files": [
53
+ "/dist",
54
+ "*.md",
55
+ "/*.js",
56
+ "/*.ts"
57
+ ],
52
58
  "optionalDependencies": {
53
59
  "msgpackr-extract": "^1.0.14"
54
60
  },
package/unpack.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface Options {
13
13
  mapsAsObjects?: boolean
14
14
  variableMapSize?: boolean
15
15
  copyBuffers?: boolean
16
+ bundleStrings?: boolean
16
17
  useTimestamp32?: boolean
17
18
  largeBigIntToFloat?: boolean
18
19
  encodeUndefinedAsNil?: boolean
@@ -21,6 +22,7 @@ export interface Options {
21
22
  shouldShareStructure?: (keys: string[]) => boolean
22
23
  getStructures?(): {}[]
23
24
  saveStructures?(structures: {}[]): boolean | void
25
+ onInvalidDate?: () => any
24
26
  }
25
27
  interface Extension {
26
28
  Class: Function
@@ -44,3 +46,4 @@ export function addExtension(extension: Extension): void
44
46
  export function clearSource(): void
45
47
  export function roundFloat32(float32Number: number): number
46
48
  export const C1: {}
49
+ export let isNativeAccelerationEnabled: boolean