cbor-x 0.8.2 → 0.9.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
@@ -14,6 +14,7 @@ let srcEnd;
14
14
  let position = 0;
15
15
  const EMPTY_ARRAY = [];
16
16
  const RECORD_TAG_ID = 0x69;
17
+ const PACKED_REFERENCE_TAG_ID = 6;
17
18
  const STOP_CODE = {};
18
19
  let strings = EMPTY_ARRAY;
19
20
  let stringPosition = 0;
@@ -24,11 +25,15 @@ let srcStringStart = 0;
24
25
  let srcStringEnd = 0;
25
26
  let referenceMap;
26
27
  let currentExtensions = [];
28
+ let currentExtensionRanges = [];
29
+ let packedValues;
27
30
  let dataView;
31
+ let restoreMapsAsObject;
28
32
  let defaultOptions = {
29
33
  useRecords: false,
30
34
  mapsAsObjects: true
31
35
  };
36
+ let sequentialMode = false;
32
37
 
33
38
  class Decoder {
34
39
  constructor(options) {
@@ -40,12 +45,12 @@ class Decoder {
40
45
  }
41
46
  Object.assign(this, options);
42
47
  }
43
- decode(source, end, continueReading) {
48
+ decode(source, end) {
44
49
  if (src) {
45
50
  // re-entrant execution, save the state and restore it after we do this decode
46
51
  return saveState(() => {
47
52
  clearSource();
48
- return this ? this.decode(source, end, continueReading) : Decoder.prototype.decode.call(defaultOptions, source, end, continueReading)
53
+ return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
49
54
  })
50
55
  }
51
56
  srcEnd = end > -1 ? end : source.length;
@@ -61,19 +66,12 @@ class Decoder {
61
66
  dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
62
67
  if (this) {
63
68
  currentDecoder = this;
69
+ packedValues = this.sharedValues &&
70
+ (this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
71
+ this.sharedValues);
64
72
  if (this.structures) {
65
73
  currentStructures = this.structures;
66
- try {
67
- return read()
68
- } finally {
69
- if (position >= srcEnd || !continueReading) {
70
- // finished reading this source, cleanup references
71
- currentStructures = null;
72
- src = null;
73
- if (referenceMap)
74
- referenceMap = null;
75
- }
76
- }
74
+ return checkedRead()
77
75
  } else if (!currentStructures || currentStructures.length > 0) {
78
76
  currentStructures = [];
79
77
  }
@@ -81,27 +79,23 @@ class Decoder {
81
79
  currentDecoder = defaultOptions;
82
80
  if (!currentStructures || currentStructures.length > 0)
83
81
  currentStructures = [];
82
+ packedValues = null;
84
83
  }
85
- try {
86
- return read()
87
- } finally {
88
- if (position >= srcEnd || !continueReading) {
89
- src = null;
90
- if (referenceMap)
91
- referenceMap = null;
92
- }
93
- }
84
+ return checkedRead()
94
85
  }
95
86
  decodeMultiple(source, forEach) {
87
+ let values, lastPosition = 0;
96
88
  try {
97
- let decoder = this;
98
89
  let size = source.length;
99
- let value = this ? this.decode(source, size, true) : defaultDecoder.decode(source, size, true);
100
- let values;
90
+ sequentialMode = true;
91
+ let value = this ? this.decode(source, size) : defaultDecoder.decode(source, size);
101
92
  if (forEach) {
102
- forEach(value);
93
+ if (forEach(value) === false) {
94
+ return
95
+ }
103
96
  while(position < size) {
104
- if (forEach(read()) === false) {
97
+ lastPosition = position;
98
+ if (forEach(checkedRead()) === false) {
105
99
  return
106
100
  }
107
101
  }
@@ -109,17 +103,47 @@ class Decoder {
109
103
  else {
110
104
  values = [ value ];
111
105
  while(position < size) {
112
- values.push(read());
106
+ lastPosition = position;
107
+ values.push(checkedRead());
113
108
  }
114
109
  return values
115
110
  }
111
+ } catch(error) {
112
+ error.lastPosition = lastPosition;
113
+ error.values = values;
114
+ throw error
116
115
  } finally {
116
+ sequentialMode = false;
117
117
  clearSource();
118
118
  }
119
119
  }
120
120
  }
121
- function getPosition() {
122
- return position
121
+ function checkedRead() {
122
+ try {
123
+ let result = read();
124
+ if (position == srcEnd) {
125
+ // finished reading this source, cleanup references
126
+ currentStructures = null;
127
+ src = null;
128
+ if (referenceMap)
129
+ referenceMap = null;
130
+ } else if (position > srcEnd) {
131
+ // over read
132
+ let error = new Error('Unexpected end of CBOR data');
133
+ error.incomplete = true;
134
+ throw error
135
+ } else if (!sequentialMode) {
136
+ throw new Error('Data read, but end of buffer not reached')
137
+ }
138
+ // else more to read, but we are reading sequentially, so don't clear source yet
139
+ return result
140
+ } catch(error) {
141
+ clearSource();
142
+ if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
143
+ error.incomplete = true;
144
+ }
145
+ throw error
146
+ }
123
147
  }
124
148
 
125
149
  function read() {
@@ -185,6 +209,10 @@ function read() {
185
209
  object[key] = read();
186
210
  return object
187
211
  } else {
212
+ if (restoreMapsAsObject) {
213
+ currentDecoder.mapsAsObjects = true;
214
+ restoreMapsAsObject = false;
215
+ }
188
216
  let map = new Map();
189
217
  while ((key = read()) != STOP_CODE)
190
218
  map.set(key, read());
@@ -231,6 +259,10 @@ function read() {
231
259
  }
232
260
  return object
233
261
  } else {
262
+ if (restoreMapsAsObject) {
263
+ currentDecoder.mapsAsObjects = true;
264
+ restoreMapsAsObject = false;
265
+ }
234
266
  let map = new Map();
235
267
  for (let i = 0; i < token; i++) {
236
268
  map.set(read(), read());
@@ -270,9 +302,15 @@ function read() {
270
302
  return extension(read)
271
303
  else
272
304
  return extension(read())
305
+ } else {
306
+ let input = read();
307
+ for (let i = 0; i < currentExtensionRanges.length; i++) {
308
+ let value = currentExtensionRanges[i](token, input);
309
+ if (value !== undefined)
310
+ return value
311
+ }
312
+ return new Tag(input)
273
313
  }
274
- else
275
- return new Tag(read())
276
314
  }
277
315
  case 7: // fixed value
278
316
  switch (token) {
@@ -282,6 +320,9 @@ function read() {
282
320
  case 0x17: return; // undefined
283
321
  case 0x1f:
284
322
  default:
323
+ let packedValue = packedValues[token];
324
+ if (packedValue !== undefined)
325
+ return packedValue
285
326
  throw new Error('Unknown token ' + token)
286
327
  }
287
328
  default: // negative int
@@ -704,6 +745,23 @@ currentExtensions[RECORD_TAG_ID] = recordDefinition;
704
745
  currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
705
746
  return (glbl[data[0]] || Error)(data[1], data[2])
706
747
  };
748
+ const packedTable = (read) => {
749
+ if (src[position++] != 0x84)
750
+ throw new Error('Packed values structure must be followed by 4 element array')
751
+ let newPackedValues = read(); // packed values
752
+ packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
753
+ packedValues.prefixes = read();
754
+ packedValues.suffixes = read();
755
+ return read() // read the rump
756
+ };
757
+ packedTable.handlesRead = true;
758
+ currentExtensions[51] = packedTable;
759
+
760
+ currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
761
+ if (typeof data == 'number')
762
+ return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
763
+ throw new Error('No support for non-integer packed references yet')
764
+ };
707
765
 
708
766
  currentExtensions[40009] = (id) => {
709
767
  // id extension (for structured clones)
@@ -735,6 +793,36 @@ currentExtensions[40010] = (id) => {
735
793
  };
736
794
 
737
795
  currentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md
796
+ (currentExtensions[259] = (read) => {
797
+ // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
798
+ // for decoding as a standard Map
799
+ if (currentDecoder.mapsAsObjects) {
800
+ currentDecoder.mapsAsObjects = false;
801
+ restoreMapsAsObject = true;
802
+ }
803
+ return read()
804
+ }).handlesRead = true;
805
+ function combine(a, b) {
806
+ if (typeof a === 'string')
807
+ return a + b
808
+ if (a instanceof Array)
809
+ return a.concat(b)
810
+ return Object.assign({}, a, b)
811
+ }
812
+ currentExtensionRanges.push((tag, input) => {
813
+ if (tag >= 225 && tag <= 255)
814
+ return combine(packedTable.prefixes[tag - 224], input)
815
+ if (tag >= 28704 && tag <= 32767)
816
+ return combine(packedTable.prefixes[tag - 28672], input)
817
+ if (tag >= 1879052288 && tag <= 2147483647)
818
+ return combine(packedTable.prefixes[tag - 1879048192], input)
819
+ if (tag >= 216 && tag <= 223)
820
+ return combine(input, packedTable.suffixes[tag - 216])
821
+ if (tag >= 27647 && tag <= 28671)
822
+ return combine(input, packedTable.suffixes[tag - 27639])
823
+ if (tag >= 1811940352 && tag <= 1879048191)
824
+ return combine(input, packedTable.suffixes[tag - 1811939328])
825
+ });
738
826
 
739
827
  const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
740
828
  const typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 81, 82];
@@ -763,6 +851,7 @@ function saveState(callback) {
763
851
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
764
852
  let savedStructures = currentStructures;
765
853
  let savedDecoder = currentDecoder;
854
+ let savedSequentialMode = sequentialMode;
766
855
  let value = callback();
767
856
  srcEnd = savedSrcEnd;
768
857
  position = savedPosition;
@@ -773,6 +862,7 @@ function saveState(callback) {
773
862
  strings = savedStrings;
774
863
  referenceMap = savedReferenceMap;
775
864
  src = savedSrc;
865
+ sequentialMode = savedSequentialMode;
776
866
  currentStructures = savedStructures;
777
867
  currentDecoder = savedDecoder;
778
868
  dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
@@ -788,7 +878,7 @@ function addExtension(extension) {
788
878
  currentExtensions[extension.tag] = extension.decode;
789
879
  }
790
880
 
791
- let mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
881
+ const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
792
882
  for (let i = 0; i < 256; i++) {
793
883
  mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
794
884
  }
@@ -800,7 +890,14 @@ const FLOAT32_OPTIONS = {
800
890
  ALWAYS: 1,
801
891
  DECIMAL_ROUND: 3,
802
892
  DECIMAL_FIT: 4
803
- };
893
+ };
894
+ let f32Array = new Float32Array(1);
895
+ let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
896
+ function roundFloat32(float32Number) {
897
+ f32Array[0] = float32Number;
898
+ let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
899
+ return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
900
+ }
804
901
 
805
902
  let textEncoder;
806
903
  try {
@@ -827,6 +924,7 @@ class Encoder extends Decoder {
827
924
  let hasSharedUpdate;
828
925
  let structures;
829
926
  let referenceMap;
927
+ options = options || {};
830
928
  let lastSharedStructuresLength = 0;
831
929
  let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
832
930
  return target.utf8Write(string, position, maxBytes)
@@ -837,19 +935,25 @@ class Encoder extends Decoder {
837
935
 
838
936
  let encoder = this;
839
937
  let maxSharedStructures = 64;
840
- let isSequential = options && options.sequential;
938
+ let isSequential = options.sequential;
841
939
  if (isSequential) {
842
940
  maxSharedStructures = 0;
843
941
  this.structures = [];
844
942
  }
943
+ let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
944
+ let sharedPackedObjectMap;
945
+ if (sharedValues) {
946
+ sharedPackedObjectMap = Object.create(null);
947
+ for (let i = 0, l = sharedValues.length; i < l; i++) {
948
+ sharedPackedObjectMap[sharedValues[i]] = i;
949
+ }
950
+
951
+ }
845
952
  let recordIdsToRemove = [];
846
953
  let transitionsCount = 0;
847
954
  let serializationsSinceTransitionRebuild = 0;
848
- if (this.structures && this.structures.length > maxSharedStructures) {
849
- throw new Error('Too many shared structures')
850
- }
851
955
 
852
- this.encode = function(value) {
956
+ this.encode = function(value, encodeOptions) {
853
957
  if (!target) {
854
958
  target = new ByteArrayAllocate(8192);
855
959
  targetView = new DataView(target.buffer, 0, 8192);
@@ -862,7 +966,8 @@ class Encoder extends Decoder {
862
966
  targetView = new DataView(target.buffer, 0, target.length);
863
967
  safeEnd = target.length - 10;
864
968
  position$1 = 0;
865
- }
969
+ } else if (encodeOptions === REUSE_BUFFER_MODE)
970
+ position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
866
971
  start = position$1;
867
972
  referenceMap = encoder.structuredClone ? new Map() : null;
868
973
  sharedStructures = encoder.structures;
@@ -870,7 +975,7 @@ class Encoder extends Decoder {
870
975
  if (sharedStructures.uninitialized)
871
976
  encoder.structures = sharedStructures = encoder.getStructures();
872
977
  let sharedStructuresLength = sharedStructures.length;
873
- if (sharedStructuresLength > maxSharedStructures && !isSequential)
978
+ if (sharedStructuresLength > maxSharedStructures && !isSequential)
874
979
  sharedStructuresLength = maxSharedStructures;
875
980
  if (!sharedStructures.transitions) {
876
981
  // rebuild our structure transitions
@@ -880,8 +985,8 @@ class Encoder extends Decoder {
880
985
  if (!keys)
881
986
  continue
882
987
  let nextTransition, transition = sharedStructures.transitions;
883
- for (let i =0, l = keys.length; i < l; i++) {
884
- let key = keys[i];
988
+ for (let j = 0, l = keys.length; j < l; j++) {
989
+ let key = keys[j];
885
990
  nextTransition = transition[key];
886
991
  if (!nextTransition) {
887
992
  nextTransition = transition[key] = Object.create(null);
@@ -898,6 +1003,29 @@ class Encoder extends Decoder {
898
1003
  if (hasSharedUpdate)
899
1004
  hasSharedUpdate = false;
900
1005
  structures = sharedStructures || [];
1006
+ packedObjectMap = sharedPackedObjectMap;
1007
+ if (options.pack) {
1008
+ let packedValues = new Map();
1009
+ packedValues.values = [];
1010
+ packedValues.encoder = encoder;
1011
+ packedValues.maxValues = options.maxPrivatePackedValues || (sharedPackedObjectMap ? 16 : Infinity);
1012
+ packedValues.objectMap = sharedPackedObjectMap || false;
1013
+ packedValues.samplingPackedValues = samplingPackedValues;
1014
+ findRepetitiveStrings(value, packedValues);
1015
+ if (packedValues.values.length > 0) {
1016
+ target[position$1++] = 0xd8; // one-byte tag
1017
+ target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
1018
+ writeArrayHeader(4);
1019
+ let valuesArray = packedValues.values;
1020
+ encode(valuesArray);
1021
+ writeArrayHeader(0); // prefixes
1022
+ writeArrayHeader(0); // suffixes
1023
+ packedObjectMap = Object.create(sharedPackedObjectMap || null);
1024
+ for (let i = 0, l = valuesArray.length; i < l; i++) {
1025
+ packedObjectMap[valuesArray[i]] = i;
1026
+ }
1027
+ }
1028
+ }
901
1029
  try {
902
1030
  encode(value);
903
1031
  encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
@@ -910,7 +1038,12 @@ class Encoder extends Decoder {
910
1038
  referenceMap = null;
911
1039
  return serialized
912
1040
  }
913
- return target.subarray(start, position$1) // position can change if we call encode again in saveStructures, so we get the buffer now
1041
+ if (encodeOptions === REUSE_BUFFER_MODE) {
1042
+ target.start = start;
1043
+ target.end = position$1;
1044
+ return target
1045
+ }
1046
+ return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
914
1047
  } finally {
915
1048
  if (sharedStructures) {
916
1049
  if (serializationsSinceTransitionRebuild < 10)
@@ -924,7 +1057,7 @@ class Encoder extends Decoder {
924
1057
  recordIdsToRemove = [];
925
1058
  } else if (recordIdsToRemove.length > 0 && !isSequential) {
926
1059
  for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
927
- recordIdsToRemove[i][RECORD_SYMBOL] = 0;
1060
+ recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
928
1061
  }
929
1062
  recordIdsToRemove = [];
930
1063
  }
@@ -932,17 +1065,43 @@ class Encoder extends Decoder {
932
1065
  if (encoder.structures.length > maxSharedStructures) {
933
1066
  encoder.structures = encoder.structures.slice(0, maxSharedStructures);
934
1067
  }
1068
+ // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1069
+ let returnBuffer = target.subarray(start, position$1);
1070
+ let shared = encoder.structures || [];
1071
+ if (sharedValues) {
1072
+ shared = shared.concat(sharedValues);
1073
+ }
935
1074
 
936
1075
  if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
937
1076
  // get updated structures and try again if the update failed
938
1077
  encoder.structures = encoder.getStructures() || [];
939
1078
  return encoder.encode(value)
940
1079
  }
941
- lastSharedStructuresLength = encoder.structures.length;
1080
+ lastSharedStructuresLength = shared.length;
1081
+ return returnBuffer
942
1082
  }
943
1083
  }
944
1084
  }
945
1085
  };
1086
+ this.findCommonStringsToPack = () => {
1087
+ samplingPackedValues = new Map();
1088
+ if (!sharedPackedObjectMap)
1089
+ sharedPackedObjectMap = Object.create(null);
1090
+ return ({ threshold }) => {
1091
+ threshold = threshold || 4;
1092
+ let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
1093
+ if (!sharedValues)
1094
+ sharedValues = this.sharedValues = [];
1095
+ for (let [ key, status ] of samplingPackedValues) {
1096
+ if (status.count > threshold) {
1097
+ sharedPackedObjectMap[key] = position++;
1098
+ sharedValues.push(key);
1099
+ hasSharedUpdate = true;
1100
+ }
1101
+ }
1102
+ samplingPackedValues = null;
1103
+ }
1104
+ };
946
1105
  const encode = (value) => {
947
1106
  if (position$1 > safeEnd)
948
1107
  target = makeRoom(position$1);
@@ -950,6 +1109,43 @@ class Encoder extends Decoder {
950
1109
  var type = typeof value;
951
1110
  var length;
952
1111
  if (type === 'string') {
1112
+ if (packedObjectMap) {
1113
+ let packedPosition = packedObjectMap[value];
1114
+ if (packedPosition >= 0) {
1115
+ if (packedPosition < 16)
1116
+ target[position$1++] = packedPosition + 0xe0; // simple values, defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
1117
+ else {
1118
+ target[position$1++] = 0xc6; // tag 6 defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
1119
+ if (packedPosition & 1)
1120
+ encode((15 - packedPosition) >> 1);
1121
+ else
1122
+ encode((packedPosition - 16) >> 1);
1123
+ }
1124
+ return
1125
+ /* } else if (packedStatus.serializationId != serializationId) {
1126
+ packedStatus.serializationId = serializationId
1127
+ packedStatus.count = 1
1128
+ if (options.sharedPack) {
1129
+ let sharedCount = packedStatus.sharedCount = (packedStatus.sharedCount || 0) + 1
1130
+ if (shareCount > (options.sharedPack.threshold || 5)) {
1131
+ let sharedPosition = packedStatus.position = packedStatus.nextSharedPosition
1132
+ hasSharedUpdate = true
1133
+ if (sharedPosition < 16)
1134
+ target[position++] = sharedPosition + 0xc0
1135
+
1136
+ }
1137
+ }
1138
+ } // else any in-doc incrementation?*/
1139
+ } else if (samplingPackedValues && !options.pack) {
1140
+ let status = samplingPackedValues.get(value);
1141
+ if (status)
1142
+ status.count++;
1143
+ else
1144
+ samplingPackedValues.set(value, {
1145
+ count: 1,
1146
+ });
1147
+ }
1148
+ }
953
1149
  let strLength = value.length;
954
1150
  let headerSize;
955
1151
  // first we estimate the header size, so we can write to the correct location
@@ -1059,7 +1255,7 @@ class Encoder extends Decoder {
1059
1255
  targetView.setFloat32(position$1, value);
1060
1256
  let xShifted;
1061
1257
  if (useFloat32 < 4 ||
1062
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1258
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1063
1259
  ((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
1064
1260
  position$1 += 4;
1065
1261
  return
@@ -1105,6 +1301,12 @@ class Encoder extends Decoder {
1105
1301
  encode(value[i]);
1106
1302
  }
1107
1303
  } else if (constructor === Map) {
1304
+ if (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {
1305
+ // use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way
1306
+ target[position$1++] = 0xd9;
1307
+ target[position$1++] = 1;
1308
+ target[position$1++] = 3;
1309
+ }
1108
1310
  length = value.size;
1109
1311
  if (length < 0x18) {
1110
1312
  target[position$1++] = 0xa0 | length;
@@ -1182,10 +1384,9 @@ class Encoder extends Decoder {
1182
1384
  }
1183
1385
  position$1 += 8;
1184
1386
  } else if (type === 'undefined') {
1185
- //target[position++] = 0xc1 // this is the "never-used" byte
1186
1387
  target[position$1++] = 0xf7;
1187
1388
  } else {
1188
- throw new Error('Unknown type ' + type)
1389
+ throw new Error('Unknown type: ' + type)
1189
1390
  }
1190
1391
  };
1191
1392
 
@@ -1274,7 +1475,7 @@ class Encoder extends Decoder {
1274
1475
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1275
1476
  let newTransitions = 0;
1276
1477
  let length = keys.length;
1277
- for (let i =0; i < length; i++) {
1478
+ for (let i = 0; i < length; i++) {
1278
1479
  let key = keys[i];
1279
1480
  nextTransition = transition[key];
1280
1481
  if (!nextTransition) {
@@ -1284,7 +1485,7 @@ class Encoder extends Decoder {
1284
1485
  transition = nextTransition;
1285
1486
  }
1286
1487
  let recordId = transition[RECORD_SYMBOL];
1287
- if (recordId) {
1488
+ if (recordId !== undefined) {
1288
1489
  target[position$1++] = 0xd9; // tag two byte
1289
1490
  target[position$1++] = RECORD_STARTING_ID_PREFIX;
1290
1491
  target[position$1++] = recordId;
@@ -1311,12 +1512,9 @@ class Encoder extends Decoder {
1311
1512
  transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1312
1513
  // record the removal of the id, we can maintain our shared structure
1313
1514
  if (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)
1314
- recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1515
+ recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
1315
1516
  recordIdsToRemove.push(transition);
1316
- if (length < 0x16)
1317
- target[position$1++] = 0x82 + length; // array header, length of values + 2
1318
- else
1319
- writeArrayHeader(length + 2);
1517
+ writeArrayHeader(length + 2);
1320
1518
  encode(keys);
1321
1519
  target[position$1++] = 0x19; // uint16
1322
1520
  target[position$1++] = RECORD_STARTING_ID_PREFIX;
@@ -1366,7 +1564,9 @@ class Encoder extends Decoder {
1366
1564
  }
1367
1565
 
1368
1566
  function writeArrayHeader(length) {
1369
- if (length < 0x100) {
1567
+ if (length < 0x18)
1568
+ target[position$1++] = 0x80 | length;
1569
+ else if (length < 0x100) {
1370
1570
  target[position$1++] = 0x98;
1371
1571
  target[position$1++] = length;
1372
1572
  } else if (length < 0x10000) {
@@ -1380,6 +1580,56 @@ function writeArrayHeader(length) {
1380
1580
  }
1381
1581
  }
1382
1582
 
1583
+ function findRepetitiveStrings(value, packedValues) {
1584
+ switch(typeof value) {
1585
+ case 'string':
1586
+ if (value.length > 3) {
1587
+ if (packedValues.objectMap[value] > -1 || packedValues.values.length >= packedValues.maxValues)
1588
+ return
1589
+ let packedStatus = packedValues.get(value);
1590
+ if (packedStatus) {
1591
+ if (++packedStatus.count == 2) {
1592
+ packedValues.values.push(value);
1593
+ }
1594
+ } else {
1595
+ packedValues.set(value, {
1596
+ count: 1,
1597
+ });
1598
+ if (packedValues.samplingPackedValues) {
1599
+ let status = packedValues.samplingPackedValues.get(value);
1600
+ if (status)
1601
+ status.count++;
1602
+ else
1603
+ packedValues.samplingPackedValues.set(value, {
1604
+ count: 1,
1605
+ });
1606
+ }
1607
+ }
1608
+ }
1609
+ break
1610
+ case 'object':
1611
+ if (value) {
1612
+ if (value instanceof Array) {
1613
+ for (let i = 0, l = value.length; i < l; i++) {
1614
+ findRepetitiveStrings(value[i], packedValues);
1615
+ }
1616
+
1617
+ } else {
1618
+ let includeKeys = !packedValues.encoder.useRecords;
1619
+ for (var key in value) {
1620
+ if (value.hasOwnProperty(key)) {
1621
+ if (includeKeys)
1622
+ findRepetitiveStrings(key, packedValues);
1623
+ findRepetitiveStrings(value[key], packedValues);
1624
+ }
1625
+ }
1626
+ }
1627
+ }
1628
+ break
1629
+ case 'function': console.log(value);
1630
+ }
1631
+ }
1632
+
1383
1633
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
1384
1634
  Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array, BigUint64Array, Int8Array, Int16Array, Int32Array, BigInt64Array,
1385
1635
  Float32Array, Float64Array];
@@ -1451,7 +1701,9 @@ function typedArrayEncoder(tag) {
1451
1701
  }
1452
1702
  function writeBuffer(buffer, makeRoom) {
1453
1703
  let length = buffer.byteLength;
1454
- if (length < 0x100) {
1704
+ if (length < 0x18) {
1705
+ target[position$1++] = 0x40 + length;
1706
+ } else if (length < 0x100) {
1455
1707
  target[position$1++] = 0x58;
1456
1708
  target[position$1++] = length;
1457
1709
  } else if (length < 0x10000) {
@@ -1506,24 +1758,21 @@ function addExtension$1(extension) {
1506
1758
  }
1507
1759
  let defaultEncoder = new Encoder({ useRecords: false });
1508
1760
  const encode = defaultEncoder.encode;
1509
- const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1761
+ const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1762
+ const REUSE_BUFFER_MODE = 1000;
1510
1763
 
1511
1764
  class EncoderStream extends stream.Transform {
1512
1765
  constructor(options) {
1513
1766
  if (!options)
1514
1767
  options = {};
1768
+ options.writableObjectMode = true;
1515
1769
  super(options);
1516
1770
  options.sequential = true;
1517
- this.encoder = new Encoder(options);
1771
+ this.encoder = options.encoder || new Encoder(options);
1518
1772
  }
1519
- write(value) {
1773
+ _transform(value, encoding, callback) {
1520
1774
  this.push(this.encoder.encode(value));
1521
- }
1522
-
1523
- end(value) {
1524
- if (value != null)
1525
- this.push(this.encoder.encode(value));
1526
- this.push(null);
1775
+ callback();
1527
1776
  }
1528
1777
  }
1529
1778
 
@@ -1534,33 +1783,118 @@ class DecoderStream extends stream.Transform {
1534
1783
  options.objectMode = true;
1535
1784
  super(options);
1536
1785
  options.structures = [];
1537
- this.decoder = new Decoder(options);
1786
+ this.decoder = options.decoder || new Decoder(options);
1538
1787
  }
1539
1788
  _transform(chunk, encoding, callback) {
1540
1789
  if (this.incompleteBuffer) {
1541
1790
  chunk = Buffer.concat([this.incompleteBuffer, chunk]);
1542
1791
  this.incompleteBuffer = null;
1543
1792
  }
1544
- let position = 0;
1545
- let size = chunk.length;
1793
+ let values;
1546
1794
  try {
1547
- this.push(this.decoder.decode(chunk, size, true));
1548
- position = getPosition();
1549
- while (position < size) {
1550
- let value = read();
1551
- this.push(value);
1552
- position = getPosition();
1553
- }
1795
+ values = this.decoder.decodeMultiple(chunk);
1554
1796
  } catch(error) {
1555
- if (error.incomplete)
1556
- this.incompleteBuffer = chunk.slice(position);
1797
+ if (error.incomplete) {
1798
+ this.incompleteBuffer = chunk.slice(error.lastPosition);
1799
+ values = error.values;
1800
+ }
1557
1801
  else
1558
1802
  throw error
1559
1803
  } finally {
1560
- clearSource();
1804
+ for (let value of values || []) {
1805
+ if (value === null)
1806
+ value = this.getNullValue();
1807
+ this.push(value);
1808
+ }
1561
1809
  }
1562
1810
  if (callback) callback();
1563
1811
  }
1812
+ getNullValue() {
1813
+ return Symbol.for(null)
1814
+ }
1815
+ }
1816
+
1817
+ /**
1818
+ * Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
1819
+ * If the argument is only Async Iterable, the return value will be an Async Iterable.
1820
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
1821
+ * @param {options} [options] - cbor-x Encoder options
1822
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator>}
1823
+ */
1824
+ function encodeIter (objectIterator, options = {}) {
1825
+ if (!objectIterator || typeof objectIterator !== 'object') {
1826
+ throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
1827
+ } else if (typeof objectIterator[Symbol.iterator] === 'function') {
1828
+ return encodeIterSync(objectIterator, options)
1829
+ } else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
1830
+ return encodeIterAsync(objectIterator, options)
1831
+ } else {
1832
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
1833
+ }
1834
+ }
1835
+
1836
+ function * encodeIterSync (objectIterator, options) {
1837
+ const encoder = new Encoder(options);
1838
+ for (const value of objectIterator) {
1839
+ yield encoder.encode(value);
1840
+ }
1841
+ }
1842
+
1843
+ async function * encodeIterAsync (objectIterator, options) {
1844
+ const encoder = new Encoder(options);
1845
+ for await (const value of objectIterator) {
1846
+ yield encoder.encode(value);
1847
+ }
1848
+ }
1849
+
1850
+ /**
1851
+ * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
1852
+ * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
1853
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
1854
+ * @param {object} [options] - Decoder options
1855
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator}
1856
+ */
1857
+ function decodeIter (bufferIterator, options = {}) {
1858
+ if (!bufferIterator || typeof bufferIterator !== 'object') {
1859
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
1860
+ }
1861
+
1862
+ const decoder = new Decoder(options);
1863
+ let incomplete;
1864
+ const parser = (chunk) => {
1865
+ let yields;
1866
+ // if there's incomplete data from previous chunk, concatinate and try again
1867
+ if (incomplete) {
1868
+ chunk = Buffer.concat([incomplete, chunk]);
1869
+ incomplete = undefined;
1870
+ }
1871
+
1872
+ try {
1873
+ yields = decoder.decodeMultiple(chunk);
1874
+ } catch (err) {
1875
+ if (err.incomplete) {
1876
+ incomplete = chunk.slice(err.lastPosition);
1877
+ yields = err.values;
1878
+ } else {
1879
+ throw err
1880
+ }
1881
+ }
1882
+ return yields
1883
+ };
1884
+
1885
+ if (typeof bufferIterator[Symbol.iterator] === 'function') {
1886
+ return (function * iter () {
1887
+ for (const value of bufferIterator) {
1888
+ yield * parser(value);
1889
+ }
1890
+ })()
1891
+ } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
1892
+ return (async function * iter () {
1893
+ for await (const value of bufferIterator) {
1894
+ yield * parser(value);
1895
+ }
1896
+ })()
1897
+ }
1564
1898
  }
1565
1899
 
1566
1900
  const useRecords = false;
@@ -1591,10 +1925,15 @@ exports.Encoder = Encoder;
1591
1925
  exports.EncoderStream = EncoderStream;
1592
1926
  exports.FLOAT32_OPTIONS = FLOAT32_OPTIONS;
1593
1927
  exports.NEVER = NEVER;
1928
+ exports.REUSE_BUFFER_MODE = REUSE_BUFFER_MODE;
1594
1929
  exports.Tag = Tag;
1595
1930
  exports.addExtension = addExtension$1;
1931
+ exports.clearSource = clearSource;
1596
1932
  exports.decode = decode;
1933
+ exports.decodeIter = decodeIter;
1597
1934
  exports.decodeMultiple = decodeMultiple;
1598
1935
  exports.encode = encode;
1936
+ exports.encodeIter = encodeIter;
1599
1937
  exports.mapsAsObjects = mapsAsObjects;
1938
+ exports.roundFloat32 = roundFloat32;
1600
1939
  exports.useRecords = useRecords;