msgpackr 1.7.0-alpha4 → 1.7.0-alpha7

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "msgpackr",
3
3
  "author": "Kris Zyp",
4
- "version": "1.7.0-alpha4",
4
+ "version": "1.7.0-alpha7",
5
5
  "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
6
  "license": "MIT",
7
7
  "types": "./index.d.ts",
package/struct.js CHANGED
@@ -41,11 +41,13 @@ const ASCII = 3; // the MIBenum from https://www.iana.org/assignments/character-
41
41
  const NUMBER = 0;
42
42
  const UTF8 = 2;
43
43
  const OBJECT_DATA = 1;
44
+ const DATE = 16;
44
45
  const TYPE_NAMES = ['num', 'object', 'string', 'ascii'];
46
+ TYPE_NAMES[DATE] = 'date';
45
47
  const float32Headers = [false, true, true, false, false, true, true, false];
46
48
  let updatedPosition;
47
49
  const hasNodeBuffer = typeof Buffer !== 'undefined'
48
- let textEncoder
50
+ let textEncoder, currentSource;
49
51
  try {
50
52
  textEncoder = new TextEncoder()
51
53
  } catch (error) {}
@@ -89,7 +91,7 @@ function writeStruct(object, target, position, structures, makeRoom, pack, packr
89
91
  return 0;
90
92
  position += headerSize;
91
93
  let queuedReferences = [];
92
- let usedLatin0;
94
+ let usedAscii0;
93
95
  let keyIndex = 0;
94
96
  for (let key in object) {
95
97
  let value = object[key];
@@ -105,7 +107,8 @@ function writeStruct(object, target, position, structures, makeRoom, pack, packr
105
107
  string16: null,
106
108
  object16: null,
107
109
  num32: null,
108
- float64: null
110
+ float64: null,
111
+ date64: null
109
112
  };
110
113
  }
111
114
  if (position > safeEnd) {
@@ -198,25 +201,47 @@ function writeStruct(object, target, position, structures, makeRoom, pack, packr
198
201
  refPosition += encodeUtf8(target, value, refPosition);
199
202
  isNotAscii = refPosition - strStart > strLength;
200
203
  }
201
- if (refOffset < 0x100) {
202
- if (isNotAscii)
203
- transition = nextTransition.string8 || createTypeTransition(nextTransition, UTF8, 1);
204
- else
205
- transition = nextTransition.ascii8 || createTypeTransition(nextTransition, ASCII, 1);
204
+ if (refOffset < 0xa0 || (refOffset < 0xf6 && (nextTransition.ascii8 || nextTransition.string8))) {
205
+ // short strings
206
+ if (isNotAscii) {
207
+ if (!(transition = nextTransition.string8)) {
208
+ if (typedStructs.length > 10 && (transition = nextTransition.ascii8)) {
209
+ // we can safely change ascii to utf8 in place since they are compatible
210
+ transition.__type = UTF8;
211
+ nextTransition.ascii8 = null;
212
+ nextTransition.string8 = transition;
213
+ pack(null, 0, true); // special call to notify that structures have been updated
214
+ } else {
215
+ transition = createTypeTransition(nextTransition, UTF8, 1);
216
+ }
217
+ }
218
+ } else if (refOffset === 0 && !usedAscii0) {
219
+ usedAscii0 = true;
220
+ transition = nextTransition.ascii0 || createTypeTransition(nextTransition, ASCII, 0);
221
+ break; // don't increment position
222
+ }// else ascii:
223
+ else if (!(transition = nextTransition.ascii8) && !(typedStructs.length > 10 && (transition = nextTransition.string8)))
224
+ transition = createTypeTransition(nextTransition, ASCII, 1);
206
225
  target[position++] = refOffset;
207
226
  } else {
208
- if (isNotAscii)
227
+ // TODO: Enable ascii16 at some point, but get the logic right
228
+ //if (isNotAscii)
209
229
  transition = nextTransition.string16 || createTypeTransition(nextTransition, UTF8, 2);
210
- else
211
- transition = nextTransition.ascii16 || createTypeTransition(nextTransition, ASCII, 2);
230
+ //else
231
+ //transition = nextTransition.ascii16 || createTypeTransition(nextTransition, ASCII, 2);
212
232
  targetView.setUint16(position, refOffset, true);
213
233
  position += 2;
214
234
  }
215
235
  break;
216
236
  case 'object':
217
237
  if (value) {
218
- //transition = nextTransition.object16 || createTypeTransition(nextTransition, OBJECT_DATA, 2);
219
- queuedReferences.push(key, value, keyIndex);
238
+ if (value.constructor === Date) {
239
+ transition = nextTransition.date64 || createTypeTransition(nextTransition, DATE, 8);
240
+ targetView.setFloat64(position, value.getTime(), true);
241
+ position += 8;
242
+ } else {
243
+ queuedReferences.push(key, value, keyIndex);
244
+ }
220
245
  break;
221
246
  } else { // null
222
247
  nextTransition = anyType(nextTransition, position, targetView, -10); // match CBOR with this
@@ -306,7 +331,7 @@ function writeStruct(object, target, position, structures, makeRoom, pack, packr
306
331
  targetView.setUint32(position, refOffset, true);
307
332
  position += 4;
308
333
  }
309
- } else {
334
+ } else { // null or undefined
310
335
  transition = nextTransition.object16 || createTypeTransition(nextTransition, OBJECT_DATA, 2);
311
336
  targetView.setInt16(position, value === null ? -10 : -9, true);
312
337
  position += 2;
@@ -434,7 +459,8 @@ function onLoadedStructures(sharedData) {
434
459
  string16: null,
435
460
  object16: null,
436
461
  num32: null,
437
- float64: null
462
+ float64: null,
463
+ date64: null,
438
464
  };
439
465
  }
440
466
  transition = createTypeTransition(nextTransition, type, size);
@@ -478,12 +504,13 @@ function readStruct(src, position, srcEnd, unpackr) {
478
504
  construct = structure.construct = function LazyObject() {
479
505
  }
480
506
  var prototype = construct.prototype;
507
+ let properties = [];
481
508
  Object.defineProperty(prototype, 'toJSON', {
482
- get() {
509
+ value() {
483
510
  // return an enumerable object with own properties to JSON stringify
484
511
  let resolved = {};
485
- for (let i = 0, l = structure.length; i < l; i++) {
486
- let key = structure[i];
512
+ for (let i = 0, l = properties.length; i < l; i++) {
513
+ let key = properties[i].key;
487
514
  resolved[key] = this[key];
488
515
  }
489
516
  return resolved;
@@ -492,7 +519,6 @@ function readStruct(src, position, srcEnd, unpackr) {
492
519
  });
493
520
  let currentOffset = 0;
494
521
  let lastRefProperty;
495
- let properties = [];
496
522
  for (let i = 0, l = structure.length; i < l; i++) {
497
523
  let definition = structure[i];
498
524
  let [ type, size, key, enumerationOffset ] = definition;
@@ -612,7 +638,12 @@ function readStruct(src, position, srcEnd, unpackr) {
612
638
  if (type === UTF8) {
613
639
  return src.toString('utf8', ref + refStart, end + refStart);
614
640
  } else {
615
- return unpackr.unpack(src, { start: ref + refStart, end: end + refStart }); // could reuse this object
641
+ currentSource = source;
642
+ try {
643
+ return unpackr.unpack(src, { start: ref + refStart, end: end + refStart });
644
+ } finally {
645
+ currentSource = null;
646
+ }
616
647
  }
617
648
  };
618
649
  break;
@@ -660,6 +691,16 @@ function readStruct(src, position, srcEnd, unpackr) {
660
691
  };
661
692
  break;
662
693
  }
694
+ break;
695
+ case DATE:
696
+ get = function () {
697
+ let source = this[sourceSymbol];
698
+ let src = source.src;
699
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
700
+ return new Date(dataView.getFloat64(source.position + property.offset, true));
701
+ };
702
+ break;
703
+
663
704
  }
664
705
  property.get = get;
665
706
  }
@@ -684,14 +725,23 @@ function toConstant(code) {
684
725
  }
685
726
  throw new Error('Unknown constant');
686
727
  }
728
+
729
+ function saveState() {
730
+ if (currentSource) {
731
+ currentSource.src = Uint8Array.prototype.slice.call(currentSource.src, currentSource.position, currentSource.srcEnd);
732
+ currentSource.position = 0;
733
+ currentSource.srcEnd = currentSource.src.length;
734
+ }
735
+ }
687
736
  function prepareStructures(structures, packr) {
688
- if (!packr.typedStructs)
689
- return structures;
690
- let structMap = new Map();
691
- structMap.set('named', structures);
692
- structMap.set('typed', packr.typedStructs);
737
+ if (packr.typedStructs) {
738
+ let structMap = new Map();
739
+ structMap.set('named', structures);
740
+ structMap.set('typed', packr.typedStructs);
741
+ structures = structMap;
742
+ }
693
743
  let lastTypedStructuresLength = packr.lastTypedStructuresLength || 0;
694
- structMap.isCompatible = existing => {
744
+ structures.isCompatible = existing => {
695
745
  let compatible = true;
696
746
  if (existing instanceof Map) {
697
747
  let named = existing.get('named') || [];
@@ -709,8 +759,8 @@ function prepareStructures(structures, packr) {
709
759
  return compatible;
710
760
  };
711
761
  packr.lastTypedStructuresLength = packr.typedStructs?.length;
712
- return structMap;
762
+ return structures;
713
763
  }
714
764
 
715
- setReadStruct(readStruct, onLoadedStructures);
765
+ setReadStruct(readStruct, onLoadedStructures, saveState);
716
766
 
package/unpack.js CHANGED
@@ -28,7 +28,7 @@ export const C1 = new C1Type()
28
28
  C1.name = 'MessagePack 0xC1'
29
29
  var sequentialMode = false
30
30
  var inlineObjectReadThreshold = 2
31
- var readStruct, onLoadedStructures
31
+ var readStruct, onLoadedStructures, onSaveState
32
32
  try {
33
33
  new Function('')
34
34
  } catch(error) {
@@ -95,7 +95,7 @@ export class Unpackr {
95
95
  currentUnpackr = this
96
96
  if (this.structures) {
97
97
  currentStructures = this.structures
98
- return checkedRead()
98
+ return checkedRead(options)
99
99
  } else if (!currentStructures || currentStructures.length > 0) {
100
100
  currentStructures = []
101
101
  }
@@ -104,7 +104,7 @@ export class Unpackr {
104
104
  if (!currentStructures || currentStructures.length > 0)
105
105
  currentStructures = []
106
106
  }
107
- return checkedRead()
107
+ return checkedRead(options)
108
108
  }
109
109
  unpackMultiple(source, forEach) {
110
110
  let values, lastPosition = 0
@@ -173,7 +173,7 @@ export class Unpackr {
173
173
  export function getPosition() {
174
174
  return position
175
175
  }
176
- export function checkedRead() {
176
+ export function checkedRead(options) {
177
177
  try {
178
178
  if (!currentUnpackr.trusted && !sequentialMode) {
179
179
  let sharedLength = currentStructures.sharedLength || 0
@@ -183,6 +183,8 @@ export function checkedRead() {
183
183
  let result
184
184
  if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && src[position] >= 0x20 && readStruct) {
185
185
  result = readStruct(src, position, srcEnd, currentUnpackr)
186
+ if (!(options && options.lazy) && result)
187
+ result = result.toJSON()
186
188
  position = srcEnd
187
189
  } else
188
190
  result = read()
@@ -206,7 +208,7 @@ export function checkedRead() {
206
208
  // else more to read, but we are reading sequentially, so don't clear source yet
207
209
  return result
208
210
  } catch(error) {
209
- if (currentStructures.restoreStructures)
211
+ if (currentStructures?.restoreStructures)
210
212
  restoreStructures()
211
213
  clearSource()
212
214
  if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer') || position > srcEnd) {
@@ -1030,6 +1032,8 @@ currentExtensions[0xff] = (data) => {
1030
1032
  // currentExtensions[0x52] = () =>
1031
1033
 
1032
1034
  function saveState(callback) {
1035
+ if (onSaveState)
1036
+ onSaveState();
1033
1037
  let savedSrcEnd = srcEnd
1034
1038
  let savedPosition = position
1035
1039
  let savedStringPosition = stringPosition
@@ -1099,7 +1103,8 @@ export function roundFloat32(float32Number) {
1099
1103
  let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
1100
1104
  return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
1101
1105
  }
1102
- export function setReadStruct(updatedReadStruct, loadedStructs) {
1106
+ export function setReadStruct(updatedReadStruct, loadedStructs, saveState) {
1103
1107
  readStruct = updatedReadStruct;
1104
1108
  onLoadedStructures = loadedStructs;
1109
+ onSaveState = saveState;
1105
1110
  }