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/.vscode/launch.json +22 -0
- package/README.md +54 -18
- package/SECURITY.md +11 -0
- package/{unpack.d.ts → decode.d.ts} +12 -11
- package/decode.js +134 -33
- package/dist/index.js +400 -57
- package/dist/index.min.js +83 -53
- package/dist/node.cjs +419 -80
- package/dist/test.js +82 -1
- package/encode.d.ts +6 -0
- package/encode.js +181 -24
- package/index.d.ts +7 -6
- package/index.js +2 -2
- package/iterators.js +85 -0
- package/{node.js → node-index.js} +4 -3
- package/package.json +17 -17
- package/rollup.config.js +2 -2
- package/stream.js +20 -22
- package/tests/benchmark.cjs +48 -8
- package/tests/test-compatibility.cjs +1 -0
- package/tests/test-incomplete.js +41 -0
- package/tests/test-node-iterators.js +72 -0
- package/tests/test-node-stream.js +11 -1
- package/tests/test.js +82 -2
- package/pack.d.ts +0 -9
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
let
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
122
|
-
|
|
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
|
-
|
|
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
|
|
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 >
|
|
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
|
|
884
|
-
let key = keys[
|
|
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
|
-
|
|
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] =
|
|
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 =
|
|
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
|
-
|
|
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] =
|
|
1515
|
+
recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
|
|
1315
1516
|
recordIdsToRemove.push(transition);
|
|
1316
|
-
|
|
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 <
|
|
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 <
|
|
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
|
-
|
|
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
|
|
1545
|
-
let size = chunk.length;
|
|
1793
|
+
let values;
|
|
1546
1794
|
try {
|
|
1547
|
-
this.
|
|
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(
|
|
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
|
-
|
|
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;
|