msgpackr 1.5.1 → 1.5.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/test.js CHANGED
@@ -684,6 +684,14 @@
684
684
  var deserialized = packr.unpack(serialized);
685
685
  assert.deepEqual(deserialized, data);
686
686
  });
687
+ test('pack/unpack sample data with bundled strings', function(){
688
+ var data = sampleData;
689
+ let structures = [];
690
+ let packr = new Packr({ structures, bundleStrings: true });
691
+ var serialized = packr.pack(data);
692
+ var deserialized = packr.unpack(serialized);
693
+ assert.deepEqual(deserialized, data);
694
+ });
687
695
  if (typeof Buffer != 'undefined')
688
696
  test('replace data', function(){
689
697
  var data1 = {
@@ -1010,16 +1018,19 @@
1010
1018
  var data = {
1011
1019
  map: map,
1012
1020
  date: new Date(1532219539011),
1021
+ invalidDate: new Date('invalid')
1013
1022
  };
1014
1023
  let packr = new Packr({
1015
1024
  mapsAsObjects: true,
1016
1025
  useTimestamp32: true,
1026
+ onInvalidDate: () => 'Custom invalid date'
1017
1027
  });
1018
1028
  var serialized = packr.pack(data);
1019
1029
  var deserialized = packr.unpack(serialized);
1020
1030
  assert.equal(deserialized.map[4], 'four');
1021
1031
  assert.equal(deserialized.map.three, 3);
1022
1032
  assert.equal(deserialized.date.getTime(), 1532219539000);
1033
+ assert.equal(deserialized.invalidDate, 'Custom invalid date');
1023
1034
  });
1024
1035
  test('key caching', function() {
1025
1036
  var data = {
@@ -1199,7 +1210,7 @@
1199
1210
  let structures = [];
1200
1211
  var serialized = pack(data);
1201
1212
  console.log('MessagePack size', serialized.length);
1202
- let packr = new Packr({ structures });
1213
+ let packr = new Packr({ structures, bundleStrings: false });
1203
1214
  var serialized = packr.pack(data);
1204
1215
  console.log('msgpackr w/ record ext size', serialized.length);
1205
1216
  for (var i = 0; i < ITERATIONS; i++) {
@@ -1210,7 +1221,7 @@
1210
1221
  var data = sampleData;
1211
1222
  this.timeout(10000);
1212
1223
  let structures = [];
1213
- let packr = new Packr({ structures });
1224
+ let packr = new Packr({ structures, bundleStrings: false });
1214
1225
  let buffer = typeof Buffer != 'undefined' ? Buffer.alloc(0x10000) : new Uint8Array(0x10000);
1215
1226
 
1216
1227
  for (var i = 0; i < ITERATIONS; i++) {
package/pack.js CHANGED
@@ -13,6 +13,8 @@ let target
13
13
  let targetView
14
14
  let position = 0
15
15
  let safeEnd
16
+ let bundledStrings = null
17
+ const hasNonLatin = /[\u0080-\uFFFF]/
16
18
  const RECORD_SYMBOL = Symbol('record-id')
17
19
  export class Packr extends Unpackr {
18
20
  constructor(options) {
@@ -75,6 +77,14 @@ export class Packr extends Unpackr {
75
77
  position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster
76
78
  start = position
77
79
  referenceMap = packr.structuredClone ? new Map() : null
80
+ if (packr.bundleStrings) {
81
+ bundledStrings = ['', '']
82
+ target[position++] = 0xd6
83
+ target[position++] = 0x62 // 'b'
84
+ bundledStrings.position = position - start
85
+ position += 4
86
+ } else
87
+ bundledStrings = null
78
88
  sharedStructures = packr.structures
79
89
  if (sharedStructures) {
80
90
  if (sharedStructures.uninitialized)
@@ -113,6 +123,13 @@ export class Packr extends Unpackr {
113
123
  structures = sharedStructures || []
114
124
  try {
115
125
  pack(value)
126
+ if (bundledStrings) {
127
+ targetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start)
128
+ let writeStrings = bundledStrings
129
+ bundledStrings = null
130
+ pack(writeStrings[0])
131
+ pack(writeStrings[1])
132
+ }
116
133
  packr.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
117
134
  if (referenceMap && referenceMap.idsToInsert) {
118
135
  position += referenceMap.idsToInsert.length * 6
@@ -123,7 +140,7 @@ export class Packr extends Unpackr {
123
140
  referenceMap = null
124
141
  return serialized
125
142
  }
126
- if (encodeOptions === REUSE_BUFFER_MODE) {
143
+ if (encodeOptions & REUSE_BUFFER_MODE) {
127
144
  target.start = start
128
145
  target.end = position
129
146
  return target
@@ -162,6 +179,8 @@ export class Packr extends Unpackr {
162
179
  return returnBuffer
163
180
  }
164
181
  }
182
+ if (encodeOptions & RESET_BUFFER_MODE)
183
+ position = start
165
184
  }
166
185
  }
167
186
  const pack = (value) => {
@@ -172,6 +191,13 @@ export class Packr extends Unpackr {
172
191
  var length
173
192
  if (type === 'string') {
174
193
  let strLength = value.length
194
+ if (bundledStrings && strLength >= 8 && strLength < 0x1000) {
195
+ let twoByte = hasNonLatin.test(value)
196
+ bundledStrings[twoByte ? 0 : 1] += value
197
+ target[position++] = 0xc1
198
+ pack(twoByte ? -strLength : strLength);
199
+ return
200
+ }
175
201
  let headerSize
176
202
  // first we estimate the header size, so we can write to the correct location
177
203
  if (strLength < 0x20) {
@@ -638,8 +664,10 @@ extensions = [{
638
664
  targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0))
639
665
  targetView.setUint32(position + 4, seconds)
640
666
  } else if (isNaN(seconds)) {
641
- if (this.onInvalidDate)
667
+ if (this.onInvalidDate) {
668
+ allocateForWrite(0)
642
669
  return pack(this.onInvalidDate())
670
+ }
643
671
  // Intentionally invalid timestamp
644
672
  let { target, targetView, position} = allocateForWrite(3)
645
673
  target[position++] = 0xd4
@@ -832,4 +860,5 @@ export const Encoder = Packr
832
860
  export { FLOAT32_OPTIONS } from './unpack.js'
833
861
  import { FLOAT32_OPTIONS } from './unpack.js'
834
862
  export const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS
835
- export const REUSE_BUFFER_MODE = 1000
863
+ export const REUSE_BUFFER_MODE = 512
864
+ export const RESET_BUFFER_MODE = 1024
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "msgpackr",
3
3
  "author": "Kris Zyp",
4
- "version": "1.5.1",
4
+ "version": "1.5.2",
5
5
  "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
6
  "license": "MIT",
7
7
  "types": "./index.d.ts",
@@ -49,6 +49,12 @@
49
49
  "default": "./unpack.js"
50
50
  }
51
51
  },
52
+ "files": [
53
+ "/dist",
54
+ "*.md",
55
+ "/*.js",
56
+ "/*.ts"
57
+ ],
52
58
  "optionalDependencies": {
53
59
  "msgpackr-extract": "^1.0.14"
54
60
  },
package/unpack.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface Options {
13
13
  mapsAsObjects?: boolean
14
14
  variableMapSize?: boolean
15
15
  copyBuffers?: boolean
16
+ bundleStrings?: boolean
16
17
  useTimestamp32?: boolean
17
18
  largeBigIntToFloat?: boolean
18
19
  encodeUndefinedAsNil?: boolean
@@ -21,6 +22,7 @@ export interface Options {
21
22
  shouldShareStructure?: (keys: string[]) => boolean
22
23
  getStructures?(): {}[]
23
24
  saveStructures?(structures: {}[]): boolean | void
25
+ onInvalidDate?: () => any
24
26
  }
25
27
  interface Extension {
26
28
  Class: Function
package/unpack.js CHANGED
@@ -15,6 +15,7 @@ var currentStructures
15
15
  var srcString
16
16
  var srcStringStart = 0
17
17
  var srcStringEnd = 0
18
+ var bundledStrings
18
19
  var referenceMap
19
20
  var currentExtensions = []
20
21
  var dataView
@@ -55,6 +56,7 @@ export class Unpackr {
55
56
  srcStringEnd = 0
56
57
  srcString = null
57
58
  strings = EMPTY_ARRAY
59
+ bundledStrings = null
58
60
  src = source
59
61
  // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
60
62
  // technique for getting data from a database where it can be copied into an existing buffer instead of creating
@@ -248,7 +250,15 @@ export function read() {
248
250
  let value
249
251
  switch (token) {
250
252
  case 0xc0: return null
251
- case 0xc1: return C1; // "never-used", return special object to denote that
253
+ case 0xc1:
254
+ if (bundledStrings) {
255
+ value = read() // followed by the length of the string in characters (not bytes!)
256
+ if (value > 0)
257
+ return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
258
+ else
259
+ return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 -= value)
260
+ }
261
+ return C1; // "never-used", return special object to denote that
252
262
  case 0xc2: return false
253
263
  case 0xc3: return true
254
264
  case 0xc4:
@@ -898,6 +908,22 @@ currentExtensions[0x78] = () => {
898
908
  return new RegExp(data[0], data[1])
899
909
  }
900
910
 
911
+ currentExtensions[0x62] = (data) => {
912
+ let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
913
+ let dataPosition = position
914
+ position += dataSize - 4
915
+ bundledStrings = [read(), read()]
916
+ bundledStrings.position0 = 0
917
+ bundledStrings.position1 = 0
918
+ let postBundlePosition = position
919
+ position = dataPosition
920
+ try {
921
+ return read()
922
+ } finally {
923
+ position = postBundlePosition
924
+ }
925
+ }
926
+
901
927
  currentExtensions[0xff] = (data) => {
902
928
  // 32-bit date extension
903
929
  if (data.length == 4)
@@ -925,6 +951,7 @@ function saveState(callback) {
925
951
  let savedSrcString = srcString
926
952
  let savedStrings = strings
927
953
  let savedReferenceMap = referenceMap
954
+ let savedBundledStrings = bundledStrings
928
955
 
929
956
  // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
930
957
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed
@@ -941,6 +968,7 @@ function saveState(callback) {
941
968
  srcString = savedSrcString
942
969
  strings = savedStrings
943
970
  referenceMap = savedReferenceMap
971
+ bundledStrings = savedBundledStrings
944
972
  src = savedSrc
945
973
  sequentialMode = savedSequentialMode
946
974
  currentStructures = savedStructures
@@ -1,23 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "type": "pwa-node",
9
- "request": "launch",
10
- "name": "Run msgpackr tests",
11
- "runtimeArgs": [
12
- "test"
13
- ],
14
- "runtimeExecutable": "npm",
15
- "skipFiles": [
16
- "<node_internals>/**"
17
- ],
18
- "type": "pwa-node",
19
- "console": "internalConsole",
20
- "outputCapture": "std"
21
- }
22
- ]
23
- }
@@ -1,282 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- var PassThrough = require("stream").PassThrough;
4
- var async = require("async");
5
-
6
- let { PackrStream, UnpackrStream } = require("..");
7
- var msgpack = require("msgpack-lite");
8
- var Encoder = require("msgpack-lite/lib/encoder").Encoder;
9
- var Decoder = require("msgpack-lite/lib/decoder").Decoder;
10
- var notepack = require("notepack");
11
-
12
- var pkg = require("../package.json");
13
-
14
- // a sample fluentd message
15
- var data = ["tag", [[1440949922, {"message": "hi there"}]]];
16
- var packed = msgpack.encode(data); // 30 bytes per message
17
- var packsize = packed.length;
18
- var opcount = 1000000;
19
- var joincount = 100;
20
- var packjoin = repeatbuf(packed, joincount); // 3KB per chunk
21
- var limit = 2;
22
-
23
- var blocksToJoin = []
24
- var streamForJoin = new PackrStream();
25
- streamForJoin.on("data", data => blocksToJoin.push(data));
26
- for (var j = 0; j < joincount; j++) {
27
- streamForJoin.write(data);
28
- }
29
- var packjoinWithRecords = Buffer.concat(blocksToJoin)
30
-
31
- var argv = Array.prototype.slice.call(process.argv, 2);
32
-
33
- if (argv[0] === "-v") {
34
- console.warn(pkg.name + " " + pkg.version);
35
- process.exit(0);
36
- }
37
-
38
- if (argv[0] - 0) limit = argv.shift() - 0;
39
-
40
- var list = [
41
- ['new PackrStream().write(obj);', encode5],
42
- ['new UnpackrStream().write(buf);', decode5],
43
- ['stream.write(msgpack.encode(obj));', encode1],
44
- ['stream.write(msgpack.decode(buf));', decode1],
45
- ['stream.write(notepack.encode(obj));', encode4],
46
- ['stream.write(notepack.decode(buf));', decode4],
47
- ['msgpack.Encoder().on("data",ondata).encode(obj);', encode2],
48
- ['msgpack.createDecodeStream().write(buf);', decode3],
49
- ['msgpack.createEncodeStream().write(obj);', encode3],
50
- ['msgpack.Decoder().on("data",ondata).decode(buf);', decode2],
51
- // ['stream.write(Buffer.from(JSON.stringify(obj)));', stringify],
52
- // ['stream.write(JSON.parse(buf));', parse]
53
- ];
54
-
55
- function encode5(callback) {
56
- var stream = new PackrStream();
57
- var cnt = counter(callback);
58
- stream.on("data", cnt.inc);
59
- stream.on("end", cnt.end);
60
- for (var j = 0; j < opcount; j++) {
61
- stream.write(data);
62
- }
63
- stream.end();
64
- }
65
-
66
- function encode1(callback) {
67
- var stream = new PassThrough();
68
- var cnt = counter(callback);
69
- stream.on("data", cnt.buf);
70
- stream.on("end", cnt.end);
71
- for (var j = 0; j < opcount; j++) {
72
- stream.write(msgpack.encode(data));
73
- }
74
- stream.end();
75
- }
76
-
77
- function encode2(callback) {
78
- var stream = new PassThrough();
79
- var cnt = counter(callback);
80
- stream.on("data", cnt.buf);
81
- stream.on("end", cnt.end);
82
- var encoder = Encoder();
83
- encoder.on("data", function(chunk) {
84
- stream.write(chunk);
85
- });
86
- encoder.on("end", function() {
87
- stream.end();
88
- });
89
- for (var j = 0; j < opcount; j++) {
90
- encoder.encode(data);
91
- }
92
- encoder.end();
93
- }
94
-
95
- function encode3(callback) {
96
- var stream = msgpack.createEncodeStream();
97
- var cnt = counter(callback);
98
- stream.on("data", cnt.buf);
99
- stream.on("end", cnt.end);
100
- for (var j = 0; j < opcount; j++) {
101
- stream.write(data);
102
- }
103
- stream.end();
104
- }
105
-
106
- function encode4(callback) {
107
- var stream = new PassThrough();
108
- var cnt = counter(callback);
109
- stream.on("data", cnt.buf);
110
- stream.on("end", cnt.end);
111
- for (var j = 0; j < opcount; j++) {
112
- stream.write(notepack.encode(data));
113
- }
114
- stream.end();
115
- }
116
-
117
- function decode5(callback) {
118
- var stream = new UnpackrStream();
119
- var cnt = counter(callback);
120
- stream.on("data", cnt.inc);
121
- stream.on("end", cnt.end);
122
- for (var j = 0; j < opcount / joincount; j++) {
123
- stream.write(packjoinWithRecords);
124
- }
125
- stream.end();
126
- }
127
-
128
- function decode1(callback) {
129
- var stream = new PassThrough({objectMode: true});
130
- var cnt = counter(callback);
131
- stream.on("data", cnt.inc);
132
- stream.on("end", cnt.end);
133
- for (var j = 0; j < opcount; j++) {
134
- stream.write(msgpack.decode(packed));
135
- }
136
- stream.end();
137
- }
138
-
139
- function decode2(callback) {
140
- var stream = new PassThrough({objectMode: true});
141
- var cnt = counter(callback);
142
- stream.on("data", cnt.inc);
143
- stream.on("end", cnt.end);
144
- var decoder = Decoder();
145
- decoder.on("data", function(chunk) {
146
- stream.write(chunk);
147
- });
148
- decoder.on("end", function() {
149
- stream.end();
150
- });
151
- for (var j = 0; j < opcount / joincount; j++) {
152
- decoder.decode(packjoin);
153
- }
154
- decoder.end();
155
- }
156
-
157
- function decode3(callback) {
158
- var stream = msgpack.createDecodeStream();
159
- var cnt = counter(callback);
160
- stream.on("data", cnt.inc);
161
- stream.on("end", cnt.end);
162
- for (var j = 0; j < opcount / joincount; j++) {
163
- stream.write(packjoin);
164
- }
165
- stream.end();
166
- }
167
-
168
- function decode4(callback) {
169
- var stream = new PassThrough({objectMode: true});
170
- var cnt = counter(callback);
171
- stream.on("data", cnt.inc);
172
- stream.on("end", cnt.end);
173
- for (var j = 0; j < opcount; j++) {
174
- stream.write(notepack.decode(packed));
175
- }
176
- stream.end();
177
- }
178
-
179
- function rpad(str, len, chr) {
180
- if (!chr) chr = " ";
181
- str += "";
182
- while (str.length < len) str += chr;
183
- return str;
184
- }
185
-
186
- function lpad(str, len, chr) {
187
- if (!chr) chr = " ";
188
- str += "";
189
- while (str.length < len) str = chr + str;
190
- return str;
191
- }
192
-
193
- function repeatbuf(buf, cnt) {
194
- var array = [];
195
- for (var i = 0; i < cnt; i++) {
196
- array.push(buf);
197
- }
198
- return Buffer.concat(array);
199
- }
200
-
201
- function counter(callback) {
202
- var cnt = 0;
203
- return {buf: b, inc: i, end: e};
204
-
205
- function b(buf) {
206
- cnt += buf.length / packsize;
207
- }
208
-
209
- function i() {
210
- cnt++;
211
- }
212
-
213
- function e() {
214
- cnt = Math.round(cnt);
215
- callback(null, cnt);
216
- }
217
- }
218
-
219
- function run() {
220
- // task filter
221
- if (argv.length) {
222
- list = list.filter(function(pair) {
223
- var name = pair[0];
224
- var match = argv.filter(function(grep) {
225
- return (name.indexOf(grep) > -1);
226
- });
227
- return match.length;
228
- });
229
- }
230
-
231
- // run tasks repeatedly
232
- var tasks = [];
233
- for (var i = 0; i < limit; i++) {
234
- tasks.push(oneset);
235
- }
236
- async.series(tasks, end);
237
-
238
- // run a series of tasks
239
- function oneset(callback) {
240
- async.eachSeries(list, bench, callback);
241
- }
242
-
243
- // run a single benchmark
244
- function bench(pair, callback) {
245
- process.stdout.write(".");
246
- var func = pair[1];
247
- var start = new Date() - 0;
248
- func(function(err, cnt) {
249
- var end = new Date() - 0;
250
- var array = pair[2] || (pair[2] = []);
251
- array.push(end - start);
252
- pair[3] = cnt;
253
- setTimeout(callback, 100);
254
- });
255
- }
256
-
257
- // show result
258
- function end() {
259
- var title = "operation (" + opcount + " x " + limit + ")";
260
- process.stdout.write("\n");
261
-
262
- // table header
263
- var COL1 = 48;
264
- console.log(rpad(title, COL1), "|", " op ", "|", " ms ", "|", " op/s ");
265
- console.log(rpad("", COL1, "-"), "|", "------:", "|", "----:", "|", "-----:");
266
-
267
- // table body
268
- list.forEach(function(pair) {
269
- var name = pair[0];
270
- var op = pair[3];
271
- var array = pair[2];
272
- array = array.sort(function(a, b) {
273
- return a > b;
274
- });
275
- var fastest = array[0];
276
- var score = Math.floor(opcount / fastest * 1000);
277
- console.log(rpad(name, COL1), "|", lpad(op, 7), "|", lpad(fastest, 5), "|", lpad(score, 6));
278
- });
279
- }
280
- }
281
-
282
- run();