msgpackr 1.6.2 → 1.7.0-alpha3

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT, REUSE_BUFFER_MODE } from './pack.js'
2
- export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32, isNativeAccelerationEnabled } from './unpack.js'
3
- export { decodeIter, encodeIter } from './iterators.js'
4
- export const useRecords = false
5
- export const mapsAsObjects = true
1
+ export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT, REUSE_BUFFER_MODE } from './pack.js'
2
+ export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32, isNativeAccelerationEnabled } from './unpack.js'
3
+ export { decodeIter, encodeIter } from './iterators.js'
4
+ export const useRecords = false
5
+ export const mapsAsObjects = true
package/iterators.js CHANGED
@@ -1,87 +1,87 @@
1
- import { Packr } from './pack.js'
2
- import { Unpackr } from './unpack.js'
3
-
4
- /**
5
- * Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
6
- * If the argument is only Async Iterable, the return value will be an Async Iterable.
7
- * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
8
- * @param {options} [options] - msgpackr pack options
9
- * @returns {IterableIterator|Promise.<AsyncIterableIterator>}
10
- */
11
- export function packIter (objectIterator, options = {}) {
12
- if (!objectIterator || typeof objectIterator !== 'object') {
13
- throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
14
- } else if (typeof objectIterator[Symbol.iterator] === 'function') {
15
- return packIterSync(objectIterator, options)
16
- } else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
17
- return packIterAsync(objectIterator, options)
18
- } else {
19
- throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
20
- }
21
- }
22
-
23
- function * packIterSync (objectIterator, options) {
24
- const packr = new Packr(options)
25
- for (const value of objectIterator) {
26
- yield packr.pack(value)
27
- }
28
- }
29
-
30
- async function * packIterAsync (objectIterator, options) {
31
- const packr = new Packr(options)
32
- for await (const value of objectIterator) {
33
- yield packr.pack(value)
34
- }
35
- }
36
-
37
- /**
38
- * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
39
- * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
40
- * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
41
- * @param {object} [options] - unpackr options
42
- * @returns {IterableIterator|Promise.<AsyncIterableIterator}
43
- */
44
- export function unpackIter (bufferIterator, options = {}) {
45
- if (!bufferIterator || typeof bufferIterator !== 'object') {
46
- throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
47
- }
48
-
49
- const unpackr = new Unpackr(options)
50
- let incomplete
51
- const parser = (chunk) => {
52
- let yields
53
- // if there's incomplete data from previous chunk, concatinate and try again
54
- if (incomplete) {
55
- chunk = Buffer.concat([incomplete, chunk])
56
- incomplete = undefined
57
- }
58
-
59
- try {
60
- yields = unpackr.unpackMultiple(chunk)
61
- } catch (err) {
62
- if (err.incomplete) {
63
- incomplete = chunk.slice(err.lastPosition)
64
- yields = err.values
65
- } else {
66
- throw err
67
- }
68
- }
69
- return yields
70
- }
71
-
72
- if (typeof bufferIterator[Symbol.iterator] === 'function') {
73
- return (function * iter () {
74
- for (const value of bufferIterator) {
75
- yield * parser(value)
76
- }
77
- })()
78
- } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
79
- return (async function * iter () {
80
- for await (const value of bufferIterator) {
81
- yield * parser(value)
82
- }
83
- })()
84
- }
85
- }
86
- export const decodeIter = unpackIter
1
+ import { Packr } from './pack.js'
2
+ import { Unpackr } from './unpack.js'
3
+
4
+ /**
5
+ * Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
6
+ * If the argument is only Async Iterable, the return value will be an Async Iterable.
7
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
8
+ * @param {options} [options] - msgpackr pack options
9
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator>}
10
+ */
11
+ export function packIter (objectIterator, options = {}) {
12
+ if (!objectIterator || typeof objectIterator !== 'object') {
13
+ throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
14
+ } else if (typeof objectIterator[Symbol.iterator] === 'function') {
15
+ return packIterSync(objectIterator, options)
16
+ } else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
17
+ return packIterAsync(objectIterator, options)
18
+ } else {
19
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
20
+ }
21
+ }
22
+
23
+ function * packIterSync (objectIterator, options) {
24
+ const packr = new Packr(options)
25
+ for (const value of objectIterator) {
26
+ yield packr.pack(value)
27
+ }
28
+ }
29
+
30
+ async function * packIterAsync (objectIterator, options) {
31
+ const packr = new Packr(options)
32
+ for await (const value of objectIterator) {
33
+ yield packr.pack(value)
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
39
+ * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
40
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
41
+ * @param {object} [options] - unpackr options
42
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator}
43
+ */
44
+ export function unpackIter (bufferIterator, options = {}) {
45
+ if (!bufferIterator || typeof bufferIterator !== 'object') {
46
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
47
+ }
48
+
49
+ const unpackr = new Unpackr(options)
50
+ let incomplete
51
+ const parser = (chunk) => {
52
+ let yields
53
+ // if there's incomplete data from previous chunk, concatinate and try again
54
+ if (incomplete) {
55
+ chunk = Buffer.concat([incomplete, chunk])
56
+ incomplete = undefined
57
+ }
58
+
59
+ try {
60
+ yields = unpackr.unpackMultiple(chunk)
61
+ } catch (err) {
62
+ if (err.incomplete) {
63
+ incomplete = chunk.slice(err.lastPosition)
64
+ yields = err.values
65
+ } else {
66
+ throw err
67
+ }
68
+ }
69
+ return yields
70
+ }
71
+
72
+ if (typeof bufferIterator[Symbol.iterator] === 'function') {
73
+ return (function * iter () {
74
+ for (const value of bufferIterator) {
75
+ yield * parser(value)
76
+ }
77
+ })()
78
+ } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
79
+ return (async function * iter () {
80
+ for await (const value of bufferIterator) {
81
+ yield * parser(value)
82
+ }
83
+ })()
84
+ }
85
+ }
86
+ export const decodeIter = unpackIter
87
87
  export const encodeIter = packIter
