cborg 4.4.0 → 4.5.0
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/.github/workflows/test-and-release.yml +1 -0
- package/CHANGELOG.md +13 -0
- package/README.md +21 -0
- package/bench/README.md +115 -0
- package/bench/bench-comparative.js +133 -0
- package/bench/bench.js +414 -101
- package/bench/fixtures.js +558 -0
- package/bench/index.html +405 -0
- package/cborg.js +2 -1
- package/interface.ts +8 -2
- package/lib/0uint.js +11 -11
- package/lib/1negint.js +4 -4
- package/lib/2bytes.js +5 -5
- package/lib/3string.js +1 -1
- package/lib/4array.js +4 -4
- package/lib/5map.js +4 -4
- package/lib/6tag.js +4 -4
- package/lib/7float.js +10 -10
- package/lib/bl.js +46 -0
- package/lib/encode.js +40 -15
- package/lib/json/encode.js +10 -10
- package/package.json +1 -1
- package/test/test-0uint.js +12 -1
- package/test/test-1negint.js +12 -1
- package/test/test-2bytes.js +11 -1
- package/test/test-3string.js +11 -1
- package/test/test-4array.js +11 -1
- package/test/test-5map.js +11 -3
- package/test/test-6tag.js +19 -1
- package/test/test-7float.js +11 -1
- package/test/test-cbor-vectors.js +13 -2
- package/test/test-encodeInto.js +246 -0
- package/types/cborg.d.ts +2 -1
- package/types/cborg.d.ts.map +1 -1
- package/types/interface.d.ts +7 -2
- package/types/interface.d.ts.map +1 -1
- package/types/lib/0uint.d.ts +6 -6
- package/types/lib/0uint.d.ts.map +1 -1
- package/types/lib/1negint.d.ts +4 -4
- package/types/lib/1negint.d.ts.map +1 -1
- package/types/lib/2bytes.d.ts +3 -3
- package/types/lib/2bytes.d.ts.map +1 -1
- package/types/lib/3string.d.ts +1 -1
- package/types/lib/3string.d.ts.map +1 -1
- package/types/lib/4array.d.ts +3 -3
- package/types/lib/4array.d.ts.map +1 -1
- package/types/lib/5map.d.ts +3 -3
- package/types/lib/5map.d.ts.map +1 -1
- package/types/lib/6tag.d.ts +4 -4
- package/types/lib/6tag.d.ts.map +1 -1
- package/types/lib/7float.d.ts +3 -3
- package/types/lib/7float.d.ts.map +1 -1
- package/types/lib/bl.d.ts +25 -0
- package/types/lib/bl.d.ts.map +1 -1
- package/types/lib/encode.d.ts +12 -1
- package/types/lib/encode.d.ts.map +1 -1
- package/types/lib/json/encode.d.ts +1 -1
- package/types/lib/json/encode.d.ts.map +1 -1
package/lib/7float.js
CHANGED
|
@@ -6,7 +6,7 @@ import { decodeErrPrefix } from './common.js'
|
|
|
6
6
|
import { encodeUint } from './0uint.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @typedef {import('
|
|
9
|
+
* @typedef {import('../interface').ByteWriter} ByteWriter
|
|
10
10
|
* @typedef {import('../interface').DecodeOptions} DecodeOptions
|
|
11
11
|
* @typedef {import('../interface').EncodeOptions} EncodeOptions
|
|
12
12
|
*/
|
|
@@ -98,21 +98,21 @@ export function decodeFloat64 (data, pos, _minor, options) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* @param {
|
|
101
|
+
* @param {ByteWriter} writer
|
|
102
102
|
* @param {Token} token
|
|
103
103
|
* @param {EncodeOptions} options
|
|
104
104
|
*/
|
|
105
|
-
export function encodeFloat (
|
|
105
|
+
export function encodeFloat (writer, token, options) {
|
|
106
106
|
const float = token.value
|
|
107
107
|
|
|
108
108
|
if (float === false) {
|
|
109
|
-
|
|
109
|
+
writer.push([Type.float.majorEncoded | MINOR_FALSE])
|
|
110
110
|
} else if (float === true) {
|
|
111
|
-
|
|
111
|
+
writer.push([Type.float.majorEncoded | MINOR_TRUE])
|
|
112
112
|
} else if (float === null) {
|
|
113
|
-
|
|
113
|
+
writer.push([Type.float.majorEncoded | MINOR_NULL])
|
|
114
114
|
} else if (float === undefined) {
|
|
115
|
-
|
|
115
|
+
writer.push([Type.float.majorEncoded | MINOR_UNDEFINED])
|
|
116
116
|
} else {
|
|
117
117
|
let decoded
|
|
118
118
|
let success = false
|
|
@@ -121,14 +121,14 @@ export function encodeFloat (buf, token, options) {
|
|
|
121
121
|
decoded = readFloat16(ui8a, 1)
|
|
122
122
|
if (float === decoded || Number.isNaN(float)) {
|
|
123
123
|
ui8a[0] = 0xf9
|
|
124
|
-
|
|
124
|
+
writer.push(ui8a.slice(0, 3))
|
|
125
125
|
success = true
|
|
126
126
|
} else {
|
|
127
127
|
encodeFloat32(float)
|
|
128
128
|
decoded = readFloat32(ui8a, 1)
|
|
129
129
|
if (float === decoded) {
|
|
130
130
|
ui8a[0] = 0xfa
|
|
131
|
-
|
|
131
|
+
writer.push(ui8a.slice(0, 5))
|
|
132
132
|
success = true
|
|
133
133
|
}
|
|
134
134
|
}
|
|
@@ -137,7 +137,7 @@ export function encodeFloat (buf, token, options) {
|
|
|
137
137
|
encodeFloat64(float)
|
|
138
138
|
decoded = readFloat64(ui8a, 1)
|
|
139
139
|
ui8a[0] = 0xfb
|
|
140
|
-
|
|
140
|
+
writer.push(ui8a.slice(0, 9))
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
}
|
package/lib/bl.js
CHANGED
|
@@ -122,3 +122,49 @@ export class Bl {
|
|
|
122
122
|
return byts
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* U8Bl is a buffer list that writes directly to a user-provided Uint8Array.
|
|
128
|
+
* It provides the same interface as Bl but writes to a fixed destination.
|
|
129
|
+
*/
|
|
130
|
+
export class U8Bl {
|
|
131
|
+
/**
|
|
132
|
+
* @param {Uint8Array} dest
|
|
133
|
+
*/
|
|
134
|
+
constructor (dest) {
|
|
135
|
+
this.dest = dest
|
|
136
|
+
/** @type {number} */
|
|
137
|
+
this.cursor = 0
|
|
138
|
+
// chunks is for interface compatibility with Bl - encode.js checks chunks.length
|
|
139
|
+
// as a sanity check for pre-calculated sizes. For U8Bl this is always [dest].
|
|
140
|
+
/** @type {Uint8Array[]} */
|
|
141
|
+
this.chunks = [dest]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
reset () {
|
|
145
|
+
this.cursor = 0
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @param {Uint8Array|number[]} bytes
|
|
150
|
+
*/
|
|
151
|
+
push (bytes) {
|
|
152
|
+
if (this.cursor + bytes.length > this.dest.length) {
|
|
153
|
+
throw new Error('write out of bounds, destination buffer is too small')
|
|
154
|
+
}
|
|
155
|
+
this.dest.set(bytes, this.cursor)
|
|
156
|
+
this.cursor += bytes.length
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @param {boolean} [reset]
|
|
161
|
+
* @returns {Uint8Array}
|
|
162
|
+
*/
|
|
163
|
+
toBytes (reset = false) {
|
|
164
|
+
const byts = this.dest.subarray(0, this.cursor)
|
|
165
|
+
if (reset) {
|
|
166
|
+
this.reset()
|
|
167
|
+
}
|
|
168
|
+
return byts
|
|
169
|
+
}
|
|
170
|
+
}
|
package/lib/encode.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { is } from './is.js'
|
|
2
2
|
import { Token, Type } from './token.js'
|
|
3
|
-
import { Bl } from './bl.js'
|
|
3
|
+
import { Bl, U8Bl } from './bl.js'
|
|
4
4
|
import { encodeErrPrefix } from './common.js'
|
|
5
5
|
import { quickEncodeToken } from './jump.js'
|
|
6
6
|
import { asU8A, compare } from './byte-utils.js'
|
|
@@ -21,6 +21,7 @@ import { encodeFloat } from './7float.js'
|
|
|
21
21
|
* @typedef {import('../interface').StrictTypeEncoder} StrictTypeEncoder
|
|
22
22
|
* @typedef {import('../interface').TokenTypeEncoder} TokenTypeEncoder
|
|
23
23
|
* @typedef {import('../interface').TokenOrNestedTokens} TokenOrNestedTokens
|
|
24
|
+
* @typedef {import('../interface').ByteWriter} ByteWriter
|
|
24
25
|
*/
|
|
25
26
|
|
|
26
27
|
/** @type {EncodeOptions} */
|
|
@@ -53,7 +54,7 @@ export function makeCborEncoders () {
|
|
|
53
54
|
|
|
54
55
|
const cborEncoders = makeCborEncoders()
|
|
55
56
|
|
|
56
|
-
const
|
|
57
|
+
const defaultWriter = new Bl()
|
|
57
58
|
|
|
58
59
|
/** @implements {Reference} */
|
|
59
60
|
class Ref {
|
|
@@ -452,18 +453,18 @@ function encodeRfc8949 (data) {
|
|
|
452
453
|
}
|
|
453
454
|
|
|
454
455
|
/**
|
|
455
|
-
* @param {
|
|
456
|
+
* @param {ByteWriter} writer
|
|
456
457
|
* @param {TokenOrNestedTokens} tokens
|
|
457
458
|
* @param {TokenTypeEncoder[]} encoders
|
|
458
459
|
* @param {EncodeOptions} options
|
|
459
460
|
*/
|
|
460
|
-
function tokensToEncoded (
|
|
461
|
+
function tokensToEncoded (writer, tokens, encoders, options) {
|
|
461
462
|
if (Array.isArray(tokens)) {
|
|
462
463
|
for (const token of tokens) {
|
|
463
|
-
tokensToEncoded(
|
|
464
|
+
tokensToEncoded(writer, token, encoders, options)
|
|
464
465
|
}
|
|
465
466
|
} else {
|
|
466
|
-
encoders[tokens.type.major](
|
|
467
|
+
encoders[tokens.type.major](writer, tokens, options)
|
|
467
468
|
}
|
|
468
469
|
}
|
|
469
470
|
|
|
@@ -471,31 +472,43 @@ function tokensToEncoded (buf, tokens, encoders, options) {
|
|
|
471
472
|
* @param {any} data
|
|
472
473
|
* @param {TokenTypeEncoder[]} encoders
|
|
473
474
|
* @param {EncodeOptions} options
|
|
475
|
+
* @param {Uint8Array} [destination]
|
|
474
476
|
* @returns {Uint8Array}
|
|
475
477
|
*/
|
|
476
|
-
function encodeCustom (data, encoders, options) {
|
|
478
|
+
function encodeCustom (data, encoders, options, destination) {
|
|
479
|
+
// arg ordering is different to encodeInto for backward compatibility
|
|
480
|
+
const hasDest = destination instanceof Uint8Array
|
|
481
|
+
let writeTo = hasDest ? new U8Bl(destination) : defaultWriter
|
|
482
|
+
|
|
477
483
|
const tokens = objectToTokens(data, options)
|
|
478
484
|
if (!Array.isArray(tokens) && options.quickEncodeToken) {
|
|
479
485
|
const quickBytes = options.quickEncodeToken(tokens)
|
|
480
486
|
if (quickBytes) {
|
|
487
|
+
if (hasDest) {
|
|
488
|
+
// Copy quick bytes into destination buffer
|
|
489
|
+
writeTo.push(quickBytes)
|
|
490
|
+
return writeTo.toBytes()
|
|
491
|
+
}
|
|
481
492
|
return quickBytes
|
|
482
493
|
}
|
|
483
494
|
const encoder = encoders[tokens.type.major]
|
|
484
495
|
if (encoder.encodedSize) {
|
|
485
496
|
const size = encoder.encodedSize(tokens, options)
|
|
486
|
-
|
|
487
|
-
|
|
497
|
+
if (!hasDest) {
|
|
498
|
+
writeTo = new Bl(size)
|
|
499
|
+
}
|
|
500
|
+
encoder(writeTo, tokens, options)
|
|
488
501
|
/* c8 ignore next 4 */
|
|
489
502
|
// this would be a problem with encodedSize() functions
|
|
490
|
-
if (
|
|
503
|
+
if (writeTo.chunks.length !== 1) {
|
|
491
504
|
throw new Error(`Unexpected error: pre-calculated length for ${tokens} was wrong`)
|
|
492
505
|
}
|
|
493
|
-
return asU8A(
|
|
506
|
+
return hasDest ? writeTo.toBytes() : asU8A(writeTo.chunks[0])
|
|
494
507
|
}
|
|
495
508
|
}
|
|
496
|
-
|
|
497
|
-
tokensToEncoded(
|
|
498
|
-
return
|
|
509
|
+
writeTo.reset()
|
|
510
|
+
tokensToEncoded(writeTo, tokens, encoders, options)
|
|
511
|
+
return writeTo.toBytes(true)
|
|
499
512
|
}
|
|
500
513
|
|
|
501
514
|
/**
|
|
@@ -508,4 +521,16 @@ function encode (data, options) {
|
|
|
508
521
|
return encodeCustom(data, cborEncoders, options)
|
|
509
522
|
}
|
|
510
523
|
|
|
511
|
-
|
|
524
|
+
/**
|
|
525
|
+
* @param {any} data
|
|
526
|
+
* @param {Uint8Array} destination
|
|
527
|
+
* @param {EncodeOptions} [options]
|
|
528
|
+
* @returns {{ written: number }}
|
|
529
|
+
*/
|
|
530
|
+
function encodeInto (data, destination, options) {
|
|
531
|
+
options = Object.assign({}, defaultEncodeOptions, options)
|
|
532
|
+
const result = encodeCustom(data, cborEncoders, options, destination)
|
|
533
|
+
return { written: result.length }
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export { objectToTokens, encode, encodeCustom, encodeInto, Ref }
|
package/lib/json/encode.js
CHANGED
|
@@ -5,8 +5,8 @@ import { asU8A, fromString } from '../byte-utils.js'
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {import('../../interface').EncodeOptions} EncodeOptions
|
|
8
|
+
* @typedef {import('../../interface').ByteWriter} ByteWriter
|
|
8
9
|
* @typedef {import('../token').Token} Token
|
|
9
|
-
* @typedef {import('../bl').Bl} Bl
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
class JSONEncoder extends Array {
|
|
@@ -17,7 +17,7 @@ class JSONEncoder extends Array {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* @param {
|
|
20
|
+
* @param {ByteWriter} buf
|
|
21
21
|
*/
|
|
22
22
|
prefix (buf) {
|
|
23
23
|
const recurs = this.inRecursive[this.inRecursive.length - 1]
|
|
@@ -42,7 +42,7 @@ class JSONEncoder extends Array {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* @param {
|
|
45
|
+
* @param {ByteWriter} buf
|
|
46
46
|
* @param {Token} token
|
|
47
47
|
*/
|
|
48
48
|
[Type.uint.major] (buf, token) {
|
|
@@ -56,7 +56,7 @@ class JSONEncoder extends Array {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* @param {
|
|
59
|
+
* @param {ByteWriter} buf
|
|
60
60
|
* @param {Token} token
|
|
61
61
|
*/
|
|
62
62
|
[Type.negint.major] (buf, token) {
|
|
@@ -65,7 +65,7 @@ class JSONEncoder extends Array {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* @param {
|
|
68
|
+
* @param {ByteWriter} _buf
|
|
69
69
|
* @param {Token} _token
|
|
70
70
|
*/
|
|
71
71
|
[Type.bytes.major] (_buf, _token) {
|
|
@@ -73,7 +73,7 @@ class JSONEncoder extends Array {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* @param {
|
|
76
|
+
* @param {ByteWriter} buf
|
|
77
77
|
* @param {Token} token
|
|
78
78
|
*/
|
|
79
79
|
[Type.string.major] (buf, token) {
|
|
@@ -86,7 +86,7 @@ class JSONEncoder extends Array {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
|
-
* @param {
|
|
89
|
+
* @param {ByteWriter} buf
|
|
90
90
|
* @param {Token} _token
|
|
91
91
|
*/
|
|
92
92
|
[Type.array.major] (buf, _token) {
|
|
@@ -96,7 +96,7 @@ class JSONEncoder extends Array {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* @param {
|
|
99
|
+
* @param {ByteWriter} buf
|
|
100
100
|
* @param {Token} _token
|
|
101
101
|
*/
|
|
102
102
|
[Type.map.major] (buf, _token) {
|
|
@@ -106,13 +106,13 @@ class JSONEncoder extends Array {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
* @param {
|
|
109
|
+
* @param {ByteWriter} _buf
|
|
110
110
|
* @param {Token} _token
|
|
111
111
|
*/
|
|
112
112
|
[Type.tag.major] (_buf, _token) {}
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
* @param {
|
|
115
|
+
* @param {ByteWriter} buf
|
|
116
116
|
* @param {Token} token
|
|
117
117
|
*/
|
|
118
118
|
[Type.float.major] (buf, token) {
|
package/package.json
CHANGED
package/test/test-0uint.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// some from https://github.com/PJK/libcbor
|
|
11
17
|
|
|
12
18
|
const fixtures = [
|
|
@@ -27,6 +33,8 @@ const fixtures = [
|
|
|
27
33
|
{ data: '1bffffffffffffffff', expected: BigInt('18446744073709551615'), type: 'uint64' }
|
|
28
34
|
]
|
|
29
35
|
|
|
36
|
+
const fixedDest = new Uint8Array(1024)
|
|
37
|
+
|
|
30
38
|
describe('uint', () => {
|
|
31
39
|
describe('decode', () => {
|
|
32
40
|
for (const fixture of fixtures) {
|
|
@@ -53,8 +61,10 @@ describe('uint', () => {
|
|
|
53
61
|
it(`should encode ${fixture.type}=${fixture.expected}`, () => {
|
|
54
62
|
if (fixture.strict === false) {
|
|
55
63
|
assert.notStrictEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type} !strict`)
|
|
64
|
+
assert.notStrictEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type} !strict`)
|
|
56
65
|
} else {
|
|
57
66
|
assert.strictEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type}`)
|
|
67
|
+
assert.strictEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type}`)
|
|
58
68
|
}
|
|
59
69
|
})
|
|
60
70
|
}
|
|
@@ -66,6 +76,7 @@ describe('uint', () => {
|
|
|
66
76
|
if (fixture.strict !== false) {
|
|
67
77
|
it(`should roundtrip ${fixture.type}=${fixture.expected}`, () => {
|
|
68
78
|
assert.ok(decode(encode(fixture.expected)) === fixture.expected, `roundtrip ${fixture.type}`)
|
|
79
|
+
assert.ok(decode(encodeIntoBytes(fixture.expected, fixedDest)) === fixture.expected, `roundtrip ${fixture.type}`)
|
|
69
80
|
})
|
|
70
81
|
}
|
|
71
82
|
}
|
package/test/test-1negint.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// some from https://github.com/PJK/libcbor
|
|
11
17
|
|
|
12
18
|
const fixtures = [
|
|
@@ -28,6 +34,8 @@ const fixtures = [
|
|
|
28
34
|
{ data: '3bffffffffffffffff', expected: BigInt('-18446744073709551616'), type: 'negint64' }
|
|
29
35
|
]
|
|
30
36
|
|
|
37
|
+
const fixedDest = new Uint8Array(1024)
|
|
38
|
+
|
|
31
39
|
describe('negint', () => {
|
|
32
40
|
describe('decode', () => {
|
|
33
41
|
for (const fixture of fixtures) {
|
|
@@ -48,8 +56,10 @@ describe('negint', () => {
|
|
|
48
56
|
it(`should encode ${fixture.type}=${fixture.expected}`, () => {
|
|
49
57
|
if (fixture.strict === false) {
|
|
50
58
|
assert.notStrictEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type} !strict`)
|
|
59
|
+
assert.notStrictEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type} !strict`)
|
|
51
60
|
} else {
|
|
52
61
|
assert.strictEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type}`)
|
|
62
|
+
assert.strictEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type}`)
|
|
53
63
|
}
|
|
54
64
|
})
|
|
55
65
|
}
|
|
@@ -60,6 +70,7 @@ describe('negint', () => {
|
|
|
60
70
|
for (const fixture of fixtures) {
|
|
61
71
|
it(`should roundtrip ${fixture.type}=${fixture.expected}`, () => {
|
|
62
72
|
assert.ok(decode(encode(fixture.expected)) === fixture.expected, `roundtrip ${fixture.type}`)
|
|
73
|
+
assert.ok(decode(encodeIntoBytes(fixture.expected, fixedDest)) === fixture.expected, `roundtrip ${fixture.type}`)
|
|
63
74
|
})
|
|
64
75
|
}
|
|
65
76
|
})
|
package/test/test-2bytes.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { useBuffer, fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// some from https://github.com/PJK/libcbor
|
|
11
17
|
|
|
12
18
|
const fixtures = [
|
|
@@ -42,6 +48,8 @@ const fixtures = [
|
|
|
42
48
|
}
|
|
43
49
|
]
|
|
44
50
|
|
|
51
|
+
const fixedDest = new Uint8Array(65536 + 8)
|
|
52
|
+
|
|
45
53
|
// fill up byte arrays we can validate in strict mode, the minimal size for each
|
|
46
54
|
// excluding 64-bit because 4G is just too big
|
|
47
55
|
;(() => {
|
|
@@ -111,8 +119,10 @@ describe('bytes', () => {
|
|
|
111
119
|
assert.throws(() => encode(data), Error, /^CBOR encode error: number too large to encode \(-\d+\)$/)
|
|
112
120
|
} else if (fixture.strict === false) {
|
|
113
121
|
assert.notStrictEqual(toHex(encode(data)), expectedHex, `encode ${fixture.type} !strict`)
|
|
122
|
+
assert.notStrictEqual(toHex(encodeIntoBytes(data, fixedDest)), expectedHex, `encode ${fixture.type} !strict`)
|
|
114
123
|
} else {
|
|
115
124
|
assert.strictEqual(toHex(encode(data)), expectedHex, `encode ${fixture.type}`)
|
|
125
|
+
assert.strictEqual(toHex(encodeIntoBytes(data, fixedDest)), expectedHex, `encode ${fixture.type}`)
|
|
116
126
|
}
|
|
117
127
|
})
|
|
118
128
|
}
|
package/test/test-3string.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// some from https://github.com/PJK/libcbor
|
|
11
17
|
|
|
12
18
|
const fixtures = [
|
|
@@ -52,6 +58,8 @@ const fixtures = [
|
|
|
52
58
|
}
|
|
53
59
|
]
|
|
54
60
|
|
|
61
|
+
const fixedDest = new Uint8Array(65536 + 8)
|
|
62
|
+
|
|
55
63
|
// fill up byte arrays converted to strings so we can validate in strict mode,
|
|
56
64
|
// the minimal size for each excluding 64-bit because 4G is just too big
|
|
57
65
|
;(() => {
|
|
@@ -131,8 +139,10 @@ describe('string', () => {
|
|
|
131
139
|
assert.throws(() => encode(data), Error, /^CBOR encode error: number too large to encode \(-\d+\)$/)
|
|
132
140
|
} else if (fixture.strict === false) {
|
|
133
141
|
assert.notStrictEqual(toHex(encode(data)), expectedHex, `encode ${fixture.type} !strict`)
|
|
142
|
+
assert.notStrictEqual(toHex(encodeIntoBytes(data, fixedDest)), expectedHex, `encode ${fixture.type} !strict`)
|
|
134
143
|
} else {
|
|
135
144
|
assert.strictEqual(toHex(encode(data)), expectedHex, `encode ${fixture.type}`)
|
|
145
|
+
assert.strictEqual(toHex(encodeIntoBytes(data, fixedDest)), expectedHex, `encode ${fixture.type}`)
|
|
136
146
|
}
|
|
137
147
|
})
|
|
138
148
|
|
package/test/test-4array.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
const fixtures = [
|
|
11
17
|
{ data: '80', expected: [], type: 'array empty' },
|
|
12
18
|
{ data: '8102', expected: [2], type: 'array 1 compact uint' },
|
|
@@ -35,6 +41,8 @@ const fixtures = [
|
|
|
35
41
|
{ data: '9b000000000000000403040506', expected: [3, 4, 5, 6], type: 'array 4 ints, length64', strict: false }
|
|
36
42
|
]
|
|
37
43
|
|
|
44
|
+
const fixedDest = new Uint8Array(1024)
|
|
45
|
+
|
|
38
46
|
describe('array', () => {
|
|
39
47
|
describe('decode', () => {
|
|
40
48
|
for (const fixture of fixtures) {
|
|
@@ -63,8 +71,10 @@ describe('array', () => {
|
|
|
63
71
|
assert.throws(encode.bind(null, fixture.expected), Error, /^CBOR encode error: number too large to encode \(\d+\)$/)
|
|
64
72
|
} else if (fixture.strict === false) {
|
|
65
73
|
assert.notDeepEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type} !strict`)
|
|
74
|
+
assert.notDeepEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type} !strict`)
|
|
66
75
|
} else {
|
|
67
76
|
assert.strictEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type}`)
|
|
77
|
+
assert.strictEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type}`)
|
|
68
78
|
}
|
|
69
79
|
})
|
|
70
80
|
}
|
package/test/test-5map.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// TODO: reject duplicate keys from encoded form
|
|
11
17
|
|
|
12
18
|
const fixtures = [
|
|
@@ -133,6 +139,8 @@ const fixtures = [
|
|
|
133
139
|
{ data: 'bb0000000000000001616101', expected: { a: 1 }, type: 'map 1 pair, length64', strict: false }
|
|
134
140
|
]
|
|
135
141
|
|
|
142
|
+
const fixedDest = new Uint8Array(1024)
|
|
143
|
+
|
|
136
144
|
function toMap (arr) {
|
|
137
145
|
const m = new Map()
|
|
138
146
|
for (const [key, value] of arr) {
|
|
@@ -205,9 +213,9 @@ describe('map', () => {
|
|
|
205
213
|
if (fixture.unsafe) {
|
|
206
214
|
assert.throws(encode.bind(null, toEncode), Error, /^CBOR encode error: number too large to encode \(\d+\)$/)
|
|
207
215
|
} else if (fixture.strict === false || fixture.roundtrip === false) {
|
|
208
|
-
assert.notDeepEqual(toHex(
|
|
216
|
+
assert.notDeepEqual(toHex(encodeIntoBytes(toEncode, fixedDest)), fixture.data, `encode ${fixture.type} !strict`)
|
|
209
217
|
} else {
|
|
210
|
-
assert.strictEqual(toHex(
|
|
218
|
+
assert.strictEqual(toHex(encodeIntoBytes(toEncode, fixedDest)), fixture.data, `encode ${fixture.type}`)
|
|
211
219
|
}
|
|
212
220
|
})
|
|
213
221
|
}
|
package/test/test-6tag.js
CHANGED
|
@@ -3,12 +3,20 @@
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
5
|
import { Token, Type } from '../lib/token.js'
|
|
6
|
-
import { decode, encode } from '../cborg.js'
|
|
6
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
7
7
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
8
8
|
import { dateDecoder, dateEncoder } from './common.js'
|
|
9
9
|
|
|
10
10
|
const { assert } = chai
|
|
11
11
|
|
|
12
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
13
|
+
const encodeIntoBytes = (data, dest, options) => {
|
|
14
|
+
const { written } = encodeInto(data, dest, options)
|
|
15
|
+
return dest.subarray(0, written)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fixedDest = new Uint8Array(1024)
|
|
19
|
+
|
|
12
20
|
function Uint16ArrayDecoder (obj) {
|
|
13
21
|
if (typeof obj !== 'string') {
|
|
14
22
|
throw new Error('expected string for tag 23')
|
|
@@ -36,6 +44,11 @@ describe('tag', () => {
|
|
|
36
44
|
'c074323031332d30332d32315432303a30343a30305a' // from appendix_a
|
|
37
45
|
)
|
|
38
46
|
|
|
47
|
+
assert.equal(
|
|
48
|
+
toHex(encodeIntoBytes(new Date('2013-03-21T20:04:00Z'), fixedDest, { typeEncoders: { Date: dateEncoder } })),
|
|
49
|
+
'c074323031332d30332d32315432303a30343a30305a' // from appendix_a
|
|
50
|
+
)
|
|
51
|
+
|
|
39
52
|
const decodedDate = decode(fromHex('c074323031332d30332d32315432303a30343a30305a'), { tags: { 0: dateDecoder } })
|
|
40
53
|
assert.instanceOf(decodedDate, Date)
|
|
41
54
|
assert.equal(decodedDate.toISOString(), new Date('2013-03-21T20:04:00Z').toISOString())
|
|
@@ -47,6 +60,11 @@ describe('tag', () => {
|
|
|
47
60
|
'd76c303130303032303030333030' // tag(23) + string('010002000300')
|
|
48
61
|
)
|
|
49
62
|
|
|
63
|
+
assert.equal(
|
|
64
|
+
toHex(encodeIntoBytes(Uint16Array.from([1, 2, 3]), fixedDest, { typeEncoders: { Uint16Array: Uint16ArrayEncoder } })),
|
|
65
|
+
'd76c303130303032303030333030' // tag(23) + string('010002000300')
|
|
66
|
+
)
|
|
67
|
+
|
|
50
68
|
const decoded = decode(fromHex('d76c303130303032303030333030'), { tags: { 23: Uint16ArrayDecoder } })
|
|
51
69
|
assert.instanceOf(decoded, Uint16Array)
|
|
52
70
|
assert.equal(toHex(decoded), toHex(Uint16Array.from([1, 2, 3])))
|
package/test/test-7float.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import * as chai from 'chai'
|
|
4
4
|
|
|
5
|
-
import { decode, encode } from '../cborg.js'
|
|
5
|
+
import { decode, encode, encodeInto } from '../cborg.js'
|
|
6
6
|
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
7
7
|
|
|
8
8
|
const { assert } = chai
|
|
9
9
|
|
|
10
|
+
// Helper to get encoded bytes from encodeInto (which returns { written })
|
|
11
|
+
const encodeIntoBytes = (data, dest) => {
|
|
12
|
+
const { written } = encodeInto(data, dest)
|
|
13
|
+
return dest.subarray(0, written)
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
const fixtures = [
|
|
11
17
|
{ data: '8601f5f4f6f720', expected: [1, true, false, null, undefined, -1], type: 'array of float specials' },
|
|
12
18
|
{ data: 'f93800', expected: 0.5, type: 'float16' },
|
|
@@ -32,6 +38,8 @@ const fixtures = [
|
|
|
32
38
|
{ data: 'fb40f4241a31a5a515', expected: 82497.63712086187, type: 'float64' }
|
|
33
39
|
]
|
|
34
40
|
|
|
41
|
+
const fixedDest = new Uint8Array(1024)
|
|
42
|
+
|
|
35
43
|
describe('float', () => {
|
|
36
44
|
describe('decode', () => {
|
|
37
45
|
for (const fixture of fixtures) {
|
|
@@ -56,6 +64,7 @@ describe('float', () => {
|
|
|
56
64
|
if (fixture.strict !== false) {
|
|
57
65
|
it(`should encode ${fixture.type}=${fixture.expected}`, () => {
|
|
58
66
|
assert.strictEqual(toHex(encode(fixture.expected)), fixture.data, `encode ${fixture.type}`)
|
|
67
|
+
assert.strictEqual(toHex(encodeIntoBytes(fixture.expected, fixedDest)), fixture.data, `encode ${fixture.type}`)
|
|
59
68
|
})
|
|
60
69
|
}
|
|
61
70
|
}
|
|
@@ -79,6 +88,7 @@ describe('float', () => {
|
|
|
79
88
|
if (!fixture.unsafe && fixture.strict !== false) {
|
|
80
89
|
it(`should roundtrip ${fixture.type}=${fixture.expected}`, () => {
|
|
81
90
|
assert.deepStrictEqual(decode(encode(fixture.expected)), fixture.expected, `roundtrip ${fixture.type}`)
|
|
91
|
+
assert.deepStrictEqual(decode(encodeIntoBytes(fixture.expected, fixedDest)), fixture.expected, `roundtrip ${fixture.type}`)
|
|
82
92
|
})
|
|
83
93
|
}
|
|
84
94
|
}
|