msgpackr 1.7.0-alpha2 → 1.7.0-alpha5

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/test.js CHANGED
@@ -1,7 +1,8 @@
1
- (function (msgpackr, chai, fs) {
1
+ (function (msgpackr, chai, inspector, fs) {
2
2
  'use strict';
3
3
 
4
4
  chai = chai && Object.prototype.hasOwnProperty.call(chai, 'default') ? chai['default'] : chai;
5
+ inspector = inspector && Object.prototype.hasOwnProperty.call(inspector, 'default') ? inspector['default'] : inspector;
5
6
 
6
7
  var decoder;
7
8
  try {
@@ -28,7 +29,7 @@
28
29
  C1.name = 'MessagePack 0xC1';
29
30
  var sequentialMode = false;
30
31
  var inlineObjectReadThreshold = 2;
31
- var readStruct;
32
+ var readStruct, onLoadedStructures;
32
33
  try {
33
34
  new Function('');
34
35
  } catch(error) {
@@ -58,16 +59,21 @@
58
59
  }
59
60
  Object.assign(this, options);
60
61
  }
61
- unpack(source, end) {
62
+ unpack(source, options) {
62
63
  if (src) {
63
64
  // re-entrant execution, save the state and restore it after we do this unpack
64
65
  return saveState(() => {
65
66
  clearSource();
66
- return this ? this.unpack(source, end) : Unpackr.prototype.unpack.call(defaultOptions, source, end)
67
+ return this ? this.unpack(source, options) : Unpackr.prototype.unpack.call(defaultOptions, source, options)
67
68
  })
68
69
  }
69
- srcEnd = end > -1 ? end : source.length;
70
- position = 0;
70
+ if (typeof options === 'object') {
71
+ srcEnd = options.end || source.length;
72
+ position = options.start || 0;
73
+ } else {
74
+ position = 0;
75
+ srcEnd = options > -1 ? options : source.length;
76
+ }
71
77
  srcStringEnd = 0;
72
78
  srcString = null;
73
79
  bundledStrings = null;
@@ -88,7 +94,7 @@
88
94
  currentUnpackr = this;
89
95
  if (this.structures) {
90
96
  currentStructures = this.structures;
91
- return checkedRead()
97
+ return checkedRead(options)
92
98
  } else if (!currentStructures || currentStructures.length > 0) {
93
99
  currentStructures = [];
94
100
  }
@@ -97,7 +103,7 @@
97
103
  if (!currentStructures || currentStructures.length > 0)
98
104
  currentStructures = [];
99
105
  }
100
- return checkedRead()
106
+ return checkedRead(options)
101
107
  }
102
108
  unpackMultiple(source, forEach) {
103
109
  let values, lastPosition = 0;
@@ -132,7 +138,11 @@
132
138
  }
133
139
  }
134
140
  _mergeStructures(loadedStructures, existingStructures) {
141
+ if (onLoadedStructures)
142
+ loadedStructures = onLoadedStructures.call(this, loadedStructures);
135
143
  loadedStructures = loadedStructures || [];
144
+ if (Object.isFrozen(loadedStructures))
145
+ loadedStructures = loadedStructures.map(structure => structure.slice(0));
136
146
  for (let i = 0, l = loadedStructures.length; i < l; i++) {
137
147
  let structure = loadedStructures[i];
138
148
  if (structure) {
@@ -159,7 +169,7 @@
159
169
  return this.unpack(source, end)
160
170
  }
161
171
  }
162
- function checkedRead() {
172
+ function checkedRead(options) {
163
173
  try {
164
174
  if (!currentUnpackr.trusted && !sequentialMode) {
165
175
  let sharedLength = currentStructures.sharedLength || 0;
@@ -167,9 +177,10 @@
167
177
  currentStructures.length = sharedLength;
168
178
  }
169
179
  let result;
170
- if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && readStruct) {
171
- let id = (src[position++] << 8) + src[position++];
172
- result = readStruct(src, position, srcEnd, currentStructures[id - 0x40] || loadStructures()[id - 0x40], currentUnpackr);
180
+ if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && src[position] >= 0x20 && readStruct) {
181
+ result = readStruct(src, position, srcEnd, currentUnpackr);
182
+ if (!(options && options.lazy) && result)
183
+ result = result.toJSON();
173
184
  position = srcEnd;
174
185
  } else
175
186
  result = read();
@@ -565,6 +576,16 @@
565
576
 
566
577
  return result
567
578
  }
579
+ function readString(source, start, length) {
580
+ let existingSrc = src;
581
+ src = source;
582
+ position = start;
583
+ try {
584
+ return readStringJS(length);
585
+ } finally {
586
+ src = existingSrc;
587
+ }
588
+ }
568
589
 
569
590
  function readArray(length) {
570
591
  let array = new Array(length);
@@ -785,7 +806,15 @@
785
806
  function readExt(length) {
786
807
  let type = src[position++];
787
808
  if (currentExtensions[type]) {
788
- return currentExtensions[type](src.subarray(position, position += length))
809
+ let end;
810
+ return currentExtensions[type](src.subarray(position, end = (position += length)), (readPosition) => {
811
+ position = readPosition;
812
+ try {
813
+ return read();
814
+ } finally {
815
+ position = end;
816
+ }
817
+ })
789
818
  }
790
819
  else
791
820
  throw new Error('Unknown extension type ' + type)
@@ -1000,8 +1029,9 @@
1000
1029
  mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
1001
1030
  }
1002
1031
  var defaultUnpackr = new Unpackr({ useRecords: false });
1003
- function setReadStruct(func) {
1004
- readStruct = func;
1032
+ function setReadStruct(updatedReadStruct, loadedStructs) {
1033
+ readStruct = updatedReadStruct;
1034
+ onLoadedStructures = loadedStructs;
1005
1035
  }
1006
1036
 
1007
1037
  let textEncoder;
@@ -1031,7 +1061,6 @@
1031
1061
  let hasSharedUpdate;
1032
1062
  let structures;
1033
1063
  let referenceMap;
1034
- let lastSharedStructuresLength = 0;
1035
1064
  let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position) {
1036
1065
  return target.utf8Write(string, position, 0xffffffff)
1037
1066
  } : (textEncoder && textEncoder.encodeInto) ?
@@ -1117,7 +1146,7 @@
1117
1146
  }
1118
1147
  transition[RECORD_SYMBOL] = i + 0x40;
1119
1148
  }
1120
- lastSharedStructuresLength = sharedLength;
1149
+ this.lastNamedStructuresLength = sharedLength;
1121
1150
  }
1122
1151
  if (!isSequential) {
1123
1152
  structures.nextId = sharedLength + 0x40;
@@ -1153,7 +1182,7 @@
1153
1182
  if (structures) {
1154
1183
  if (serializationsSinceTransitionRebuild < 10)
1155
1184
  serializationsSinceTransitionRebuild++;
1156
- let sharedLength = structures.sharedLength || maxSharedStructures;
1185
+ let sharedLength = structures.sharedLength || 0;
1157
1186
  if (structures.length > sharedLength)
1158
1187
  structures.length = sharedLength;
1159
1188
  if (transitionsCount > 10000) {
@@ -1172,12 +1201,12 @@
1172
1201
  if (hasSharedUpdate && packr.saveStructures) {
1173
1202
  // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1174
1203
  let returnBuffer = target.subarray(start, position$1);
1175
- if (packr.saveStructures(structures, lastSharedStructuresLength) === false) {
1204
+ let newSharedData = prepareStructures(structures, packr);
1205
+ if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
1176
1206
  // get updated structures and try again if the update failed
1177
- packr._mergeStructures(packr.getStructures());
1178
1207
  return packr.pack(value)
1179
1208
  }
1180
- lastSharedStructuresLength = sharedLength;
1209
+ packr.lastNamedStructuresLength = sharedLength;
1181
1210
  return returnBuffer
1182
1211
  }
1183
1212
  }
@@ -1295,7 +1324,7 @@
1295
1324
  } else if (type === 'number') {
1296
1325
  if (value >>> 0 === value) {// positive integer, 32-bit or less
1297
1326
  // positive uint
1298
- if (value < 0x40 || (value < 0x80 && this.useRecords === false)) {
1327
+ if (value < 0x20 || (value < 0x80 && this.useRecords === false) || (value < 0x40 && !this.randomAccessStructure)) {
1299
1328
  target[position$1++] = value;
1300
1329
  } else if (value < 0x100) {
1301
1330
  target[position$1++] = 0xcc;
@@ -1695,16 +1724,18 @@
1695
1724
  }
1696
1725
  };
1697
1726
  const writeStruct = (object, safePrototype) => {
1698
- let newPosition = writeStructSlots(object, target, position$1, structures, makeRoom, (value, newPosition) => {
1727
+ let newPosition = writeStructSlots(object, target, position$1, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
1728
+ if (notifySharedUpdate)
1729
+ return hasSharedUpdate = true;
1699
1730
  position$1 = newPosition;
1700
1731
  if (start > 0) {
1701
1732
  pack(value);
1702
1733
  if (start == 0)
1703
- return { position: position$1, targetView }; // indicate the buffer was re-allocated
1734
+ return { position: position$1, targetView, target }; // indicate the buffer was re-allocated
1704
1735
  } else
1705
1736
  pack(value);
1706
1737
  return position$1;
1707
- });
1738
+ }, this);
1708
1739
  if (newPosition === 0) // bail and go to a msgpack object
1709
1740
  return writeObject(object, true);
1710
1741
  position$1 = newPosition;
@@ -1719,6 +1750,8 @@
1719
1750
  clearSharedData() {
1720
1751
  if (this.structures)
1721
1752
  this.structures = [];
1753
+ if (this.typedStructs)
1754
+ this.typedStructs = [];
1722
1755
  }
1723
1756
  }
1724
1757
 
@@ -1926,247 +1959,699 @@
1926
1959
  pack(writeStrings[1]);
1927
1960
  }
1928
1961
  }
1929
- function setWriteStructSlots(func) {
1930
- writeStructSlots = func;
1962
+ function prepareStructures(structures, packr) {
1963
+ structures.isCompatible = (existingStructures) => {
1964
+ let compatible = !existingStructures || ((packr.lastNamedStructuresLength || 0) === existingStructures.length);
1965
+ if (!compatible) // we want to merge these existing structures immediately since we already have it and we are in the right transaction
1966
+ packr._mergeStructures(existingStructures);
1967
+ return compatible;
1968
+ };
1969
+ return structures
1970
+ }
1971
+ function setWriteStructSlots(writeSlots, makeStructures) {
1972
+ writeStructSlots = writeSlots;
1973
+ prepareStructures = makeStructures;
1931
1974
  }
1932
1975
 
1933
1976
  let defaultPackr = new Packr({ useRecords: false });
1934
1977
  const REUSE_BUFFER_MODE = 512;
1935
1978
  const RESET_BUFFER_MODE = 1024;
1936
1979
 
1937
- // first four bits
1938
- const hasNonLatin$1 = /[\u0080-\uFFFF]/;
1980
+ const ASCII = 3; // the MIBenum from https://www.iana.org/assignments/character-sets/character-sets.xhtml (and other character encodings could be referenced by MIBenum)
1981
+ const NUMBER = 0;
1982
+ const UTF8 = 2;
1983
+ const OBJECT_DATA = 1;
1984
+ const TYPE_NAMES = ['num', 'object', 'string', 'ascii'];
1939
1985
  const float32Headers = [false, true, true, false, false, true, true, false];
1940
- setWriteStructSlots(writeStruct);
1941
- function writeStruct(object, target, position, structures, makeRoom, pack) {
1942
- let transition = structures.transitions || false;
1943
- let start = position;
1944
- position += 4;
1945
- let queuedReferences = [];
1946
- let uint32 = target.uint32 || (target.uint32 = new Uint32Array(target.buffer));
1986
+ let updatedPosition;
1987
+ const hasNodeBuffer$1 = typeof Buffer !== 'undefined';
1988
+ let textEncoder$1;
1989
+ try {
1990
+ textEncoder$1 = new TextEncoder();
1991
+ } catch (error) {}
1992
+ const encodeUtf8 = hasNodeBuffer$1 ? function(target, string, position) {
1993
+ return target.utf8Write(string, position, 0xffffffff)
1994
+ } : (textEncoder$1 && textEncoder$1.encodeInto) ?
1995
+ function(target, string, position) {
1996
+ return textEncoder$1.encodeInto(string, target.subarray(position)).written
1997
+ } : false;
1998
+ setWriteStructSlots(writeStruct, prepareStructures$1);
1999
+ function writeStruct(object, target, position, structures, makeRoom, pack, packr) {
2000
+ let typedStructs = packr.typedStructs || (packr.typedStructs = []);
2001
+ // note that we rely on pack.js to load stored structures before we get to this point
1947
2002
  let targetView = target.dataView;
1948
- let encoded;
1949
- let stringData = '';
2003
+ let refsStartPosition = (typedStructs.lastStringStart || 100) + position;
1950
2004
  let safeEnd = target.length - 10;
2005
+ let start = position;
2006
+ if (position > safeEnd) {
2007
+ let lastStart = start;
2008
+ target = makeRoom(position);
2009
+ targetView = target.dataView;
2010
+ position -= lastStart;
2011
+ refsStartPosition -= lastStart;
2012
+ start = 0;
2013
+ safeEnd = target.length - 10;
2014
+ }
2015
+
2016
+ let refOffset, refPosition = refsStartPosition;
2017
+
2018
+ let transition = typedStructs.transitions || (typedStructs.transitions = Object.create(null));
2019
+ let nextId = typedStructs.nextId || typedStructs.length;
2020
+ let headerSize =
2021
+ nextId < 0xf ? 1 :
2022
+ nextId < 0xf0 ? 2 :
2023
+ nextId < 0xf000 ? 3 :
2024
+ nextId < 0xf00000 ? 4 : 0;
2025
+ if (headerSize === 0)
2026
+ return 0;
2027
+ position += headerSize;
2028
+ let queuedReferences = [];
2029
+ let keyIndex = 0;
1951
2030
  for (let key in object) {
2031
+ let value = object[key];
1952
2032
  let nextTransition = transition[key];
1953
2033
  if (!nextTransition) {
1954
- return 0; // bail
1955
- //nextTransition = transition[key] = Object.create(null)
1956
- //newTransitions++
2034
+ transition[key] = nextTransition = {
2035
+ key,
2036
+ parent: transition,
2037
+ enumerationOffset: 0,
2038
+ ascii0: null,
2039
+ ascii8: null,
2040
+ num8: null,
2041
+ string16: null,
2042
+ object16: null,
2043
+ num32: null,
2044
+ float64: null
2045
+ };
1957
2046
  }
1958
2047
  if (position > safeEnd) {
1959
- let newPosition = position - start;
2048
+ let lastStart = start;
1960
2049
  target = makeRoom(position);
1961
- position = newPosition;
2050
+ targetView = target.dataView;
2051
+ position -= lastStart;
2052
+ refsStartPosition -= lastStart;
2053
+ refPosition -= lastStart;
1962
2054
  start = 0;
1963
2055
  safeEnd = target.length - 10;
1964
2056
  }
1965
- transition = nextTransition;
1966
- let value = object[key];
1967
2057
  switch (typeof value) {
1968
2058
  case 'number':
1969
- if (value >>> 0 === value && value < 0x20000000) {
1970
- encoded = value;
2059
+ let number = value;
2060
+ if (number >> 0 === number && number < 0x20000000 && number > -0x1f000000) {
2061
+ if (number < 0xf6 && number >= 0 && (nextTransition.num8 || number < 0x20 && !nextTransition.num32)) {
2062
+ transition = nextTransition.num8 || createTypeTransition(nextTransition, NUMBER, 1);
2063
+ target[position++] = number;
2064
+ } else {
2065
+ transition = nextTransition.num32 || createTypeTransition(nextTransition, NUMBER, 4);
2066
+ targetView.setUint32(position, number, true);
2067
+ position += 4;
2068
+ }
1971
2069
  break;
1972
- } else if (value < 0x100000000 && value >= -0x80000000) {
1973
- targetView.setFloat32(position, value, true);
2070
+ } else if (number < 0x100000000 && number >= -0x80000000) {
2071
+ targetView.setFloat32(position, number, true);
1974
2072
  if (float32Headers[target[position + 3] >>> 5]) {
1975
2073
  let xShifted;
1976
2074
  // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1977
- if (((xShifted = value * mult10[((target[position + 3] & 0x7f) << 1) | (target[position + 2] >> 7)]) >> 0) === xShifted) {
2075
+ if (((xShifted = number * mult10[((target[position + 3] & 0x7f) << 1) | (target[position + 2] >> 7)]) >> 0) === xShifted) {
2076
+ transition = nextTransition.num32 || createTypeTransition(nextTransition, NUMBER, 4);
1978
2077
  position += 4;
1979
- continue;
2078
+ break;
1980
2079
  }
1981
2080
  }
1982
2081
  }
1983
- // fall back to msgpack encoding
1984
- queuedReferences.push(value, position - start);
1985
- position += 4;
1986
- continue;
2082
+ transition = nextTransition.num64 || createTypeTransition(nextTransition, NUMBER, 8);
2083
+ targetView.setFloat64(position, number, true);
2084
+ position += 8;
2085
+ break;
1987
2086
  case 'string':
1988
- if (hasNonLatin$1.test(value)) {
1989
- queuedReferences.push(value, position - start);
1990
- position += 4;
1991
- continue;
2087
+ let strLength = value.length;
2088
+ refOffset = refPosition - refsStartPosition;
2089
+ if ((strLength << 2) + position > safeEnd) {
2090
+ let lastStart = start;
2091
+ target = makeRoom(refPosition);
2092
+ targetView = target.dataView;
2093
+ position -= lastStart;
2094
+ refsStartPosition -= lastStart;
2095
+ refPosition -= lastStart;
2096
+ start = 0;
2097
+ safeEnd = target.length - 10;
1992
2098
  }
1993
- if (value.length < 4) { // we can inline really small strings
1994
- encoded = 0xf8000000 + (value.length << 24) + (value.charCodeAt(0) << 16) + (value.charCodeAt(1) << 8) + (value.charCodeAt(2) || 0);
1995
- // TODO: determining remaining and make max value be a ratio of that (probably 1/256th)
1996
- } else if (value.length < 256 && stringData.length < 61440) {
1997
- // bundle these strings
1998
- encoded = 0x60000000 | (value.length << 16) | stringData.length;
1999
- stringData += value;
2000
- } else { // else queue it
2001
- queuedReferences.push(value, position - start);
2002
- position += 4;
2003
- continue;
2099
+ if (strLength > ((0xff00 + refOffset) >> 2)) {
2100
+ queuedReferences.push(key, value, position - start);
2101
+ break;
2102
+ }
2103
+ let isNotAscii;
2104
+ let strStart = refPosition;
2105
+ if (strLength < 0x40) {
2106
+ let i, c1, c2;
2107
+ for (i = 0; i < strLength; i++) {
2108
+ c1 = value.charCodeAt(i);
2109
+ if (c1 < 0x80) {
2110
+ target[refPosition++] = c1;
2111
+ } else if (c1 < 0x800) {
2112
+ isNotAscii = true;
2113
+ target[refPosition++] = c1 >> 6 | 0xc0;
2114
+ target[refPosition++] = c1 & 0x3f | 0x80;
2115
+ } else if (
2116
+ (c1 & 0xfc00) === 0xd800 &&
2117
+ ((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
2118
+ ) {
2119
+ isNotAscii = true;
2120
+ c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
2121
+ i++;
2122
+ target[refPosition++] = c1 >> 18 | 0xf0;
2123
+ target[refPosition++] = c1 >> 12 & 0x3f | 0x80;
2124
+ target[refPosition++] = c1 >> 6 & 0x3f | 0x80;
2125
+ target[refPosition++] = c1 & 0x3f | 0x80;
2126
+ } else {
2127
+ isNotAscii = true;
2128
+ target[refPosition++] = c1 >> 12 | 0xe0;
2129
+ target[refPosition++] = c1 >> 6 & 0x3f | 0x80;
2130
+ target[refPosition++] = c1 & 0x3f | 0x80;
2131
+ }
2132
+ }
2133
+ } else {
2134
+ refPosition += encodeUtf8(target, value, refPosition);
2135
+ isNotAscii = refPosition - strStart > strLength;
2136
+ }
2137
+ if (refOffset < 0x100) {
2138
+ if (isNotAscii)
2139
+ transition = nextTransition.string8 || createTypeTransition(nextTransition, UTF8, 1);
2140
+ else
2141
+ transition = nextTransition.ascii8 || createTypeTransition(nextTransition, ASCII, 1);
2142
+ target[position++] = refOffset;
2143
+ } else {
2144
+ if (isNotAscii)
2145
+ transition = nextTransition.string16 || createTypeTransition(nextTransition, UTF8, 2);
2146
+ else
2147
+ transition = nextTransition.ascii16 || createTypeTransition(nextTransition, ASCII, 2);
2148
+ targetView.setUint16(position, refOffset, true);
2149
+ position += 2;
2004
2150
  }
2005
2151
  break;
2006
2152
  case 'object':
2007
2153
  if (value) {
2008
- queuedReferences.push(value, position - start);
2009
- position += 4;
2010
- continue;
2154
+ //transition = nextTransition.object16 || createTypeTransition(nextTransition, OBJECT_DATA, 2);
2155
+ queuedReferences.push(key, value, keyIndex);
2156
+ break;
2011
2157
  } else { // null
2012
- encoded = 0xe0000000;
2158
+ nextTransition = anyType(nextTransition, position, targetView, -10); // match CBOR with this
2159
+ if (nextTransition) {
2160
+ transition = nextTransition;
2161
+ position = updatedPosition;
2162
+ } else queuedReferences.push(key, value, keyIndex);
2013
2163
  }
2014
2164
  break;
2015
2165
  case 'boolean':
2016
- encoded = value ? 0xe3000000 : 0xe2000000;
2166
+ transition = nextTransition.num8 || nextTransition.ascii8 || createTypeTransition(nextTransition, NUMBER, 1);
2167
+ target[position++] = value ? 0xf9 : 0xf8; // match CBOR with these
2017
2168
  break;
2018
2169
  case 'undefined':
2019
- encoded = 0xe1000000;
2170
+ nextTransition = anyType(nextTransition, position, targetView, -9); // match CBOR with this
2171
+ if (nextTransition) {
2172
+ transition = nextTransition;
2173
+ position = updatedPosition;
2174
+ } else queuedReferences.push(key, value, keyIndex);
2020
2175
  break;
2021
2176
  }
2022
- targetView.setUint32(position, encoded, true);
2023
- position += 4;
2177
+ keyIndex++;
2024
2178
  }
2025
- let recordId = transition[RECORD_SYMBOL];
2026
- if (!(recordId < 1024)) {
2027
- // for now just punt and go back to writeObject
2028
- return 0;
2029
- // newRecord(transition, transition.__keys__ || Object.keys(object), newTransitions, true)
2030
- }
2031
- let stringLength = stringData.length;
2032
- if (stringData) {
2033
- if (position + stringLength > safeEnd) {
2034
- target = makeRoom(position + stringLength);
2035
- }
2036
- position += target.latin1Write(stringData, position, 0xffffffff);
2037
- }
2038
- target[start] = recordId >> 8;
2039
- target[start + 1] = recordId & 0xff;
2040
- target[start + 2] = stringLength >> 8;
2041
- target[start + 3] = stringLength & 0xff;
2042
- let queued32BitReferences;
2179
+
2043
2180
  for (let i = 0, l = queuedReferences.length; i < l;) {
2181
+ let key = queuedReferences[i++];
2044
2182
  let value = queuedReferences[i++];
2045
- let slotOffset = queuedReferences[i++] + start;
2046
- let offset = position - slotOffset;
2047
- if (offset < 0x1f000000) {
2048
- targetView.setUint32(slotOffset, 0x80000000 | (offset), true);
2183
+ let propertyIndex = queuedReferences[i++];
2184
+ let nextTransition = transition[key];
2185
+ if (!nextTransition) {
2186
+ transition[key] = nextTransition = {
2187
+ key,
2188
+ parent: transition,
2189
+ enumerationOffset: propertyIndex - keyIndex,
2190
+ ascii0: null,
2191
+ ascii8: null,
2192
+ num8: null,
2193
+ string16: null,
2194
+ object16: null,
2195
+ num32: null,
2196
+ float64: null
2197
+ };
2198
+ }
2199
+ let newPosition;
2200
+ if (value) {
2201
+ /*if (typeof value === 'string') { // TODO: we could re-enable long strings
2202
+ if (position + value.length * 3 > safeEnd) {
2203
+ target = makeRoom(position + value.length * 3);
2204
+ position -= start;
2205
+ targetView = target.dataView;
2206
+ start = 0;
2207
+ }
2208
+ newPosition = position + target.utf8Write(value, position, 0xffffffff);
2209
+ } else { */
2210
+ let size;
2211
+ refOffset = refPosition - refsStartPosition;
2212
+ if (refOffset < 0xff00) {
2213
+ transition = nextTransition.object16;
2214
+ if (transition)
2215
+ size = 2;
2216
+ else if ((transition = nextTransition.object32))
2217
+ size = 4;
2218
+ else {
2219
+ transition = createTypeTransition(nextTransition, OBJECT_DATA, 2);
2220
+ size = 2;
2221
+ }
2222
+ } else {
2223
+ transition = nextTransition.object32 || createTypeTransition(nextTransition, OBJECT_DATA, 4);
2224
+ size = 4;
2225
+ }
2226
+ newPosition = pack(value, refPosition);
2227
+ //}
2228
+ if (typeof newPosition === 'object') {
2229
+ // re-allocated
2230
+ refPosition = newPosition.position;
2231
+ targetView = newPosition.targetView;
2232
+ target = newPosition.target;
2233
+ refsStartPosition -= start;
2234
+ position -= start;
2235
+ start = 0;
2236
+ } else
2237
+ refPosition = newPosition;
2238
+ if (size === 2) {
2239
+ targetView.setUint16(position, refOffset, true);
2240
+ position += 2;
2241
+ } else {
2242
+ targetView.setUint32(position, refOffset, true);
2243
+ position += 4;
2244
+ }
2049
2245
  } else {
2050
- if (!queued32BitReferences)
2051
- queued32BitReferences = [];
2052
- queued32BitReferences.push({slotOffset, offset: position - start});
2246
+ transition = nextTransition.object16 || createTypeTransition(nextTransition, OBJECT_DATA, 2);
2247
+ targetView.setInt16(position, value === null ? -10 : -9, true);
2248
+ position += 2;
2053
2249
  }
2054
- let newPosition = pack(value, position);
2055
- if (typeof newPosition === 'object') {
2056
- // re-allocated
2057
- position = newPosition.position;
2058
- targetView = newPosition.targetView;
2059
- start = 0;
2060
- } else
2061
- position = newPosition;
2250
+ keyIndex++;
2062
2251
  }
2063
- if (queued32BitReferences) {
2064
- // TODO: makeRoom
2065
- for (let i = 0, l = queued32BitReferences.length; i < l; i++) {
2066
- let ref = queued32BitReferences[i];
2067
- targetView.setUint32(ref.slotOffset, 0xa0000000 - ((l - i) << 2), true);
2068
- targetView.setUint32(position, ref.offset, true);
2069
- position += 4;
2252
+
2253
+
2254
+ let recordId = transition[RECORD_SYMBOL];
2255
+ if (recordId == null) {
2256
+ recordId = packr.typedStructs.length;
2257
+ let structure = [];
2258
+ let nextTransition = transition;
2259
+ let key, type;
2260
+ while ((type = nextTransition.__type) !== undefined) {
2261
+ let size = nextTransition.__size;
2262
+ nextTransition = nextTransition.__parent;
2263
+ key = nextTransition.key;
2264
+ let property = [type, size, key];
2265
+ if (nextTransition.enumerationOffset)
2266
+ property.push(nextTransition.enumerationOffset);
2267
+ structure.push(property);
2268
+ nextTransition = nextTransition.parent;
2070
2269
  }
2270
+ structure.reverse();
2271
+ transition[RECORD_SYMBOL] = recordId;
2272
+ packr.typedStructs[recordId] = structure;
2273
+ pack(null, 0, true); // special call to notify that structures have been updated
2274
+ }
2275
+
2276
+
2277
+ switch (headerSize) {
2278
+ case 1:
2279
+ if (recordId >= 0x10) return 0;
2280
+ target[start] = recordId + 0x20;
2281
+ break;
2282
+ case 2:
2283
+ if (recordId >= 0x100) return 0;
2284
+ target[start] = 0x38;
2285
+ target[start + 1] = recordId;
2286
+ break;
2287
+ case 3:
2288
+ if (recordId >= 0x10000) return 0;
2289
+ target[start] = 0x39;
2290
+ target.setUint16(start + 1, recordId, true);
2291
+ break;
2292
+ case 4:
2293
+ if (recordId >= 0x1000000) return 0;
2294
+ target.setUint32(start, (recordId << 8) + 0x3a, true);
2295
+ break;
2071
2296
  }
2072
2297
 
2073
- return position;
2298
+ if (position < refsStartPosition) {
2299
+ if (refsStartPosition === refPosition)
2300
+ return position; // no refs
2301
+ // adjust positioning
2302
+ target.copyWithin(position, refsStartPosition, refPosition);
2303
+ refPosition += position - refsStartPosition;
2304
+ typedStructs.lastStringStart = position - start;
2305
+ } else if (position > refsStartPosition) {
2306
+ if (refsStartPosition === refPosition)
2307
+ return position; // no refs
2308
+ typedStructs.lastStringStart = position - start;
2309
+ return writeStruct(object, target, start, structures, makeRoom, pack, packr);
2310
+ }
2311
+ return refPosition;
2312
+ }
2313
+ function anyType(transition, position, targetView, value) {
2314
+ let nextTransition;
2315
+ if ((nextTransition = transition.ascii8 || transition.num8)) {
2316
+ targetView.setInt8(position, value, true);
2317
+ updatedPosition = position + 1;
2318
+ return nextTransition;
2319
+ }
2320
+ if ((nextTransition = transition.string16 || transition.object16)) {
2321
+ targetView.setInt16(position, value, true);
2322
+ updatedPosition = position + 2;
2323
+ return nextTransition;
2324
+ }
2325
+ if (nextTransition = transition.num32) {
2326
+ targetView.setUint32(position, 0xe0000100 + value, true);
2327
+ updatedPosition = position + 4;
2328
+ return nextTransition;
2329
+ }
2330
+ // transition.float64
2331
+ if (nextTransition = transition.num64) {
2332
+ targetView.setFloat64(position, NaN, true);
2333
+ targetView.setInt8(position, value);
2334
+ updatedPosition = position + 8;
2335
+ return nextTransition;
2336
+ }
2337
+ updatedPosition = position;
2338
+ // TODO: can we do an "any" type where we defer the decision?
2339
+ return;
2340
+ }
2341
+ function createTypeTransition(transition, type, size) {
2342
+ let typeName = TYPE_NAMES[type] + (size << 3);
2343
+ let newTransition = transition[typeName] || (transition[typeName] = Object.create(null));
2344
+ newTransition.__type = type;
2345
+ newTransition.__size = size;
2346
+ newTransition.__parent = transition;
2347
+ return newTransition;
2348
+ }
2349
+ function onLoadedStructures$1(sharedData) {
2350
+ if (!(sharedData instanceof Map))
2351
+ return sharedData;
2352
+ let typed = sharedData.get('typed') || [];
2353
+ if (Object.isFrozen(typed))
2354
+ typed = typed.map(structure => structure.slice(0));
2355
+ let named = sharedData.get('named');
2356
+ let transitions = Object.create(null);
2357
+ for (let i = 0, l = typed.length; i < l; i++) {
2358
+ let structure = typed[i];
2359
+ let transition = transitions;
2360
+ for (let [type, size, key] of structure) {
2361
+ let nextTransition = transition[key];
2362
+ if (!nextTransition) {
2363
+ transition[key] = nextTransition = {
2364
+ key,
2365
+ parent: transition,
2366
+ enumerationOffset: 0,
2367
+ ascii0: null,
2368
+ ascii8: null,
2369
+ num8: null,
2370
+ string16: null,
2371
+ object16: null,
2372
+ num32: null,
2373
+ float64: null
2374
+ };
2375
+ }
2376
+ transition = createTypeTransition(nextTransition, type, size);
2377
+ }
2378
+ transition[RECORD_SYMBOL] = i;
2379
+ }
2380
+ typed.transitions = transitions;
2381
+ this.typedStructs = typed;
2382
+ this.lastTypedStructuresLength = typed.length;
2383
+ return named;
2074
2384
  }
2075
2385
  var sourceSymbol = Symbol('source');
2076
- function readStruct$1(src, position, srcEnd, structure, unpackr) {
2077
- var stringLength = (src[position++] << 8) | src[position++];
2386
+ function readStruct$1(src, position, srcEnd, unpackr) {
2387
+ // var stringLength = (src[position++] << 8) | src[position++];
2388
+ let recordId = src[position++] - 0x20;
2389
+ if (recordId >= 24) {
2390
+ switch(recordId) {
2391
+ case 24: recordId = src[position++]; break;
2392
+ // little endian:
2393
+ case 25: recordId = src[position++] + (src[position++] << 8); break;
2394
+ case 26: recordId = src[position++] + (src[position++] << 8) + (src[position++] << 16); break;
2395
+ case 27: recordId = src[position++] + (src[position++] << 8) + (src[position++] << 16) + (src[position++] << 24); break;
2396
+ }
2397
+ }
2398
+ let structure = unpackr.typedStructs?.[recordId];
2399
+ if (!structure) {
2400
+ // copy src buffer because getStructures will override it
2401
+ src = Uint8Array.prototype.slice.call(src, position, srcEnd);
2402
+ srcEnd -= position;
2403
+ position = 0;
2404
+ unpackr._mergeStructures(unpackr.getStructures());
2405
+ if (!unpackr.typedStructs)
2406
+ throw new Error('Could not find any shared typed structures');
2407
+ unpackr.lastTypedStructuresLength = unpackr.typedStructs.length;
2408
+ structure = unpackr.typedStructs[recordId];
2409
+ if (!structure)
2410
+ throw new Error('Could not find typed structure ' + recordId);
2411
+ }
2078
2412
  var construct = structure.construct;
2079
2413
  if (!construct) {
2080
- construct = structure.construct = function() {
2414
+ construct = structure.construct = function LazyObject() {
2081
2415
  };
2082
2416
  var prototype = construct.prototype;
2417
+ let properties = [];
2083
2418
  Object.defineProperty(prototype, 'toJSON', {
2084
- get() {
2419
+ value() {
2085
2420
  // return an enumerable object with own properties to JSON stringify
2086
2421
  let resolved = {};
2087
- for (let i = 0, l = structure.length; i < l; i++) {
2088
- let key = structure[i];
2422
+ for (let i = 0, l = properties.length; i < l; i++) {
2423
+ let key = properties[i].key;
2089
2424
  resolved[key] = this[key];
2090
2425
  }
2091
2426
  return resolved;
2092
2427
  },
2093
2428
  // not enumerable or anything
2094
2429
  });
2430
+ let currentOffset = 0;
2431
+ let lastRefProperty;
2095
2432
  for (let i = 0, l = structure.length; i < l; i++) {
2096
- let key = structure[i];
2097
- Object.defineProperty(prototype, key, {
2098
- get() {
2099
- let source = this[sourceSymbol];
2100
- let src = source.src;
2101
- //let uint32 = src.uint32 || (src.uint32 = new Uint32Array(src.buffer, src.byteOffset, src.byteLength));
2102
- let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2103
- let position = source.position + (i << 2);
2104
- let value = dataView.getUint32(position, true);
2105
- let start;
2106
- switch (value >>> 29) {
2107
- case 0:
2108
- return value;
2109
- case 3:
2110
- if (value & 0x10000000) {
2111
- start = (value & 0xffff) + position;
2112
- return src.toString('utf8', start, start + ((value >> 16) & 0x7ff));
2113
- } else {
2114
- if (!source.srcString) {
2115
- start = source.position + (l << 2);
2116
- source.srcString = src.toString('latin1', start, start + source.stringLength);
2117
- }
2118
- start = value & 0xffff;
2119
- return source.srcString.slice(start, start + ((value >> 16) & 0x7ff));
2120
- }
2121
- case 4:
2122
- start = (0x1fffffff & value) + position;
2123
- let end = source.srcEnd;
2124
- for (let next = i + 1; next < l; next++) {
2125
- position = source.position + (next << 2);
2126
- let nextValue = dataView.getUint32(position, true); if ((nextValue & 0xe0000000) == -0x80000000) {
2127
- end = (0x1fffffff & nextValue) + position;
2433
+ let definition = structure[i];
2434
+ let [ type, size, key, enumerationOffset ] = definition;
2435
+ let property = {
2436
+ key,
2437
+ offset: currentOffset,
2438
+ };
2439
+ if (enumerationOffset)
2440
+ properties.splice(i + enumerationOffset, 0, property);
2441
+ else
2442
+ properties.push(property);
2443
+ let getRef;
2444
+ switch(size) { // TODO: Move into a separate function
2445
+ case 0: getRef = () => 0; break;
2446
+ case 1:
2447
+ getRef = (source, position) => {
2448
+ let ref = source.src[position + property.offset];
2449
+ return ref >= 0xf6 ? toConstant(ref) : ref;
2450
+ };
2451
+ break;
2452
+ case 2:
2453
+ getRef = (source, position) => {
2454
+ let src = source.src;
2455
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2456
+ let ref = dataView.getUint16(position + property.offset, true);
2457
+ return ref >= 0xff00 ? toConstant(ref & 0xff) : ref;
2458
+ };
2459
+ break;
2460
+ case 4:
2461
+ getRef = (source, position) => {
2462
+ let src = source.src;
2463
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2464
+ let ref = dataView.getUint32(position + property.offset, true);
2465
+ return ref >= 0xffffff00 ? toConstant(ref & 0xff) : ref;
2466
+ };
2467
+ break;
2468
+ }
2469
+ property.getRef = getRef;
2470
+ currentOffset += size;
2471
+ let get;
2472
+ switch(type) {
2473
+ case ASCII:
2474
+ if (lastRefProperty && !lastRefProperty.next)
2475
+ lastRefProperty.next = property;
2476
+ lastRefProperty = property;
2477
+ property.multiGetCount = 0;
2478
+ get = function() {
2479
+ let source = this[sourceSymbol];
2480
+ let src = source.src;
2481
+ let position = source.position;
2482
+ let refStart = currentOffset + position;
2483
+ let ref = getRef(source, position);
2484
+ if (typeof ref !== 'number') return ref;
2485
+
2486
+ let end, next = property.next;
2487
+ while(next) {
2488
+ end = next.getRef(source, position);
2489
+ if (typeof end === 'number')
2490
+ break;
2491
+ else
2492
+ end = null;
2493
+ next = next.next;
2494
+ }
2495
+ if (end == null)
2496
+ end = source.srcEnd - refStart;
2497
+ if (source.srcString) {
2498
+ return source.srcString.slice(ref, end);
2499
+ }
2500
+ /*if (property.multiGetCount > 0) {
2501
+ let asciiEnd;
2502
+ next = firstRefProperty;
2503
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2504
+ do {
2505
+ asciiEnd = dataView.getUint16(source.position + next.offset, true);
2506
+ if (asciiEnd < 0xff00)
2128
2507
  break;
2508
+ else
2509
+ asciiEnd = null;
2510
+ } while((next = next.next));
2511
+ if (asciiEnd == null)
2512
+ asciiEnd = source.srcEnd - refStart
2513
+ source.srcString = src.toString('latin1', refStart, refStart + asciiEnd);
2514
+ return source.srcString.slice(ref, end);
2515
+ }
2516
+ if (source.prevStringGet) {
2517
+ source.prevStringGet.multiGetCount += 2;
2518
+ } else {
2519
+ source.prevStringGet = property;
2520
+ property.multiGetCount--;
2521
+ }*/
2522
+ return readString(src, ref + refStart, end - ref);
2523
+ //return src.toString('latin1', ref + refStart, end + refStart);
2524
+ };
2525
+ break;
2526
+ case UTF8: case OBJECT_DATA:
2527
+ if (lastRefProperty && !lastRefProperty.next)
2528
+ lastRefProperty.next = property;
2529
+ lastRefProperty = property;
2530
+ get = function() {
2531
+ let source = this[sourceSymbol];
2532
+ let position = source.position;
2533
+ let refStart = currentOffset + position;
2534
+ let ref = getRef(source, position);
2535
+ if (typeof ref !== 'number') return ref;
2536
+ let src = source.src;
2537
+ let end, next = property.next;
2538
+ while(next) {
2539
+ end = next.getRef(source, position);
2540
+ if (typeof end === 'number')
2541
+ break;
2542
+ else
2543
+ end = null;
2544
+ next = next.next;
2545
+ }
2546
+ if (end == null)
2547
+ end = source.srcEnd - refStart;
2548
+ if (type === UTF8) {
2549
+ return src.toString('utf8', ref + refStart, end + refStart);
2550
+ } else {
2551
+ return unpackr.unpack(src, { start: ref + refStart, end: end + refStart }); // could reuse this object
2552
+ }
2553
+ };
2554
+ break;
2555
+ case NUMBER:
2556
+ switch(size) {
2557
+ case 4:
2558
+ get = function () {
2559
+ let source = this[sourceSymbol];
2560
+ let src = source.src;
2561
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2562
+ let position = source.position + property.offset;
2563
+ let value = dataView.getInt32(position, true);
2564
+ if (value < 0x20000000) {
2565
+ if (value > -0x1f000000)
2566
+ return value;
2567
+ if (value > -0x20000000)
2568
+ return toConstant(value & 0xff);
2129
2569
  }
2130
- }
2131
- return unpackr.unpack(src.slice(start, end));
2132
- case 1: case 2: case 5: case 6:
2133
- let fValue = dataView.getFloat32(position, true);
2134
- // this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
2135
- let multiplier = mult10[((src[position + 3] & 0x7f) << 1) | (src[position + 2] >> 7)];
2136
- return ((multiplier * fValue + (fValue > 0 ? 0.5 : -0.5)) >> 0) / multiplier;
2137
- case 7:
2138
- switch((value >> 24) & 0x1f) {
2139
- case 0: return null;
2140
- case 1: return undefined;
2141
- case 2: return false;
2142
- case 3: return true;
2143
- case 8: return dataView.getFloat64(position + (value & 0x3ffffff), true);
2144
- case 0x18: return '';
2145
- case 0x19: return String.fromCharCode((value >> 16) & 0xff);
2146
- case 0x1a: return String.fromCharCode((value >> 16) & 0xff, (value >> 8) & 0xff);
2147
- case 0x1b: return String.fromCharCode((value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff);
2148
- default: throw new Error('Unknown constant');
2149
- }
2570
+ let fValue = dataView.getFloat32(position, true);
2571
+ // this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
2572
+ let multiplier = mult10[((src[position + 3] & 0x7f) << 1) | (src[position + 2] >> 7)];
2573
+ return ((multiplier * fValue + (fValue > 0 ? 0.5 : -0.5)) >> 0) / multiplier;
2574
+ };
2575
+ break;
2576
+ case 8:
2577
+ get = function () {
2578
+ let source = this[sourceSymbol];
2579
+ let src = source.src;
2580
+ let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2581
+ let value = dataView.getFloat64(source.position + property.offset, true);
2582
+ if (isNaN(value)) {
2583
+ let byte = src[source.position + property.offset];
2584
+ if (byte >= 0xf6)
2585
+ return toConstant(byte);
2586
+ }
2587
+ return value;
2588
+ };
2589
+ break;
2590
+ case 1:
2591
+ get = function () {
2592
+ let source = this[sourceSymbol];
2593
+ let src = source.src;
2594
+ let value = src[source.position + property.offset];
2595
+ return value < 0xf6 ? value : toConstant(value);
2596
+ };
2597
+ break;
2150
2598
  }
2151
- },
2152
- enumerable: true,
2153
- });
2599
+ }
2600
+ property.get = get;
2154
2601
  }
2602
+ for (let property of properties) // assign in enumeration order
2603
+ Object.defineProperty(prototype, property.key, { get: property.get, enumerable: true });
2155
2604
  }
2156
2605
  var instance = new construct();
2157
2606
  instance[sourceSymbol] = {
2158
2607
  src,
2159
- uint32: src.uint32,
2160
2608
  position,
2161
2609
  srcString: '',
2162
- srcEnd,
2163
- stringLength
2610
+ srcEnd
2164
2611
  };
2165
2612
  return instance;
2166
2613
  }
2167
- setReadStruct(readStruct$1);
2614
+ function toConstant(code) {
2615
+ switch(code) {
2616
+ case 0xf6: return null;
2617
+ case 0xf7: return undefined;
2618
+ case 0xf8: return false;
2619
+ case 0xf9: return true;
2620
+ }
2621
+ throw new Error('Unknown constant');
2622
+ }
2623
+ function prepareStructures$1(structures, packr) {
2624
+ if (packr.typedStructs) {
2625
+ let structMap = new Map();
2626
+ structMap.set('named', structures);
2627
+ structMap.set('typed', packr.typedStructs);
2628
+ structures = structMap;
2629
+ }
2630
+ let lastTypedStructuresLength = packr.lastTypedStructuresLength || 0;
2631
+ structures.isCompatible = existing => {
2632
+ let compatible = true;
2633
+ if (existing instanceof Map) {
2634
+ let named = existing.get('named') || [];
2635
+ if (named.length !== (packr.lastNamedStructuresLength || 0))
2636
+ compatible = false;
2637
+ let typed = existing.get('typed') || [];
2638
+ if (typed.length !== lastTypedStructuresLength)
2639
+ compatible = false;
2640
+ } else if (existing instanceof Array) {
2641
+ if (existing.length !== (packr.lastNamedStructuresLength || 0))
2642
+ compatible = false;
2643
+ }
2644
+ if (!compatible)
2645
+ packr._mergeStructures(existing);
2646
+ return compatible;
2647
+ };
2648
+ packr.lastTypedStructuresLength = packr.typedStructs?.length;
2649
+ return structures;
2650
+ }
2168
2651
 
2169
- const allSampleData = [];
2652
+ setReadStruct(readStruct$1, onLoadedStructures$1);
2653
+
2654
+ let allSampleData = [];
2170
2655
  for (let i = 1; i < 6; i++) {
2171
2656
  allSampleData.push(JSON.parse(fs.readFileSync(new URL(`./example${i > 1 ? i : ''}.json`, (document.currentScript && document.currentScript.src || new URL('test.js', document.baseURI).href)))));
2172
2657
  }
@@ -2178,6 +2663,13 @@
2178
2663
  return {}
2179
2664
  }
2180
2665
  }
2666
+
2667
+ let seed = 0;
2668
+ function random() {
2669
+ seed++;
2670
+ let a = seed * 15485863;
2671
+ return (a * a * a % 2038074743) / 2038074743;
2672
+ }
2181
2673
  //if (typeof chai === 'undefined') { chai = require('chai') }
2182
2674
  var assert = chai.assert;
2183
2675
  //if (typeof msgpackr === 'undefined') { msgpackr = require('..') }
@@ -2276,6 +2768,36 @@
2276
2768
  var deserialized = unpack(serialized);
2277
2769
  assert.equal(deserialized, data);
2278
2770
  });
2771
+ test('pack/unpack varying data with random access structures', function() {
2772
+ let structures = [];
2773
+ let packr = new Packr$1({ structures, useRecords: true, randomAccessStructure: true, freezeData: true, saveStructures(structures) {
2774
+ }, getStructures() {
2775
+ console.log('getStructures');
2776
+ } });
2777
+ for (let i = 0; i < 20; i++) {
2778
+ let data = {};
2779
+ let props = ['foo', 'bar', 'a', 'b', 'c','name', 'age', 'd'];
2780
+ function makeString() {
2781
+ let str = '';
2782
+ while (random() < 0.9) {
2783
+ str += random() < 0.8 ? 'hello world' : String.fromCharCode(300);
2784
+ }
2785
+ return str;
2786
+ }
2787
+ for (let i = 0; i < random() * 20; i++) {
2788
+ data[props[Math.floor(random() * 8)]] =
2789
+ random() < 0.3 ? Math.floor(random() * 400) / 2 :
2790
+ random() < 0.3 ? makeString() : random() < 0.3 ? true : random() < 0.3 ? sampleData : null;
2791
+ }
2792
+ var serialized = packr.pack(data);
2793
+ var deserialized = packr.unpack(serialized);
2794
+ for (let key in deserialized) {
2795
+ let a = deserialized[key];
2796
+ }
2797
+ assert.deepEqual(deserialized, data);
2798
+ }
2799
+ });
2800
+
2279
2801
  for (let sampleData of allSampleData) {
2280
2802
  let snippet = JSON.stringify(sampleData).slice(0, 20) + '...';
2281
2803
  test('pack/unpack sample data ' + snippet, function(){
@@ -2290,11 +2812,18 @@
2290
2812
  test('pack/unpack sample data with random access structures ' + snippet, function() {
2291
2813
  var data = sampleData;
2292
2814
  let structures = [];
2293
- let packr = new Packr$1({ structures, useRecords: true, randomAccessStructure: true, freezeData: true });
2815
+ let packr = new Packr$1({ structures, useRecords: true, randomAccessStructure: true, freezeData: true, saveStructures(structures) {
2816
+ }, getStructures() {
2817
+ console.log('getStructures');
2818
+ } });
2294
2819
  for (let i = 0; i < 20; i++) {
2295
2820
  var serialized = packr.pack(data);
2296
- var deserialized = packr.unpack(serialized);
2297
- assert.deepEqual(deserialized, data);
2821
+ var deserialized = packr.unpack(serialized, { lazy: true });
2822
+ var copied = {};
2823
+ for (let key in deserialized) {
2824
+ copied[key] = deserialized[key];
2825
+ }
2826
+ assert.deepEqual(copied, data);
2298
2827
  }
2299
2828
  });
2300
2829
  test('pack/unpack sample data with bundled strings ' + snippet, function(){
@@ -2304,6 +2833,7 @@
2304
2833
  var deserialized = packr.unpack(serialized);
2305
2834
  assert.deepEqual(deserialized, data);
2306
2835
  });
2836
+ break;
2307
2837
  }
2308
2838
 
2309
2839
  test('pack/unpack empty data with bundled strings', function(){
@@ -2886,5 +3416,5 @@
2886
3416
  });
2887
3417
  });
2888
3418
 
2889
- }(msgpackr, chai, fs));
3419
+ }(msgpackr, chai, inspector, fs));
2890
3420
  //# sourceMappingURL=test.js.map