package/node-index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './pack.js'
2
2
  export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32, isNativeAccelerationEnabled } from './unpack.js'
3
+ import './struct.js'
3
4
  export { PackrStream, UnpackrStream, PackrStream as EncoderStream, UnpackrStream as DecoderStream } from './stream.js'
4
5
  export { decodeIter, encodeIter } from './iterators.js'
5
6
  export const useRecords = false
package/pack.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { Unpackr } from './unpack'
2
- export { addExtension, FLOAT32_OPTIONS } from './unpack'
3
- export class Packr extends Unpackr {
4
- pack(value: any): Buffer
5
- encode(value: any): Buffer
6
- }
7
- export class Encoder extends Packr {}
8
- export function pack(value: any): Buffer
9
- export function encode(value: any): Buffer
1
+ import { Unpackr } from './unpack'
2
+ export { addExtension, FLOAT32_OPTIONS } from './unpack'
3
+ export class Packr extends Unpackr {
4
+ pack(value: any): Buffer
5
+ encode(value: any): Buffer
6
+ }
7
+ export class Encoder extends Packr {}
8
+ export function pack(value: any): Buffer
9
+ export function encode(value: any): Buffer
package/pack.js CHANGED
@@ -15,9 +15,10 @@ let targetView
15
15
  let position = 0
16
16
  let safeEnd
17
17
  let bundledStrings = null
18
+ let writeStructSlots, prepareStructures
18
19
  const MAX_BUNDLE_SIZE = 0xf000
19
20
  const hasNonLatin = /[\u0080-\uFFFF]/
