msgpackr 1.5.2 → 1.5.5
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/README.md +4 -2
- package/dist/index.js +241 -138
- package/dist/index.min.js +67 -100
- package/dist/node.cjs +243 -138
- package/dist/test.js +22 -2
- package/pack.js +189 -122
- package/package.json +1 -1
- package/unpack.d.ts +2 -0
- package/unpack.js +49 -10
- package/dist/str.cjs +0 -100
package/pack.js
CHANGED
|
@@ -9,11 +9,12 @@ const hasNodeBuffer = typeof Buffer !== 'undefined'
|
|
|
9
9
|
const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array
|
|
10
10
|
const ByteArray = hasNodeBuffer ? Buffer : Uint8Array
|
|
11
11
|
const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000
|
|
12
|
-
let target
|
|
12
|
+
let target, keysTarget
|
|
13
13
|
let targetView
|
|
14
14
|
let position = 0
|
|
15
15
|
let safeEnd
|
|
16
16
|
let bundledStrings = null
|
|
17
|
+
const MAX_BUNDLE_SIZE = 0xf000
|
|
17
18
|
const hasNonLatin = /[\u0080-\uFFFF]/
|
|
18
19
|
const RECORD_SYMBOL = Symbol('record-id')
|
|
19
20
|
export class Packr extends Unpackr {
|
|
@@ -22,7 +23,6 @@ export class Packr extends Unpackr {
|
|
|
22
23
|
this.offset = 0
|
|
23
24
|
let typeBuffer
|
|
24
25
|
let start
|
|
25
|
-
let sharedStructures
|
|
26
26
|
let hasSharedUpdate
|
|
27
27
|
let structures
|
|
28
28
|
let referenceMap
|
|
@@ -44,10 +44,13 @@ export class Packr extends Unpackr {
|
|
|
44
44
|
maxSharedStructures = hasSharedStructures ? 32 : 0
|
|
45
45
|
if (maxSharedStructures > 8160)
|
|
46
46
|
throw new Error('Maximum maxSharedStructure is 8160')
|
|
47
|
+
if (options.structuredClone && options.moreTypes == undefined) {
|
|
48
|
+
options.moreTypes = true
|
|
49
|
+
}
|
|
47
50
|
let maxOwnStructures = options.maxOwnStructures
|
|
48
51
|
if (maxOwnStructures == null)
|
|
49
52
|
maxOwnStructures = hasSharedStructures ? 32 : 64
|
|
50
|
-
if (
|
|
53
|
+
if (!this.structures && options.useRecords != false)
|
|
51
54
|
this.structures = []
|
|
52
55
|
// two byte record ids for shared structures
|
|
53
56
|
let useTwoByteRecords = maxSharedStructures > 32 || (maxOwnStructures + maxSharedStructures > 64)
|
|
@@ -77,31 +80,28 @@ export class Packr extends Unpackr {
|
|
|
77
80
|
position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster
|
|
78
81
|
start = position
|
|
79
82
|
referenceMap = packr.structuredClone ? new Map() : null
|
|
80
|
-
if (packr.bundleStrings) {
|
|
81
|
-
bundledStrings = [
|
|
82
|
-
|
|
83
|
-
target[position++] = 0x62 // 'b'
|
|
84
|
-
bundledStrings.position = position - start
|
|
85
|
-
position += 4
|
|
83
|
+
if (packr.bundleStrings && typeof value !== 'string') {
|
|
84
|
+
bundledStrings = []
|
|
85
|
+
bundledStrings.size = Infinity // force a new bundle start on first string
|
|
86
86
|
} else
|
|
87
87
|
bundledStrings = null
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
let sharedLength =
|
|
88
|
+
structures = packr.structures
|
|
89
|
+
if (structures) {
|
|
90
|
+
if (structures.uninitialized)
|
|
91
|
+
structures = packr._mergeStructures(packr.getStructures())
|
|
92
|
+
let sharedLength = structures.sharedLength || 0
|
|
93
93
|
if (sharedLength > maxSharedStructures) {
|
|
94
|
-
//if (maxSharedStructures <= 32 &&
|
|
95
|
-
throw new Error('Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to ' +
|
|
94
|
+
//if (maxSharedStructures <= 32 && structures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
|
|
95
|
+
throw new Error('Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to ' + structures.sharedLength)
|
|
96
96
|
}
|
|
97
|
-
if (!
|
|
97
|
+
if (!structures.transitions) {
|
|
98
98
|
// rebuild our structure transitions
|
|
99
|
-
|
|
99
|
+
structures.transitions = Object.create(null)
|
|
100
100
|
for (let i = 0; i < sharedLength; i++) {
|
|
101
|
-
let keys =
|
|
101
|
+
let keys = structures[i]
|
|
102
102
|
if (!keys)
|
|
103
103
|
continue
|
|
104
|
-
let nextTransition, transition =
|
|
104
|
+
let nextTransition, transition = structures.transitions
|
|
105
105
|
for (let j = 0, l = keys.length; j < l; j++) {
|
|
106
106
|
let key = keys[j]
|
|
107
107
|
nextTransition = transition[key]
|
|
@@ -115,20 +115,15 @@ export class Packr extends Unpackr {
|
|
|
115
115
|
lastSharedStructuresLength = sharedLength
|
|
116
116
|
}
|
|
117
117
|
if (!isSequential) {
|
|
118
|
-
|
|
118
|
+
structures.nextId = sharedLength + 0x40
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
if (hasSharedUpdate)
|
|
122
122
|
hasSharedUpdate = false
|
|
123
|
-
structures = sharedStructures || []
|
|
124
123
|
try {
|
|
125
124
|
pack(value)
|
|
126
125
|
if (bundledStrings) {
|
|
127
|
-
|
|
128
|
-
let writeStrings = bundledStrings
|
|
129
|
-
bundledStrings = null
|
|
130
|
-
pack(writeStrings[0])
|
|
131
|
-
pack(writeStrings[1])
|
|
126
|
+
writeBundles(start, pack)
|
|
132
127
|
}
|
|
133
128
|
packr.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
134
129
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
@@ -147,12 +142,15 @@ export class Packr extends Unpackr {
|
|
|
147
142
|
}
|
|
148
143
|
return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
149
144
|
} finally {
|
|
150
|
-
if (
|
|
145
|
+
if (structures) {
|
|
151
146
|
if (serializationsSinceTransitionRebuild < 10)
|
|
152
147
|
serializationsSinceTransitionRebuild++
|
|
148
|
+
let sharedLength = structures.sharedLength || maxSharedStructures
|
|
149
|
+
if (structures.length > sharedLength)
|
|
150
|
+
structures.length = sharedLength
|
|
153
151
|
if (transitionsCount > 10000) {
|
|
154
152
|
// force a rebuild occasionally after a lot of transitions so it can get cleaned up
|
|
155
|
-
|
|
153
|
+
structures.transitions = null
|
|
156
154
|
serializationsSinceTransitionRebuild = 0
|
|
157
155
|
transitionsCount = 0
|
|
158
156
|
if (recordIdsToRemove.length > 0)
|
|
@@ -164,13 +162,9 @@ export class Packr extends Unpackr {
|
|
|
164
162
|
recordIdsToRemove = []
|
|
165
163
|
}
|
|
166
164
|
if (hasSharedUpdate && packr.saveStructures) {
|
|
167
|
-
let sharedLength = sharedStructures.sharedLength || maxSharedStructures
|
|
168
|
-
if (sharedStructures.length > sharedLength) {
|
|
169
|
-
sharedStructures = sharedStructures.slice(0, sharedLength)
|
|
170
|
-
}
|
|
171
165
|
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
172
166
|
let returnBuffer = target.subarray(start, position)
|
|
173
|
-
if (packr.saveStructures(
|
|
167
|
+
if (packr.saveStructures(structures, lastSharedStructuresLength) === false) {
|
|
174
168
|
// get updated structures and try again if the update failed
|
|
175
169
|
packr._mergeStructures(packr.getStructures())
|
|
176
170
|
return packr.pack(value)
|
|
@@ -191,7 +185,30 @@ export class Packr extends Unpackr {
|
|
|
191
185
|
var length
|
|
192
186
|
if (type === 'string') {
|
|
193
187
|
let strLength = value.length
|
|
194
|
-
if (bundledStrings && strLength >=
|
|
188
|
+
if (bundledStrings && strLength >= 4 && strLength < 0x1000) {
|
|
189
|
+
if ((bundledStrings.size += strLength) > MAX_BUNDLE_SIZE) {
|
|
190
|
+
let extStart
|
|
191
|
+
let maxBytes = (bundledStrings[0] ? bundledStrings[0].length * 3 + bundledStrings[1].length : 0) + 10
|
|
192
|
+
if (position + maxBytes > safeEnd)
|
|
193
|
+
target = makeRoom(position + maxBytes)
|
|
194
|
+
if (bundledStrings.position) { // here we use the 0x62 extension to write the last bundle and reserve sapce for the reference pointer to the next/current bundle
|
|
195
|
+
target[position] = 0xc8 // ext 16
|
|
196
|
+
position += 3 // reserve for the writing bundle size
|
|
197
|
+
target[position++] = 0x62 // 'b'
|
|
198
|
+
extStart = position - start
|
|
199
|
+
position += 4 // reserve for writing bundle reference
|
|
200
|
+
writeBundles(start, pack) // write the last bundles
|
|
201
|
+
targetView.setUint16(extStart + start - 3, position - start - extStart)
|
|
202
|
+
} else { // here we use the 0x62 extension just to reserve the space for the reference pointer to the bundle (will be updated once the bundle is written)
|
|
203
|
+
target[position++] = 0xd6 // fixext 4
|
|
204
|
+
target[position++] = 0x62 // 'b'
|
|
205
|
+
extStart = position - start
|
|
206
|
+
position += 4 // reserve for writing bundle reference
|
|
207
|
+
}
|
|
208
|
+
bundledStrings = ['', ''] // create new ones
|
|
209
|
+
bundledStrings.size = 0
|
|
210
|
+
bundledStrings.position = extStart
|
|
211
|
+
}
|
|
195
212
|
let twoByte = hasNonLatin.test(value)
|
|
196
213
|
bundledStrings[twoByte ? 0 : 1] += value
|
|
197
214
|
target[position++] = 0xc1
|
|
@@ -496,8 +513,7 @@ export class Packr extends Unpackr {
|
|
|
496
513
|
target[objectOffset++ + start] = size >> 8
|
|
497
514
|
target[objectOffset + start] = size & 0xff
|
|
498
515
|
} :
|
|
499
|
-
|
|
500
|
-
/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
|
|
516
|
+
(options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
|
|
501
517
|
(object, safePrototype) => {
|
|
502
518
|
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
|
|
503
519
|
let objectOffset = position++ - start
|
|
@@ -505,44 +521,47 @@ export class Packr extends Unpackr {
|
|
|
505
521
|
for (let key in object) {
|
|
506
522
|
if (safePrototype || object.hasOwnProperty(key)) {
|
|
507
523
|
nextTransition = transition[key]
|
|
508
|
-
if (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
let
|
|
514
|
-
|
|
515
|
-
|
|
524
|
+
if (nextTransition)
|
|
525
|
+
transition = nextTransition
|
|
526
|
+
else {
|
|
527
|
+
// record doesn't exist, create full new record and insert it
|
|
528
|
+
let keys = Object.keys(object)
|
|
529
|
+
let lastTransition = transition
|
|
530
|
+
transition = structures.transitions
|
|
531
|
+
let newTransitions = 0
|
|
532
|
+
for (let i = 0, l = keys.length; i < l; i++) {
|
|
516
533
|
let key = keys[i]
|
|
517
|
-
|
|
518
|
-
if (
|
|
519
|
-
nextTransition =
|
|
520
|
-
|
|
534
|
+
nextTransition = transition[key]
|
|
535
|
+
if (!nextTransition) {
|
|
536
|
+
nextTransition = transition[key] = Object.create(null)
|
|
537
|
+
newTransitions++
|
|
521
538
|
}
|
|
539
|
+
transition = nextTransition
|
|
522
540
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
541
|
+
if (objectOffset + start + 1 == position) {
|
|
542
|
+
// first key, so we don't need to insert, we can just write record directly
|
|
543
|
+
position--
|
|
544
|
+
newRecord(transition, keys, newTransitions)
|
|
545
|
+
} else // otherwise we need to insert the record, moving existing data after the record
|
|
546
|
+
insertNewRecord(transition, keys, objectOffset, newTransitions)
|
|
547
|
+
wroteKeys = true
|
|
548
|
+
transition = lastTransition[key]
|
|
527
549
|
}
|
|
528
|
-
transition = nextTransition
|
|
529
550
|
pack(object[key])
|
|
530
551
|
}
|
|
531
552
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
553
|
+
if (!wroteKeys) {
|
|
554
|
+
let recordId = transition[RECORD_SYMBOL]
|
|
555
|
+
if (recordId)
|
|
556
|
+
target[objectOffset + start] = recordId
|
|
557
|
+
else
|
|
558
|
+
insertNewRecord(transition, Object.keys(object), objectOffset, 0)
|
|
537
559
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
(object) => {
|
|
541
|
-
let keys = Object.keys(object)
|
|
560
|
+
} :
|
|
561
|
+
(object, safePrototype) => {
|
|
542
562
|
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
|
|
543
563
|
let newTransitions = 0
|
|
544
|
-
for (let
|
|
545
|
-
let key = keys[i]
|
|
564
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
546
565
|
nextTransition = transition[key]
|
|
547
566
|
if (!nextTransition) {
|
|
548
567
|
nextTransition = transition[key] = Object.create(null)
|
|
@@ -558,57 +577,12 @@ export class Packr extends Unpackr {
|
|
|
558
577
|
} else
|
|
559
578
|
target[position++] = recordId
|
|
560
579
|
} else {
|
|
561
|
-
|
|
562
|
-
if (!recordId)
|
|
563
|
-
recordId = 0x40
|
|
564
|
-
if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
|
|
565
|
-
recordId = structures.nextOwnId
|
|
566
|
-
if (!(recordId < maxStructureId))
|
|
567
|
-
recordId = sharedLimitId
|
|
568
|
-
structures.nextOwnId = recordId + 1
|
|
569
|
-
} else {
|
|
570
|
-
if (recordId >= maxStructureId)// cycle back around
|
|
571
|
-
recordId = sharedLimitId
|
|
572
|
-
structures.nextId = recordId + 1
|
|
573
|
-
}
|
|
574
|
-
let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1
|
|
575
|
-
transition[RECORD_SYMBOL] = recordId
|
|
576
|
-
structures[recordId - 0x40] = keys
|
|
577
|
-
|
|
578
|
-
if (recordId < sharedLimitId) {
|
|
579
|
-
keys.isShared = true
|
|
580
|
-
structures.sharedLength = recordId - 0x3f
|
|
581
|
-
hasSharedUpdate = true
|
|
582
|
-
if (highByte >= 0) {
|
|
583
|
-
target[position++] = (recordId & 0x1f) + 0x60
|
|
584
|
-
target[position++] = highByte
|
|
585
|
-
} else {
|
|
586
|
-
target[position++] = recordId
|
|
587
|
-
}
|
|
588
|
-
} else {
|
|
589
|
-
if (highByte >= 0) {
|
|
590
|
-
target[position++] = 0xd5 // fixext 2
|
|
591
|
-
target[position++] = 0x72 // "r" record defintion extension type
|
|
592
|
-
target[position++] = (recordId & 0x1f) + 0x60
|
|
593
|
-
target[position++] = highByte
|
|
594
|
-
} else {
|
|
595
|
-
target[position++] = 0xd4 // fixext 1
|
|
596
|
-
target[position++] = 0x72 // "r" record defintion extension type
|
|
597
|
-
target[position++] = recordId
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
if (newTransitions)
|
|
601
|
-
transitionsCount += serializationsSinceTransitionRebuild * newTransitions
|
|
602
|
-
// record the removal of the id, we can maintain our shared structure
|
|
603
|
-
if (recordIdsToRemove.length >= maxOwnStructures)
|
|
604
|
-
recordIdsToRemove.shift()[RECORD_SYMBOL] = 0 // we are cycling back through, and have to remove old ones
|
|
605
|
-
recordIdsToRemove.push(transition)
|
|
606
|
-
pack(keys)
|
|
607
|
-
}
|
|
580
|
+
newRecord(transition, transition.__keys__ || Object.keys(object), newTransitions)
|
|
608
581
|
}
|
|
609
582
|
// now write the values
|
|
610
|
-
for (let
|
|
611
|
-
|
|
583
|
+
for (let key in object)
|
|
584
|
+
if (safePrototype || object.hasOwnProperty(key))
|
|
585
|
+
pack(object[key])
|
|
612
586
|
}
|
|
613
587
|
const makeRoom = (end) => {
|
|
614
588
|
let newSize
|
|
@@ -631,6 +605,86 @@ export class Packr extends Unpackr {
|
|
|
631
605
|
safeEnd = newBuffer.length - 10
|
|
632
606
|
return target = newBuffer
|
|
633
607
|
}
|
|
608
|
+
const newRecord = (transition, keys, newTransitions) => {
|
|
609
|
+
let recordId = structures.nextId
|
|
610
|
+
if (!recordId)
|
|
611
|
+
recordId = 0x40
|
|
612
|
+
if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
|
|
613
|
+
recordId = structures.nextOwnId
|
|
614
|
+
if (!(recordId < maxStructureId))
|
|
615
|
+
recordId = sharedLimitId
|
|
616
|
+
structures.nextOwnId = recordId + 1
|
|
617
|
+
} else {
|
|
618
|
+
if (recordId >= maxStructureId)// cycle back around
|
|
619
|
+
recordId = sharedLimitId
|
|
620
|
+
structures.nextId = recordId + 1
|
|
621
|
+
}
|
|
622
|
+
let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1
|
|
623
|
+
transition[RECORD_SYMBOL] = recordId
|
|
624
|
+
transition.__keys__ = keys
|
|
625
|
+
structures[recordId - 0x40] = keys
|
|
626
|
+
|
|
627
|
+
if (recordId < sharedLimitId) {
|
|
628
|
+
keys.isShared = true
|
|
629
|
+
structures.sharedLength = recordId - 0x3f
|
|
630
|
+
hasSharedUpdate = true
|
|
631
|
+
if (highByte >= 0) {
|
|
632
|
+
target[position++] = (recordId & 0x1f) + 0x60
|
|
633
|
+
target[position++] = highByte
|
|
634
|
+
} else {
|
|
635
|
+
target[position++] = recordId
|
|
636
|
+
}
|
|
637
|
+
} else {
|
|
638
|
+
if (highByte >= 0) {
|
|
639
|
+
target[position++] = 0xd5 // fixext 2
|
|
640
|
+
target[position++] = 0x72 // "r" record defintion extension type
|
|
641
|
+
target[position++] = (recordId & 0x1f) + 0x60
|
|
642
|
+
target[position++] = highByte
|
|
643
|
+
} else {
|
|
644
|
+
target[position++] = 0xd4 // fixext 1
|
|
645
|
+
target[position++] = 0x72 // "r" record defintion extension type
|
|
646
|
+
target[position++] = recordId
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (newTransitions)
|
|
650
|
+
transitionsCount += serializationsSinceTransitionRebuild * newTransitions
|
|
651
|
+
// record the removal of the id, we can maintain our shared structure
|
|
652
|
+
if (recordIdsToRemove.length >= maxOwnStructures)
|
|
653
|
+
recordIdsToRemove.shift()[RECORD_SYMBOL] = 0 // we are cycling back through, and have to remove old ones
|
|
654
|
+
recordIdsToRemove.push(transition)
|
|
655
|
+
pack(keys)
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
const insertNewRecord = (transition, keys, insertionOffset, newTransitions) => {
|
|
659
|
+
let mainTarget = target
|
|
660
|
+
let mainPosition = position
|
|
661
|
+
let mainSafeEnd = safeEnd
|
|
662
|
+
let mainStart = start
|
|
663
|
+
target = keysTarget
|
|
664
|
+
position = 0
|
|
665
|
+
start = 0
|
|
666
|
+
if (!target)
|
|
667
|
+
keysTarget = target = new ByteArrayAllocate(8192)
|
|
668
|
+
safeEnd = target.length - 10
|
|
669
|
+
newRecord(transition, keys, newTransitions)
|
|
670
|
+
keysTarget = target
|
|
671
|
+
let keysPosition = position
|
|
672
|
+
target = mainTarget
|
|
673
|
+
position = mainPosition
|
|
674
|
+
safeEnd = mainSafeEnd
|
|
675
|
+
start = mainStart
|
|
676
|
+
if (keysPosition > 1) {
|
|
677
|
+
let newEnd = position + keysPosition - 1
|
|
678
|
+
if (newEnd > safeEnd)
|
|
679
|
+
makeRoom(newEnd)
|
|
680
|
+
let insertionPosition = insertionOffset + start
|
|
681
|
+
target.copyWithin(insertionPosition + keysPosition, insertionPosition + 1, position)
|
|
682
|
+
target.set(keysTarget.slice(0, keysPosition), insertionPosition)
|
|
683
|
+
position = newEnd
|
|
684
|
+
} else {
|
|
685
|
+
target[insertionOffset + start] = keysTarget[0]
|
|
686
|
+
}
|
|
687
|
+
}
|
|
634
688
|
}
|
|
635
689
|
useBuffer(buffer) {
|
|
636
690
|
// this means we are finished using our own buffer and we can write over it safely
|
|
@@ -638,6 +692,10 @@ export class Packr extends Unpackr {
|
|
|
638
692
|
targetView = new DataView(target.buffer, target.byteOffset, target.byteLength)
|
|
639
693
|
position = 0
|
|
640
694
|
}
|
|
695
|
+
clearSharedData() {
|
|
696
|
+
if (this.structures)
|
|
697
|
+
this.structures = []
|
|
698
|
+
}
|
|
641
699
|
}
|
|
642
700
|
|
|
643
701
|
function copyBinary(source, target, targetOffset, offset, endOffset) {
|
|
@@ -686,8 +744,8 @@ extensions = [{
|
|
|
686
744
|
}, {
|
|
687
745
|
pack(set, allocateForWrite, pack) {
|
|
688
746
|
let array = Array.from(set)
|
|
689
|
-
let { target, position} = allocateForWrite(this.
|
|
690
|
-
if (this.
|
|
747
|
+
let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0)
|
|
748
|
+
if (this.moreTypes) {
|
|
691
749
|
target[position++] = 0xd4
|
|
692
750
|
target[position++] = 0x73 // 's' for Set
|
|
693
751
|
target[position++] = 0
|
|
@@ -696,8 +754,8 @@ extensions = [{
|
|
|
696
754
|
}
|
|
697
755
|
}, {
|
|
698
756
|
pack(error, allocateForWrite, pack) {
|
|
699
|
-
let { target, position} = allocateForWrite(this.
|
|
700
|
-
if (this.
|
|
757
|
+
let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0)
|
|
758
|
+
if (this.moreTypes) {
|
|
701
759
|
target[position++] = 0xd4
|
|
702
760
|
target[position++] = 0x65 // 'e' for error
|
|
703
761
|
target[position++] = 0
|
|
@@ -706,8 +764,8 @@ extensions = [{
|
|
|
706
764
|
}
|
|
707
765
|
}, {
|
|
708
766
|
pack(regex, allocateForWrite, pack) {
|
|
709
|
-
let { target, position} = allocateForWrite(this.
|
|
710
|
-
if (this.
|
|
767
|
+
let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0)
|
|
768
|
+
if (this.moreTypes) {
|
|
711
769
|
target[position++] = 0xd4
|
|
712
770
|
target[position++] = 0x78 // 'x' for regeXp
|
|
713
771
|
target[position++] = 0
|
|
@@ -716,7 +774,7 @@ extensions = [{
|
|
|
716
774
|
}
|
|
717
775
|
}, {
|
|
718
776
|
pack(arrayBuffer, allocateForWrite) {
|
|
719
|
-
if (this.
|
|
777
|
+
if (this.moreTypes)
|
|
720
778
|
writeExtBuffer(arrayBuffer, 0x10, allocateForWrite)
|
|
721
779
|
else
|
|
722
780
|
writeBuffer(hasNodeBuffer ? Buffer.from(arrayBuffer) : new Uint8Array(arrayBuffer), allocateForWrite)
|
|
@@ -724,7 +782,7 @@ extensions = [{
|
|
|
724
782
|
}, {
|
|
725
783
|
pack(typedArray, allocateForWrite) {
|
|
726
784
|
let constructor = typedArray.constructor
|
|
727
|
-
if (constructor !== ByteArray && this.
|
|
785
|
+
if (constructor !== ByteArray && this.moreTypes)
|
|
728
786
|
writeExtBuffer(typedArray, typedArrays.indexOf(constructor.name), allocateForWrite)
|
|
729
787
|
else
|
|
730
788
|
writeBuffer(typedArray, allocateForWrite)
|
|
@@ -841,6 +899,15 @@ function insertIds(serialized, idsToInsert) {
|
|
|
841
899
|
return serialized
|
|
842
900
|
}
|
|
843
901
|
|
|
902
|
+
function writeBundles(start, pack) {
|
|
903
|
+
targetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start)
|
|
904
|
+
let writeStrings = bundledStrings
|
|
905
|
+
bundledStrings = null
|
|
906
|
+
let startPosition = position
|
|
907
|
+
pack(writeStrings[0])
|
|
908
|
+
pack(writeStrings[1])
|
|
909
|
+
}
|
|
910
|
+
|
|
844
911
|
export function addExtension(extension) {
|
|
845
912
|
if (extension.Class) {
|
|
846
913
|
if (!extension.pack && !extension.write)
|
package/package.json
CHANGED
package/unpack.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface Options {
|
|
|
9
9
|
useFloat32?: FLOAT32_OPTIONS
|
|
10
10
|
useRecords?: boolean
|
|
11
11
|
structures?: {}[]
|
|
12
|
+
moreTypes?: boolean
|
|
12
13
|
structuredClone?: boolean
|
|
13
14
|
mapsAsObjects?: boolean
|
|
14
15
|
variableMapSize?: boolean
|
|
@@ -19,6 +20,7 @@ export interface Options {
|
|
|
19
20
|
encodeUndefinedAsNil?: boolean
|
|
20
21
|
maxSharedStructures?: number
|
|
21
22
|
maxOwnStructures?: number
|
|
23
|
+
int64AsNumber?: boolean
|
|
22
24
|
shouldShareStructure?: (keys: string[]) => boolean
|
|
23
25
|
getStructures?(): {}[]
|
|
24
26
|
saveStructures?(structures: {}[]): boolean | void
|
package/unpack.js
CHANGED
|
@@ -27,6 +27,13 @@ export class C1Type {}
|
|
|
27
27
|
export const C1 = new C1Type()
|
|
28
28
|
C1.name = 'MessagePack 0xC1'
|
|
29
29
|
var sequentialMode = false
|
|
30
|
+
var inlineObjectReadThreshold = 2
|
|
31
|
+
try {
|
|
32
|
+
new Function('')
|
|
33
|
+
} catch(error) {
|
|
34
|
+
// if eval variants are not supported, do not create inline object readers ever
|
|
35
|
+
inlineObjectReadThreshold = Infinity
|
|
36
|
+
}
|
|
30
37
|
|
|
31
38
|
export class Unpackr {
|
|
32
39
|
constructor(options) {
|
|
@@ -156,6 +163,9 @@ export function checkedRead() {
|
|
|
156
163
|
currentStructures.length = sharedLength
|
|
157
164
|
}
|
|
158
165
|
let result = read()
|
|
166
|
+
if (bundledStrings) // bundled strings to skip past
|
|
167
|
+
position = bundledStrings.postBundlePosition
|
|
168
|
+
|
|
159
169
|
if (position == srcEnd) {
|
|
160
170
|
// finished reading this source, cleanup references
|
|
161
171
|
if (currentStructures.restoreStructures)
|
|
@@ -437,7 +447,7 @@ const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/
|
|
|
437
447
|
function createStructureReader(structure, firstId) {
|
|
438
448
|
function readObject() {
|
|
439
449
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
440
|
-
if (readObject.count++ >
|
|
450
|
+
if (readObject.count++ > inlineObjectReadThreshold) {
|
|
441
451
|
let readObject = structure.read = (new Function('r', 'return function(){return {' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}}'))(read)
|
|
442
452
|
if (structure.highByte === 0)
|
|
443
453
|
structure.read = createSecondByteReader(firstId, structure.read)
|
|
@@ -498,6 +508,8 @@ export function setExtractor(extractStrings) {
|
|
|
498
508
|
return function readString(length) {
|
|
499
509
|
let string = strings[stringPosition++]
|
|
500
510
|
if (string == null) {
|
|
511
|
+
if (bundledStrings)
|
|
512
|
+
return readStringJS(length)
|
|
501
513
|
let extraction = extractStrings(position - headerLength, srcEnd, src)
|
|
502
514
|
if (typeof extraction == 'string') {
|
|
503
515
|
string = extraction
|
|
@@ -756,6 +768,36 @@ function shortStringInJS(length) {
|
|
|
756
768
|
}
|
|
757
769
|
}
|
|
758
770
|
|
|
771
|
+
function readOnlyJSString() {
|
|
772
|
+
let token = src[position++]
|
|
773
|
+
let length
|
|
774
|
+
if (token < 0xc0) {
|
|
775
|
+
// fixstr
|
|
776
|
+
length = token - 0xa0
|
|
777
|
+
} else {
|
|
778
|
+
switch(token) {
|
|
779
|
+
case 0xd9:
|
|
780
|
+
// str 8
|
|
781
|
+
length = src[position++]
|
|
782
|
+
break
|
|
783
|
+
case 0xda:
|
|
784
|
+
// str 16
|
|
785
|
+
length = dataView.getUint16(position)
|
|
786
|
+
position += 2
|
|
787
|
+
break
|
|
788
|
+
case 0xdb:
|
|
789
|
+
// str 32
|
|
790
|
+
length = dataView.getUint32(position)
|
|
791
|
+
position += 4
|
|
792
|
+
break
|
|
793
|
+
default:
|
|
794
|
+
throw new Error('Expected string')
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return readStringJS(length)
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
|
|
759
801
|
function readBin(length) {
|
|
760
802
|
return currentUnpackr.copyBuffers ?
|
|
761
803
|
// specifically use the copying slice (not the node one)
|
|
@@ -907,21 +949,18 @@ currentExtensions[0x78] = () => {
|
|
|
907
949
|
let data = read()
|
|
908
950
|
return new RegExp(data[0], data[1])
|
|
909
951
|
}
|
|
910
|
-
|
|
952
|
+
const TEMP_BUNDLE = []
|
|
911
953
|
currentExtensions[0x62] = (data) => {
|
|
912
954
|
let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
|
|
913
955
|
let dataPosition = position
|
|
914
|
-
position += dataSize -
|
|
915
|
-
bundledStrings =
|
|
956
|
+
position += dataSize - data.length
|
|
957
|
+
bundledStrings = TEMP_BUNDLE
|
|
958
|
+
bundledStrings = [readOnlyJSString(), readOnlyJSString()]
|
|
916
959
|
bundledStrings.position0 = 0
|
|
917
960
|
bundledStrings.position1 = 0
|
|
918
|
-
|
|
961
|
+
bundledStrings.postBundlePosition = position
|
|
919
962
|
position = dataPosition
|
|
920
|
-
|
|
921
|
-
return read()
|
|
922
|
-
} finally {
|
|
923
|
-
position = postBundlePosition
|
|
924
|
-
}
|
|
963
|
+
return read()
|
|
925
964
|
}
|
|
926
965
|
|
|
927
966
|
currentExtensions[0xff] = (data) => {
|