msgpackr 1.7.0-alpha5 → 1.7.0-beta1

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-alpha5",
4
+ "version": "1.7.0-beta1",
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);
@@ -446,9 +472,8 @@ function onLoadedStructures(sharedData) {
446
472
  this.lastTypedStructuresLength = typed.length;
447
473
  return named;
448
474
  }
449
- var sourceSymbol = Symbol('source')
475
+ var sourceSymbol = Symbol.for('source')
450
476
  function readStruct(src, position, srcEnd, unpackr) {
451
- // var stringLength = (src[position++] << 8) | src[position++];
452
477
  let recordId = src[position++] - 0x20;
453
478
  if (recordId >= 24) {
454
479
  switch(recordId) {
@@ -509,13 +534,13 @@ function readStruct(src, position, srcEnd, unpackr) {
509
534
  case 0: getRef = () => 0; break;
510
535
  case 1:
511
536
  getRef = (source, position) => {
512
- let ref = source.src[position + property.offset];
537
+ let ref = source.bytes[position + property.offset];
513
538
  return ref >= 0xf6 ? toConstant(ref) : ref;
514
539
  };
515
540
  break;
516
541
  case 2:
517
542
  getRef = (source, position) => {
518
- let src = source.src;
543
+ let src = source.bytes;
519
544
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
520
545
  let ref = dataView.getUint16(position + property.offset, true);
521
546
  return ref >= 0xff00 ? toConstant(ref & 0xff) : ref;
@@ -523,7 +548,7 @@ function readStruct(src, position, srcEnd, unpackr) {
523
548
  break;
524
549
  case 4:
525
550
  getRef = (source, position) => {
526
- let src = source.src;
551
+ let src = source.bytes;
527
552
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
528
553
  let ref = dataView.getUint32(position + property.offset, true);
529
554
  return ref >= 0xffffff00 ? toConstant(ref & 0xff) : ref;
@@ -541,7 +566,7 @@ function readStruct(src, position, srcEnd, unpackr) {
541
566
  property.multiGetCount = 0;
542
567
  get = function() {
543
568
  let source = this[sourceSymbol];
544
- let src = source.src;
569
+ let src = source.bytes;
545
570
  let position = source.position;
546
571
  let refStart = currentOffset + position;
547
572
  let ref = getRef(source, position);
@@ -557,7 +582,7 @@ function readStruct(src, position, srcEnd, unpackr) {
557
582
  next = next.next;
558
583
  }
559
584
  if (end == null)
560
- end = source.srcEnd - refStart;
585
+ end = source.bytesEnd - refStart;
561
586
  if (source.srcString) {
562
587
  return source.srcString.slice(ref, end);
563
588
  }
@@ -573,7 +598,7 @@ function readStruct(src, position, srcEnd, unpackr) {
573
598
  asciiEnd = null;
574
599
  } while((next = next.next));
575
600
  if (asciiEnd == null)
576
- asciiEnd = source.srcEnd - refStart
601
+ asciiEnd = source.bytesEnd - refStart
577
602
  source.srcString = src.toString('latin1', refStart, refStart + asciiEnd);
578
603
  return source.srcString.slice(ref, end);
579
604
  }
@@ -597,7 +622,7 @@ function readStruct(src, position, srcEnd, unpackr) {
597
622
  let refStart = currentOffset + position;
598
623
  let ref = getRef(source, position);
599
624
  if (typeof ref !== 'number') return ref;
600
- let src = source.src;
625
+ let src = source.bytes;
601
626
  let end, next = property.next;
602
627
  while(next) {
603
628
  end = next.getRef(source, position);
@@ -608,11 +633,16 @@ function readStruct(src, position, srcEnd, unpackr) {
608
633
  next = next.next;
609
634
  }
610
635
  if (end == null)
611
- end = source.srcEnd - refStart;
636
+ end = source.bytesEnd - refStart;
612
637
  if (type === UTF8) {
613
638
  return src.toString('utf8', ref + refStart, end + refStart);
614
639
  } else {
615
- return unpackr.unpack(src, { start: ref + refStart, end: end + refStart }); // could reuse this object
640
+ currentSource = source;
641
+ try {
642
+ return unpackr.unpack(src, { start: ref + refStart, end: end + refStart });
643
+ } finally {
644
+ currentSource = null;
645
+ }
616
646
  }
617
647
  };
618
648
  break;
@@ -621,7 +651,7 @@ function readStruct(src, position, srcEnd, unpackr) {
621
651
  case 4:
622
652
  get = function () {
623
653
  let source = this[sourceSymbol];
624
- let src = source.src;
654
+ let src = source.bytes;
625
655
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
626
656
  let position = source.position + property.offset;
627
657
  let value = dataView.getInt32(position, true)
@@ -640,7 +670,7 @@ function readStruct(src, position, srcEnd, unpackr) {
640
670
  case 8:
641
671
  get = function () {
642
672
  let source = this[sourceSymbol];
643
- let src = source.src;
673
+ let src = source.bytes;
644
674
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
645
675
  let value = dataView.getFloat64(source.position + property.offset, true);
646
676
  if (isNaN(value)) {
@@ -654,12 +684,22 @@ function readStruct(src, position, srcEnd, unpackr) {
654
684
  case 1:
655
685
  get = function () {
656
686
  let source = this[sourceSymbol];
657
- let src = source.src;
687
+ let src = source.bytes;
658
688
  let value = src[source.position + property.offset];
659
689
  return value < 0xf6 ? value : toConstant(value);
660
690
  };
661
691
  break;
662
692
  }
693
+ break;
694
+ case DATE:
695
+ get = function () {
696
+ let source = this[sourceSymbol];
697
+ let src = source.bytes;
698
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
699
+ return new Date(dataView.getFloat64(source.position + property.offset, true));
700
+ };
701
+ break;
702
+
663
703
  }
664
704
  property.get = get;
665
705
  }
@@ -668,10 +708,10 @@ function readStruct(src, position, srcEnd, unpackr) {
668
708
  }
669
709
  var instance = new construct();
670
710
  instance[sourceSymbol] = {
671
- src,
711
+ bytes: src,
672
712
  position,
673
713
  srcString: '',
674
- srcEnd
714
+ bytesEnd: srcEnd
675
715
  }
676
716
  return instance;
677
717
  }
@@ -684,6 +724,14 @@ function toConstant(code) {
684
724
  }
685
725
  throw new Error('Unknown constant');
686
726
  }
727
+
728
+ function saveState() {
729
+ if (currentSource) {
730
+ currentSource.bytes = Uint8Array.prototype.slice.call(currentSource.bytes, currentSource.position, currentSource.bytesEnd);
731
+ currentSource.position = 0;
732
+ currentSource.bytesEnd = currentSource.bytes.length;
733
+ }
734
+ }
687
735
  function prepareStructures(structures, packr) {
688
736
  if (packr.typedStructs) {
689
737
  let structMap = new Map();
@@ -713,5 +761,5 @@ function prepareStructures(structures, packr) {
713
761
  return structures;
714
762
  }
715
763
 
716
- setReadStruct(readStruct, onLoadedStructures);
764
+ setReadStruct(readStruct, onLoadedStructures, saveState);
717
765
 
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) {
@@ -208,7 +208,7 @@ export function checkedRead(options) {
208
208
  // else more to read, but we are reading sequentially, so don't clear source yet
209
209
  return result
210
210
  } catch(error) {
211
- if (currentStructures.restoreStructures)
211
+ if (currentStructures?.restoreStructures)
212
212
  restoreStructures()
213
213
  clearSource()
214
214
  if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer') || position > srcEnd) {
@@ -930,7 +930,16 @@ function readKey() {
930
930
 
931
931
  // the registration of the record definition extension (as "r")
932
932
  const recordDefinition = (id, highByte) => {
933
- var structure = read()
933
+ let structure
934
+ if (currentUnpackr.freezeData) {
935
+ currentUnpackr.freezeData = false;
936
+ try {
937
+ structure = read()
938
+ } finally {
939
+ currentUnpackr.freezeData = true;
940
+ }
941
+ } else
942
+ structure = read()
934
943
  let firstByte = id
935
944
  if (highByte !== undefined) {
936
945
  id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id)
@@ -1032,6 +1041,8 @@ currentExtensions[0xff] = (data) => {
1032
1041
  // currentExtensions[0x52] = () =>
1033
1042
 
1034
1043
  function saveState(callback) {
1044
+ if (onSaveState)
1045
+ onSaveState();
1035
1046
  let savedSrcEnd = srcEnd
1036
1047
  let savedPosition = position
1037
1048
  let savedStringPosition = stringPosition
@@ -1101,7 +1112,8 @@ export function roundFloat32(float32Number) {
1101
1112
  let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
1102
1113
  return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
1103
1114
  }
1104
- export function setReadStruct(updatedReadStruct, loadedStructs) {
1115
+ export function setReadStruct(updatedReadStruct, loadedStructs, saveState) {
1105
1116
  readStruct = updatedReadStruct;
1106
1117
  onLoadedStructures = loadedStructs;
1118
+ onSaveState = saveState;
1107
1119
  }