20
- const RECORD_SYMBOL = Symbol('record-id')
21
+ export const RECORD_SYMBOL = Symbol('record-id')
21
22
  export class Packr extends Unpackr {
22
23
  constructor(options) {
23
24
  super(options)
@@ -27,7 +28,6 @@ export class Packr extends Unpackr {
27
28
  let hasSharedUpdate
28
29
  let structures
29
30
  let referenceMap
30
- let lastSharedStructuresLength = 0
31
31
  let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position) {
32
32
  return target.utf8Write(string, position, 0xffffffff)
33
33
  } : (textEncoder && textEncoder.encodeInto) ?
@@ -67,14 +67,14 @@ export class Packr extends Unpackr {
67
67
  this.pack = this.encode = function(value, encodeOptions) {
68
68
  if (!target) {
69
69
  target = new ByteArrayAllocate(8192)
70
- targetView = new DataView(target.buffer, 0, 8192)
70
+ targetView = target.dataView = new DataView(target.buffer, 0, 8192)
71
71
  position = 0
72
72
  }
73
73
  safeEnd = target.length - 10
74
74
  if (safeEnd - position < 0x800) {
75
75
  // don't start too close to the end,
76
76
  target = new ByteArrayAllocate(target.length)
77
- targetView = new DataView(target.buffer, 0, target.length)
77
+ targetView = target.dataView = new DataView(target.buffer, 0, target.length)
78
78
  safeEnd = target.length - 10
79
79
  position = 0
80
80
  } else
@@ -113,7 +113,7 @@ export class Packr extends Unpackr {
113
113
  }
114
114
  transition[RECORD_SYMBOL] = i + 0x40
115
115
  }
116
- lastSharedStructuresLength = sharedLength
116
+ this.lastNamedStructuresLength = sharedLength
117
117
  }
118
118
  if (!isSequential) {
119
119
  structures.nextId = sharedLength + 0x40
@@ -122,7 +122,10 @@ export class Packr extends Unpackr {
122
122
  if (hasSharedUpdate)
123
123
  hasSharedUpdate = false
124
124
  try {
125
- pack(value)
125
+ if (packr.randomAccessStructure && value.constructor && value.constructor === Object)
126
+ writeStruct(value);
127
+ else
128
+ pack(value)
126
129
  if (bundledStrings) {
127
130
  writeBundles(start, pack)
128
131
  }
@@ -165,12 +168,13 @@ export class Packr extends Unpackr {
165
168
  if (hasSharedUpdate && packr.saveStructures) {
166
169
  // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
167
170
  let returnBuffer = target.subarray(start, position)
168
- if (packr.saveStructures(structures, lastSharedStructuresLength) === false) {
171
+ let newSharedData = prepareStructures ? prepareStructures(structures, packr) : structures;
172
+ if (packr.saveStructures(newSharedData, newSharedData.isCompatible || packr.lastNamedStructuresLength || 0) === false) {
169
173
  // get updated structures and try again if the update failed
170
174
  packr._mergeStructures(packr.getStructures())
171
175
  return packr.pack(value)
172
176
  }
173
- lastSharedStructuresLength = sharedLength
177
+ packr.lastNamedStructuresLength = sharedLength
174
178
  return returnBuffer
175
179
  }
176
180
  }
@@ -288,7 +292,7 @@ export class Packr extends Unpackr {
288
292
  } else if (type === 'number') {
289
293
  if (value >>> 0 === value) {// positive integer, 32-bit or less
290
294
  // positive uint
291
- if (value < 0x40 || (value < 0x80 && this.useRecords === false)) {
295
+ if (value < 0x20 || (value < 0x80 && this.useRecords === false) || (value < 0x40 && !this.randomAccessStructure)) {
292
296
  target[position++] = value
293
297
  } else if (value < 0x100) {
294
298
  target[position++] = 0xcc
@@ -596,7 +600,7 @@ export class Packr extends Unpackr {
596
600
  } else // faster handling for smaller buffers
597
601
  newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12
598
602
  let newBuffer = new ByteArrayAllocate(newSize)
599
- targetView = new DataView(newBuffer.buffer, 0, newSize)
603
+ targetView = newBuffer.dataView = new DataView(newBuffer.buffer, 0, newSize)
600
604
  end = Math.min(end, target.length)
601
605
  if (target.copy)
602
606
  target.copy(newBuffer, 0, start, end)
@@ -687,6 +691,23 @@ export class Packr extends Unpackr {
687
691
  target[insertionOffset + start] = keysTarget[0]
688
692
  }
689
693
  }
694
+ const writeStruct = (object, safePrototype) => {
695
+ let newPosition = writeStructSlots(object, target, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
696
+ if (notifySharedUpdate)
697
+ hasSharedUpdate = true;
698
+ position = newPosition;
699
+ if (start > 0) {
700
+ pack(value);
701
+ if (start == 0)
702
+ return { position, targetView, target }; // indicate the buffer was re-allocated
703
+ } else
704
+ pack(value);
705
+ return position;
706
+ }, this);
707
+ if (newPosition === 0) // bail and go to a msgpack object
708
+ return writeObject(object, true);
709
+ position = newPosition;
710
+ }
690
711
  }
691
712
  useBuffer(buffer) {
692
713
  // this means we are finished using our own buffer and we can write over it safely
@@ -697,6 +718,8 @@ export class Packr extends Unpackr {
697
718
  clearSharedData() {
698
719
  if (this.structures)
699
720
  this.structures = []
721
+ if (this.typedStructs)
722
+ this.typedStructs = []
700
723
  }
701
724
  }
702
725
 
@@ -923,6 +946,10 @@ export function addExtension(extension) {
923
946
  }
924
947
  unpackAddExtension(extension)
925
948
  }
949
+ export function setWriteStructSlots(writeSlots, makeStructures) {
950
+ writeStructSlots = writeSlots;
951
+ prepareStructures = makeStructures;
952
+ }
926
953
 
927
954
  let defaultPackr = new Packr({ useRecords: false })
928
955
  export const pack = defaultPackr.pack
package/package.json CHANGED
@@ -1,83 +1,83 @@
1
- {
2
- "name": "msgpackr",
3
- "author": "Kris Zyp",
4
- "version": "1.6.2",
5
- "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
- "license": "MIT",
7
- "types": "./index.d.ts",
8
- "main": "./dist/node.cjs",
9
- "module": "./index.js",
10
- "keywords": [
11
- "MessagePack",
12
- "msgpack",
13
- "performance",
14
- "structured",
15
- "clone"
16
- ],
17
- "repository": {
18
- "type": "git",
19
- "url": "http://github.com/kriszyp/msgpackr"
20
- },
21
- "scripts": {
22
- "benchmark": "node ./tests/benchmark.cjs",
23
- "build": "rollup -c",
24
- "dry-run": "npm publish --dry-run",
25
- "prepare": "npm run build",
26
- "test": "mocha tests/test**.*js -u tdd --experimental-json-modules"
27
- },
28
- "type": "module",
29
- "exports": {
30
- ".": {
31
- "node": {
32
- "require": "./dist/node.cjs",
33
- "import": "./node-index.js"
34
- },
35
- "bun": {
36
- "require": "./dist/node.cjs",
37
- "import": "./node-index.js"
38
- },
39
- "default": "./index.js"
40
- },
41
- "./pack": {
42
- "node": {
43
- "import": "./index.js",
44
- "require": "./dist/node.cjs"
45
- },
46
- "bun": {
47
- "import": "./index.js",
48
- "require": "./dist/node.cjs"
49
- },
50
- "default": "./pack.js"
51
- },
52
- "./unpack": {
53
- "node": {
54
- "import": "./index.js",
55
- "require": "./dist/node.cjs"
56
- },
57
- "bun": {
58
- "import": "./index.js",
59
- "require": "./dist/node.cjs"
60
- },
61
- "default": "./unpack.js"
62
- }
63
- },
64
- "files": [
65
- "/dist",
66
- "*.md",
67
- "/*.js",
68
- "/*.ts"
69
- ],
70
- "optionalDependencies": {
71
- "msgpackr-extract": "^2.0.2"
72
- },
73
- "devDependencies": {
74
- "@rollup/plugin-json": "^4.1.0",
75
- "@types/node": "latest",
76
- "async": "^3",
77
- "chai": "^4.3.4",
78
- "esm": "^3.2.25",
79
- "mocha": "^8.1.3",
80
- "rollup": "^1.20.3",
81
- "rollup-plugin-babel-minify": "^9.0.0"
82
- }
83
- }
1
+ {
2
+ "name": "msgpackr",
3
+ "author": "Kris Zyp",
4
+ "version": "1.7.0-alpha3",
5
+ "description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
6
+ "license": "MIT",
7
+ "types": "./index.d.ts",
8
+ "main": "./dist/node.cjs",
9
+ "module": "./index.js",
10
+ "keywords": [
11
+ "MessagePack",
12
+ "msgpack",
13
+ "performance",
14
+ "structured",
15
+ "clone"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "http://github.com/kriszyp/msgpackr"
20
+ },
21
+ "scripts": {
22
+ "benchmark": "node ./tests/benchmark.cjs",
23
+ "build": "rollup -c",
24
+ "dry-run": "npm publish --dry-run",
25
+ "prepare": "npm run build",
26
+ "test": "mocha tests/test**.*js -u tdd --experimental-json-modules"
27
+ },
28
+ "type": "module",
29
+ "exports": {
30
+ ".": {
31
+ "node": {
32
+ "require": "./dist/node.cjs",
33
+ "import": "./node-index.js"
34
+ },
35
+ "bun": {
36
+ "require": "./dist/node.cjs",
37
+ "import": "./node-index.js"
38
+ },
39
+ "default": "./index.js"
40
+ },
41
+ "./pack": {
42
+ "node": {
43
+ "import": "./index.js",
44
+ "require": "./dist/node.cjs"
45
+ },
46
+ "bun": {
47
+ "import": "./index.js",
48
+ "require": "./dist/node.cjs"
49
+ },
50
+ "default": "./pack.js"
51
+ },
52
+ "./unpack": {
53
+ "node": {
54
+ "import": "./index.js",
55
+ "require": "./dist/node.cjs"
56
+ },
57
+ "bun": {
58
+ "import": "./index.js",
59
+ "require": "./dist/node.cjs"
60
+ },
61
+ "default": "./unpack.js"
62
+ }
63
+ },
64
+ "files": [
65
+ "/dist",
66
+ "*.md",
67
+ "/*.js",
68
+ "/*.ts"
69
+ ],
70
+ "optionalDependencies": {
71
+ "msgpackr-extract": "^2.1.1"
72
+ },
73
+ "devDependencies": {
74
+ "@rollup/plugin-json": "^4.1.0",
75
+ "@types/node": "latest",
76
+ "async": "^3",
77
+ "chai": "^4.3.4",
78
+ "esm": "^3.2.25",
79
+ "mocha": "^8.1.3",
80
+ "rollup": "^1.20.3",
81
+ "rollup-plugin-babel-minify": "^9.0.0"
82
+ }
83
+ }
package/rollup.config.js CHANGED
@@ -1,45 +1,49 @@
1
- import minify from "rollup-plugin-babel-minify";
2
- import json from "@rollup/plugin-json";
3
-
4
- export default [
5
- {
6
- input: "node-index.js",
7
- output: [
8
- {
9
- file: "dist/node.cjs",
10
- format: "cjs"
11
- }
12
- ]
13
- },
14
- {
15
- input: "index.js",
16
- output: {
17
- file: "dist/index.js",
18
- format: "umd",
19
- name: "msgpackr"
20
- }
21
- },
22
- {
23
- input: "index.js",
24
- plugins: [minify({
25
- })],
26
- output: {
27
- file: "dist/index.min.js",
28
- format: "umd",
29
- name: "msgpackr"
30
- }
31
- },
32
- {
33
- input: "tests/test.js",
34
- plugins: [json()],
35
- external: ['chai', '../index.js'],
36
- output: {
37
- file: "dist/test.js",
38
- format: "iife",
39
- globals: {
40
- chai: 'chai',
41
- './index.js': 'msgpackr',
42
- },
43
- }
44
- }
45
- ];
1
+ import minify from "rollup-plugin-babel-minify";
2
+ import json from "@rollup/plugin-json";
3
+
4
+ export default [
5
+ {
6
+ input: "node-index.js",
7
+ output: [
8
+ {
9
+ file: "dist/node.cjs",
10
+ format: "cjs",
11
+ sourcemap: true
12
+ }
13
+ ]
14
+ },
15
+ {
16
+ input: "index.js",
17
+ output: {
18
+ file: "dist/index.js",
19
+ format: "umd",
20
+ name: "msgpackr",
21
+ sourcemap: true
22
+ }
23
+ },
24
+ {
25
+ input: "index.js",
26
+ plugins: [minify({
27
+ })],
28
+ output: {
29
+ file: "dist/index.min.js",
30
+ format: "umd",
31
+ name: "msgpackr",
32
+ sourcemap: true
33
+ }
34
+ },
35
+ {
36
+ input: "tests/test.js",
37
+ plugins: [json()],
38
+ external: ['chai', '../index.js'],
39
+ output: {
40
+ file: "dist/test.js",
41
+ format: "iife",
42
+ sourcemap: true,
43
+ globals: {
44
+ chai: 'chai',
45
+ './index.js': 'msgpackr',
46
+ },
47
+ }
48
+ }
49
+ ];