@cloudpss/ubjson 0.5.11 → 0.5.13
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/common/decoder.d.ts +9 -2
- package/dist/common/decoder.js +30 -17
- package/dist/common/decoder.js.map +1 -1
- package/dist/common/encoder.js +30 -4
- package/dist/common/encoder.js.map +1 -1
- package/dist/decoder.d.ts +7 -1
- package/dist/decoder.js +8 -1
- package/dist/decoder.js.map +1 -1
- package/dist/encoder.d.ts +6 -0
- package/dist/encoder.js +33 -4
- package/dist/encoder.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/stream/index.d.ts +4 -0
- package/dist/stream/index.js +24 -0
- package/dist/stream/index.js.map +1 -1
- package/dist/stream-helper/decoder.d.ts +2 -2
- package/dist/stream-helper/decoder.js +2 -2
- package/dist/stream-helper/decoder.js.map +1 -1
- package/package.json +2 -2
- package/src/common/decoder.ts +37 -21
- package/src/common/encoder.ts +29 -5
- package/src/decoder.ts +10 -1
- package/src/encoder.ts +34 -4
- package/src/index.ts +18 -3
- package/src/stream/index.ts +22 -0
- package/src/stream-helper/decoder.ts +2 -2
- package/tests/decode.js +39 -9
- package/tests/encode.js +31 -2
- package/tests/many.js +44 -0
- package/tests/rxjs/decode.js +10 -8
- package/tests/rxjs/encode.js +6 -2
- package/tests/stream/decode.js +10 -8
- package/tests/stream/encode.js +6 -2
- package/tests/stream/many.js +100 -0
package/src/common/decoder.ts
CHANGED
|
@@ -4,15 +4,29 @@ import { decode, decodeKey } from './string-decoder.js';
|
|
|
4
4
|
|
|
5
5
|
const fromEntries = Object.fromEntries;
|
|
6
6
|
|
|
7
|
+
/** decoder options */
|
|
8
|
+
export interface DecoderOptions {
|
|
9
|
+
/** 对 {@link Uint8Array} 使用 subarray */
|
|
10
|
+
noAllocBuffer?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
/** decoder */
|
|
8
|
-
export class
|
|
14
|
+
export class DecoderBase {
|
|
9
15
|
protected readonly view: DataView;
|
|
10
16
|
protected readonly data: Uint8Array;
|
|
11
17
|
/** 当前读指针位置 */
|
|
12
18
|
protected offset = 0;
|
|
13
|
-
|
|
19
|
+
|
|
20
|
+
/** 选项 */
|
|
21
|
+
protected readonly noAllocBuffer;
|
|
22
|
+
constructor(data: BinaryData, options?: DecoderOptions) {
|
|
14
23
|
this.data = toUint8Array(data);
|
|
15
24
|
this.view = new DataView(this.data.buffer, this.data.byteOffset, this.data.byteLength);
|
|
25
|
+
if (options) {
|
|
26
|
+
this.noAllocBuffer = !!options.noAllocBuffer;
|
|
27
|
+
} else {
|
|
28
|
+
this.noAllocBuffer = false;
|
|
29
|
+
}
|
|
16
30
|
}
|
|
17
31
|
|
|
18
32
|
/** EOF */
|
|
@@ -76,9 +90,7 @@ export class Decoder {
|
|
|
76
90
|
object.length = count;
|
|
77
91
|
for (let i = 0; i < count; i++) {
|
|
78
92
|
const key = this.readKey();
|
|
79
|
-
const
|
|
80
|
-
if (t === undefined) this.eof();
|
|
81
|
-
const value = this.readData(t);
|
|
93
|
+
const value = this.readData(type ?? this.readMarker());
|
|
82
94
|
object[i] = [key, value];
|
|
83
95
|
}
|
|
84
96
|
return fromEntries(object);
|
|
@@ -99,13 +111,9 @@ export class Decoder {
|
|
|
99
111
|
switch (type) {
|
|
100
112
|
case constants.UINT8:
|
|
101
113
|
try {
|
|
102
|
-
const buf = new Uint8Array(
|
|
103
|
-
this.data.buffer,
|
|
104
|
-
this.data.byteOffset + this.offset,
|
|
105
|
-
count,
|
|
106
|
-
).slice();
|
|
114
|
+
const buf = new Uint8Array(this.data.buffer, this.data.byteOffset + this.offset, count);
|
|
107
115
|
this.offset += count;
|
|
108
|
-
return buf;
|
|
116
|
+
return this.noAllocBuffer ? buf : buf.slice();
|
|
109
117
|
} catch {
|
|
110
118
|
return this.eof();
|
|
111
119
|
}
|
|
@@ -154,8 +162,7 @@ export class Decoder {
|
|
|
154
162
|
for (let i = 0; i < count; i++) {
|
|
155
163
|
result[i] = this.readInt64Data();
|
|
156
164
|
}
|
|
157
|
-
|
|
158
|
-
//return result;
|
|
165
|
+
return result;
|
|
159
166
|
}
|
|
160
167
|
case constants.NULL:
|
|
161
168
|
return Array.from({ length: count }).fill(null);
|
|
@@ -193,8 +200,13 @@ export class Decoder {
|
|
|
193
200
|
return true;
|
|
194
201
|
case constants.FALSE:
|
|
195
202
|
return false;
|
|
196
|
-
case constants.INT64:
|
|
197
|
-
|
|
203
|
+
case constants.INT64: {
|
|
204
|
+
const n = this.readInt64Data();
|
|
205
|
+
if (n < Number.MIN_SAFE_INTEGER || n > Number.MAX_SAFE_INTEGER) {
|
|
206
|
+
return n;
|
|
207
|
+
}
|
|
208
|
+
return Number(n);
|
|
209
|
+
}
|
|
198
210
|
case constants.HIGH_PRECISION_NUMBER: {
|
|
199
211
|
const length = this.readIntLength();
|
|
200
212
|
try {
|
|
@@ -227,9 +239,14 @@ export class Decoder {
|
|
|
227
239
|
case constants.INT32:
|
|
228
240
|
length = this.readInt32Data();
|
|
229
241
|
break;
|
|
230
|
-
case constants.INT64:
|
|
231
|
-
|
|
242
|
+
case constants.INT64: {
|
|
243
|
+
const l = this.readInt64Data();
|
|
244
|
+
if (l < 0 || l > Number.MAX_SAFE_INTEGER) {
|
|
245
|
+
throw new Error('Invalid length');
|
|
246
|
+
}
|
|
247
|
+
length = Number(l);
|
|
232
248
|
break;
|
|
249
|
+
}
|
|
233
250
|
default:
|
|
234
251
|
throw new Error(`Unexpected marker '${String.fromCharCode(marker)}'(${marker}) for int length`);
|
|
235
252
|
}
|
|
@@ -284,15 +301,14 @@ export class Decoder {
|
|
|
284
301
|
}
|
|
285
302
|
}
|
|
286
303
|
/** readInt64Data */
|
|
287
|
-
private readInt64Data():
|
|
304
|
+
private readInt64Data(): bigint {
|
|
288
305
|
try {
|
|
289
|
-
const
|
|
306
|
+
const result = this.view.getBigInt64(this.offset);
|
|
290
307
|
this.offset += 8;
|
|
291
|
-
|
|
308
|
+
return result;
|
|
292
309
|
} catch {
|
|
293
310
|
this.eof();
|
|
294
311
|
}
|
|
295
|
-
throw new Error('Unsupported type int64');
|
|
296
312
|
}
|
|
297
313
|
/** readFloat32Data */
|
|
298
314
|
private readFloat32Data(): number {
|
package/src/common/encoder.ts
CHANGED
|
@@ -96,9 +96,9 @@ export abstract class EncoderBase {
|
|
|
96
96
|
this.ensureCapacity(1);
|
|
97
97
|
this.buffer[this.length++] = constants.ARRAY_END;
|
|
98
98
|
} else if (!ArrayBuffer.isView(value)) {
|
|
99
|
-
const toJSON =
|
|
100
|
-
if (toJSON) {
|
|
101
|
-
this.write(
|
|
99
|
+
const { toJSON } = value as Record<string, unknown>;
|
|
100
|
+
if (typeof toJSON == 'function') {
|
|
101
|
+
this.write(toJSON.call(value));
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
this.ensureCapacity(1);
|
|
@@ -130,8 +130,9 @@ export abstract class EncoderBase {
|
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
const arrayLength = (value as Int16Array | Int32Array | Float32Array | Float64Array)
|
|
134
|
-
|
|
133
|
+
const arrayLength = (value as Int16Array | Int32Array | BigInt64Array | Float32Array | Float64Array)
|
|
134
|
+
.length;
|
|
135
|
+
const elementSize = (value as Int16Array | Int32Array | BigInt64Array | Float32Array | Float64Array)
|
|
135
136
|
.BYTES_PER_ELEMENT;
|
|
136
137
|
if (value instanceof Int16Array) {
|
|
137
138
|
this.buffer[this.length++] = constants.INT16;
|
|
@@ -165,6 +166,14 @@ export abstract class EncoderBase {
|
|
|
165
166
|
this.view.setFloat64(this.length, value[i]);
|
|
166
167
|
this.length += elementSize;
|
|
167
168
|
}
|
|
169
|
+
} else if (value instanceof BigInt64Array) {
|
|
170
|
+
this.buffer[this.length++] = constants.INT64;
|
|
171
|
+
this.buffer[this.length++] = constants.COUNT_MARKER;
|
|
172
|
+
this.setLength(arrayLength);
|
|
173
|
+
for (let i = 0; i < arrayLength; i++) {
|
|
174
|
+
this.view.setBigInt64(this.length, value[i]);
|
|
175
|
+
this.length += elementSize;
|
|
176
|
+
}
|
|
168
177
|
} else {
|
|
169
178
|
throw new TypeError(`Unsupported typed array type ${Object.prototype.toString.call(value)}`);
|
|
170
179
|
}
|
|
@@ -175,6 +184,21 @@ export abstract class EncoderBase {
|
|
|
175
184
|
this.ensureCapacity(1);
|
|
176
185
|
this.buffer[this.length++] = value ? constants.TRUE : constants.FALSE;
|
|
177
186
|
return;
|
|
187
|
+
case 'bigint':
|
|
188
|
+
// int32 range
|
|
189
|
+
if (value >= -2_147_483_648n && value <= 2_147_483_647n) {
|
|
190
|
+
this.write(Number(value));
|
|
191
|
+
}
|
|
192
|
+
// int64 range
|
|
193
|
+
else if (value >= -9_223_372_036_854_775_808n && value <= 9_223_372_036_854_775_807n) {
|
|
194
|
+
this.ensureCapacity(9);
|
|
195
|
+
this.buffer[this.length++] = constants.INT64;
|
|
196
|
+
this.view.setBigInt64(this.length, value);
|
|
197
|
+
this.length += 8;
|
|
198
|
+
} else {
|
|
199
|
+
throw new RangeError(`BigInt value out of range: ${value}`);
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
178
202
|
default:
|
|
179
203
|
throw new Error(`Unsupported type ${Object.prototype.toString.call(value)}`);
|
|
180
204
|
}
|
package/src/decoder.ts
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { DecoderBase } from './common/decoder.js';
|
|
2
|
+
export type { DecoderOptions } from './common/decoder.js';
|
|
3
|
+
|
|
4
|
+
/** 解码 UBJSON */
|
|
5
|
+
export class Decoder extends DecoderBase {
|
|
6
|
+
/** 读取完毕 */
|
|
7
|
+
get ended(): boolean {
|
|
8
|
+
return this.offset >= this.data.byteLength;
|
|
9
|
+
}
|
|
10
|
+
}
|
package/src/encoder.ts
CHANGED
|
@@ -45,11 +45,10 @@ export class Encoder extends EncoderBase {
|
|
|
45
45
|
this.length = 0;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
this.allocUnsafe(BLOCK_SIZE);
|
|
51
|
-
this.writeValue(value);
|
|
48
|
+
/** 获取结果 */
|
|
49
|
+
private getResult(): Uint8Array {
|
|
52
50
|
if (this.flushedBuffers.length === 0) {
|
|
51
|
+
// 缓冲区为空,复制当前 buffer
|
|
53
52
|
return this.buffer.slice(0, this.length);
|
|
54
53
|
}
|
|
55
54
|
|
|
@@ -65,6 +64,37 @@ export class Encoder extends EncoderBase {
|
|
|
65
64
|
result.set(this.buffer.subarray(0, this.length), offset);
|
|
66
65
|
return result;
|
|
67
66
|
}
|
|
67
|
+
|
|
68
|
+
/** 抛弃结果 */
|
|
69
|
+
private cleanResult(): void {
|
|
70
|
+
this.flushedBuffers.splice(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 获取写入结果 */
|
|
74
|
+
encode(value: unknown): Uint8Array {
|
|
75
|
+
try {
|
|
76
|
+
this.allocUnsafe(BLOCK_SIZE);
|
|
77
|
+
this.writeValue(value);
|
|
78
|
+
return this.getResult();
|
|
79
|
+
} catch (e) {
|
|
80
|
+
this.cleanResult();
|
|
81
|
+
throw e;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 获取写入结果 */
|
|
86
|
+
encodeMany(value: Iterable<unknown>): Uint8Array {
|
|
87
|
+
try {
|
|
88
|
+
this.allocUnsafe(BLOCK_SIZE);
|
|
89
|
+
for (const v of value) {
|
|
90
|
+
this.writeValue(v);
|
|
91
|
+
}
|
|
92
|
+
return this.getResult();
|
|
93
|
+
} catch (e) {
|
|
94
|
+
this.cleanResult();
|
|
95
|
+
throw e;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
68
98
|
}
|
|
69
99
|
|
|
70
100
|
let _ENCODER: Encoder | undefined;
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { getEncoder } from './encoder.js';
|
|
2
|
-
import { Decoder } from './decoder.js';
|
|
2
|
+
import { Decoder, type DecoderOptions } from './decoder.js';
|
|
3
3
|
export { UnexpectedEof } from './utils.js';
|
|
4
4
|
|
|
5
|
+
export type { DecoderOptions };
|
|
6
|
+
|
|
5
7
|
/** 编码为 UBJSON */
|
|
6
8
|
export function encode(value: unknown): Uint8Array {
|
|
7
9
|
return getEncoder().encode(value);
|
|
8
10
|
}
|
|
9
11
|
|
|
12
|
+
/** 编码为 UBJSON */
|
|
13
|
+
export function encodeMany(value: Iterable<unknown>): Uint8Array {
|
|
14
|
+
return getEncoder().encodeMany(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
10
17
|
/** 解码 UBJSON */
|
|
11
|
-
export function decode(value: BinaryData): unknown {
|
|
12
|
-
const decoder = new Decoder(value);
|
|
18
|
+
export function decode(value: BinaryData, options?: DecoderOptions): unknown {
|
|
19
|
+
const decoder = new Decoder(value, options);
|
|
13
20
|
return decoder.decode();
|
|
14
21
|
}
|
|
22
|
+
|
|
23
|
+
/** 解码 UBJSON */
|
|
24
|
+
export function* decodeMany(value: BinaryData, options?: DecoderOptions): Iterable<unknown> {
|
|
25
|
+
const decoder = new Decoder(value, options);
|
|
26
|
+
while (!decoder.ended) {
|
|
27
|
+
yield decoder.decode();
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/stream/index.ts
CHANGED
|
@@ -14,6 +14,22 @@ export function encode(value: unknown): Readable {
|
|
|
14
14
|
encoder.end();
|
|
15
15
|
return encoder;
|
|
16
16
|
}
|
|
17
|
+
/** 编码为 UBJSON */
|
|
18
|
+
export function encodeMany(value: AsyncIterable<unknown>): Readable {
|
|
19
|
+
const encoder = new StreamEncoder();
|
|
20
|
+
void (async () => {
|
|
21
|
+
try {
|
|
22
|
+
for await (const v of value) {
|
|
23
|
+
if (v == null) encoder.write(undefined);
|
|
24
|
+
else encoder.write(v);
|
|
25
|
+
}
|
|
26
|
+
encoder.end();
|
|
27
|
+
} catch (ex) {
|
|
28
|
+
encoder.destroy(ex as Error);
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
return encoder;
|
|
32
|
+
}
|
|
17
33
|
|
|
18
34
|
/** 编码为 UBJSON */
|
|
19
35
|
export function encoder(): Transform {
|
|
@@ -31,6 +47,12 @@ export function decode(stream: NodeJS.ReadableStream): Promise<unknown> {
|
|
|
31
47
|
});
|
|
32
48
|
}
|
|
33
49
|
|
|
50
|
+
/** 解码 UBJSON */
|
|
51
|
+
export function decodeMany(stream: NodeJS.ReadableStream): AsyncIterable<unknown> {
|
|
52
|
+
const decoder = new StreamDecoder();
|
|
53
|
+
return stream.pipe(decoder);
|
|
54
|
+
}
|
|
55
|
+
|
|
34
56
|
/** 解码 UBJSON */
|
|
35
57
|
export function decoder(): Transform {
|
|
36
58
|
return new StreamDecoder();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DecoderBase } from '../common/decoder.js';
|
|
2
2
|
|
|
3
3
|
/** 未结束的流 */
|
|
4
4
|
export const kEof = Symbol('EOF');
|
|
5
5
|
|
|
6
6
|
/** 流式解码 UBJSON */
|
|
7
|
-
export class StreamDecoderHelper extends
|
|
7
|
+
export class StreamDecoderHelper extends DecoderBase {
|
|
8
8
|
constructor(data: Uint8Array) {
|
|
9
9
|
super(data);
|
|
10
10
|
}
|
package/tests/decode.js
CHANGED
|
@@ -54,8 +54,9 @@ test('decode int32', () => {
|
|
|
54
54
|
expect(decode(toBuffer('l', 0x12, 0x34, 0x56, 0x78))).toBe(0x1234_5678);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
test('decode int64
|
|
58
|
-
expect(
|
|
57
|
+
test('decode int64', () => {
|
|
58
|
+
expect(decode(toBuffer('L', 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0))).toBe(0x1234_5678_9abc_def0n);
|
|
59
|
+
expect(decode(toBuffer('L', 0x00, 0x04, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0))).toBe(0x04_5678_9abc_def0);
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
test('decode float32', () => {
|
|
@@ -156,9 +157,10 @@ test('decode huge string', () => {
|
|
|
156
157
|
expect(decode(toBuffer('S', 'l', 0x00, 0x00, 0x00, 6, 'u', 'b', 'j', 's', 'o', 'n'))).toBe('ubjson');
|
|
157
158
|
});
|
|
158
159
|
|
|
159
|
-
test('decode huge string [
|
|
160
|
-
expect(
|
|
161
|
-
|
|
160
|
+
test('decode huge string [int64 length]', () => {
|
|
161
|
+
expect(decode(toBuffer('S', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).toBe('x');
|
|
162
|
+
expect(() => decode(toBuffer('S', 'L', 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).toThrow(
|
|
163
|
+
/Invalid length/,
|
|
162
164
|
);
|
|
163
165
|
});
|
|
164
166
|
|
|
@@ -200,6 +202,24 @@ test('decode N-D array (strongly typed, optimized)', () => {
|
|
|
200
202
|
).toEqual([new Int8Array([1, 2, 3]), new Int8Array([4, 5, 6])]);
|
|
201
203
|
});
|
|
202
204
|
|
|
205
|
+
test('decode N-D array (strongly typed, optimized, no alloc buffer)', () => {
|
|
206
|
+
const buf = toBuffer('[', '$', '[', '#', 'i', 2, '$', 'i', '#', 'i', 3, 1, 2, 3, '$', 'U', '#', 'U', 3, 4, 5, 6);
|
|
207
|
+
|
|
208
|
+
const decoded1 = /** @type {[Int8Array, Uint8Array]} */ (decode(buf));
|
|
209
|
+
const decoded2 = /** @type {[Int8Array, Uint8Array]} */ (decode(buf, { noAllocBuffer: true }));
|
|
210
|
+
// @ts-expect-error Falsy value
|
|
211
|
+
const decoded3 = /** @type {[Int8Array, Uint8Array]} */ (decode(buf, { noAllocBuffer: 0 }));
|
|
212
|
+
expect(decoded1).toEqual([new Int8Array([1, 2, 3]), new Uint8Array([4, 5, 6])]);
|
|
213
|
+
expect(decoded2).toEqual([new Int8Array([1, 2, 3]), new Uint8Array([4, 5, 6])]);
|
|
214
|
+
expect(decoded3).toEqual([new Int8Array([1, 2, 3]), new Uint8Array([4, 5, 6])]);
|
|
215
|
+
expect(decoded1[0].buffer).not.toBe(buf.buffer);
|
|
216
|
+
expect(decoded1[1].buffer).not.toBe(buf.buffer);
|
|
217
|
+
expect(decoded2[0].buffer).not.toBe(buf.buffer);
|
|
218
|
+
expect(decoded2[1].buffer).toBe(buf.buffer);
|
|
219
|
+
expect(decoded3[0].buffer).not.toBe(buf.buffer);
|
|
220
|
+
expect(decoded3[1].buffer).not.toBe(buf.buffer);
|
|
221
|
+
});
|
|
222
|
+
|
|
203
223
|
test('decode array of objects (optimized)', () => {
|
|
204
224
|
expect(
|
|
205
225
|
decode(
|
|
@@ -389,13 +409,13 @@ test('decode array (int32, strongly typed, optimized) [use typed array]', () =>
|
|
|
389
409
|
});
|
|
390
410
|
|
|
391
411
|
test('decode array (int64, strongly typed, optimized) [use typed array]', () => {
|
|
392
|
-
expect(()
|
|
393
|
-
|
|
394
|
-
)
|
|
412
|
+
expect(decode(toBuffer('[', '$', 'L', '#', 'i', 1, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98))).toEqual(
|
|
413
|
+
new BigInt64Array([0x1234_5678_fedc_ba98n]),
|
|
414
|
+
);
|
|
395
415
|
});
|
|
396
416
|
|
|
397
417
|
test('decode array (int64, strongly typed, optimized, empty) [use typed array]', () => {
|
|
398
|
-
expect(
|
|
418
|
+
expect(decode(toBuffer('[', '$', 'L', '#', 'i', 0))).toEqual(new BigInt64Array([]));
|
|
399
419
|
});
|
|
400
420
|
|
|
401
421
|
test('decode array (float32, strongly typed, optimized) [use typed array]', () => {
|
|
@@ -492,3 +512,13 @@ test('decode object (empty key, optimized)', () => {
|
|
|
492
512
|
b: null,
|
|
493
513
|
});
|
|
494
514
|
});
|
|
515
|
+
|
|
516
|
+
test('decode (eof at marker)', () => {
|
|
517
|
+
expect(() => decode(toBuffer('i'))).toThrow(UnexpectedEof);
|
|
518
|
+
expect(() => decode(toBuffer('{'))).toThrow(UnexpectedEof);
|
|
519
|
+
expect(() => decode(toBuffer('{', 'i', 1, 'a'))).toThrow(UnexpectedEof);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
test('decode (eof at key)', () => {
|
|
523
|
+
expect(() => decode(toBuffer('{', 'i', 2, 'a'))).toThrow(UnexpectedEof);
|
|
524
|
+
});
|
package/tests/encode.js
CHANGED
|
@@ -20,7 +20,11 @@ test('encode function', () => {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
test('encode bigint', () => {
|
|
23
|
-
expect((
|
|
23
|
+
expect(toArray(encode(1n))).toEqual(toArray(encode(1)));
|
|
24
|
+
expect(toArray(encode(0x1234_5678_90ab_cdefn))).toEqual(
|
|
25
|
+
toArray('L', 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef),
|
|
26
|
+
);
|
|
27
|
+
expect(() => encode(0x8234_5678_90ab_cdefn)).toThrow(/BigInt value out of range:/);
|
|
24
28
|
// @ts-expect-error Access private property
|
|
25
29
|
expect(getEncoder().pool).toBe(poolInit);
|
|
26
30
|
});
|
|
@@ -365,7 +369,32 @@ test('encode array (uint64 typed array)', () => {
|
|
|
365
369
|
});
|
|
366
370
|
|
|
367
371
|
test('encode array (int64 typed array)', () => {
|
|
368
|
-
expect((
|
|
372
|
+
expect(toArray(encode(new BigInt64Array([1n, 0x1234_5678_1234_5678n])))).toEqual(
|
|
373
|
+
toArray(
|
|
374
|
+
'[',
|
|
375
|
+
'$',
|
|
376
|
+
'L',
|
|
377
|
+
'#',
|
|
378
|
+
'i',
|
|
379
|
+
2,
|
|
380
|
+
0x00,
|
|
381
|
+
0x00,
|
|
382
|
+
0x00,
|
|
383
|
+
0x00,
|
|
384
|
+
0x00,
|
|
385
|
+
0x00,
|
|
386
|
+
0x00,
|
|
387
|
+
0x01,
|
|
388
|
+
0x12,
|
|
389
|
+
0x34,
|
|
390
|
+
0x56,
|
|
391
|
+
0x78,
|
|
392
|
+
0x12,
|
|
393
|
+
0x34,
|
|
394
|
+
0x56,
|
|
395
|
+
0x78,
|
|
396
|
+
),
|
|
397
|
+
);
|
|
369
398
|
// @ts-expect-error Access private property
|
|
370
399
|
expect(getEncoder().pool).toBe(poolInit);
|
|
371
400
|
});
|
package/tests/many.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { encodeMany, decodeMany } from '../dist/index.js';
|
|
2
|
+
|
|
3
|
+
test('encode/decode many', () => {
|
|
4
|
+
const data = [
|
|
5
|
+
{
|
|
6
|
+
a: 1,
|
|
7
|
+
b: 2,
|
|
8
|
+
c: 3,
|
|
9
|
+
d: 4,
|
|
10
|
+
e: 5,
|
|
11
|
+
},
|
|
12
|
+
1,
|
|
13
|
+
null,
|
|
14
|
+
'x',
|
|
15
|
+
true,
|
|
16
|
+
[1, 2, 3],
|
|
17
|
+
Uint8Array.of(3, 3, 1),
|
|
18
|
+
];
|
|
19
|
+
const encoded = encodeMany(data);
|
|
20
|
+
const decoded = [...decodeMany(encoded)];
|
|
21
|
+
expect(decoded).toEqual(data);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('encode/decode many with error', () => {
|
|
25
|
+
expect(() =>
|
|
26
|
+
encodeMany(
|
|
27
|
+
(function* () {
|
|
28
|
+
yield 1;
|
|
29
|
+
throw new Error('xx');
|
|
30
|
+
})(),
|
|
31
|
+
),
|
|
32
|
+
).toThrow('xx');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('encode/decode many with invalid value', () => {
|
|
36
|
+
expect(() => encodeMany([1, () => 1])).toThrow();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('encode/decode many with undefined', () => {
|
|
40
|
+
const data = [1, null, undefined, [undefined]];
|
|
41
|
+
const encoded = encodeMany(data);
|
|
42
|
+
const decoded = [...decodeMany(encoded)];
|
|
43
|
+
expect(decoded).toEqual([1, null, [null]]);
|
|
44
|
+
});
|
package/tests/rxjs/decode.js
CHANGED
|
@@ -77,8 +77,9 @@ test('decode int32', async () => {
|
|
|
77
77
|
expect(await decode(toBuffer('l', 0x12, 0x34, 0x56, 0x78))).toBe(0x1234_5678);
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
test('decode int64
|
|
81
|
-
|
|
80
|
+
test('decode int64', async () => {
|
|
81
|
+
expect(await decode(toBuffer('L', 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0))).toBe(0x1234_5678_9abc_def0n);
|
|
82
|
+
expect(await decode(toBuffer('L', 0x00, 0x00, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0))).toBe(0x5678_9abc_def0);
|
|
82
83
|
});
|
|
83
84
|
|
|
84
85
|
test('decode float32', async () => {
|
|
@@ -140,9 +141,10 @@ test('decode huge string', async () => {
|
|
|
140
141
|
expect(await decode(toBuffer('S', 'l', 0x00, 0x00, 0x00, 6, 'u', 'b', 'j', 's', 'o', 'n'))).toBe('ubjson');
|
|
141
142
|
});
|
|
142
143
|
|
|
143
|
-
test('decode huge string [
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
test('decode huge string [int64 length]', async () => {
|
|
145
|
+
expect(await decode(toBuffer('S', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).toBe('x');
|
|
146
|
+
await expect(() => decode(toBuffer('S', 'L', 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).rejects.toThrow(
|
|
147
|
+
/Invalid length/,
|
|
146
148
|
);
|
|
147
149
|
});
|
|
148
150
|
|
|
@@ -359,9 +361,9 @@ test('decode array (int32, strongly typed, optimized) [use typed array]', async
|
|
|
359
361
|
});
|
|
360
362
|
|
|
361
363
|
test('decode array (int64, strongly typed, optimized) [use typed array]', async () => {
|
|
362
|
-
await
|
|
363
|
-
|
|
364
|
-
)
|
|
364
|
+
expect(await decode(toBuffer('[', '$', 'L', '#', 'i', 1, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98))).toEqual(
|
|
365
|
+
new BigInt64Array([0x1234_5678_fedc_ba98n]),
|
|
366
|
+
);
|
|
365
367
|
});
|
|
366
368
|
|
|
367
369
|
test('decode array (float32, strongly typed, optimized) [use typed array]', async () => {
|
package/tests/rxjs/encode.js
CHANGED
|
@@ -28,7 +28,11 @@ test('encode function', async () => {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test('encode bigint', async () => {
|
|
31
|
-
|
|
31
|
+
expect(toArray(await encodeAsync(1n))).toEqual(toArray('U', 1));
|
|
32
|
+
expect(toArray(await encodeAsync(0x1876_9876_1234_1234n))).toEqual(
|
|
33
|
+
toArray('L', 0x18, 0x76, 0x98, 0x76, 0x12, 0x34, 0x12, 0x34),
|
|
34
|
+
);
|
|
35
|
+
await expect(encodeAsync(0x8234_5678_90ab_cdefn)).rejects.toThrow(/BigInt value out of range:/);
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
test('encode symbol', async () => {
|
|
@@ -268,7 +272,7 @@ test('encode array (uint64 typed array)', async () => {
|
|
|
268
272
|
});
|
|
269
273
|
|
|
270
274
|
test('encode array (int64 typed array)', async () => {
|
|
271
|
-
|
|
275
|
+
expect(toArray(await encodeAsync(new BigInt64Array()))).toEqual(toArray('[', '$', 'L', '#', 'i', 0));
|
|
272
276
|
});
|
|
273
277
|
|
|
274
278
|
test('encode object', async () => {
|
package/tests/stream/decode.js
CHANGED
|
@@ -72,8 +72,9 @@ test('decode int32', async () => {
|
|
|
72
72
|
expect(await decode(toBuffer('l', 0x12, 0x34, 0x56, 0x78))).toBe(0x1234_5678);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
test('decode int64
|
|
76
|
-
|
|
75
|
+
test('decode int64', async () => {
|
|
76
|
+
expect(await decode(toBuffer('L', 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0))).toBe(0x1234_5678_9abc_def0n);
|
|
77
|
+
expect(await decode(toBuffer('L', 0x00, 0x04, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0))).toBe(0x04_5678_9abc_def0);
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
test('decode float32', async () => {
|
|
@@ -126,9 +127,10 @@ test('decode huge string', async () => {
|
|
|
126
127
|
expect(await decode(toBuffer('S', 'l', 0x00, 0x00, 0x00, 6, 'u', 'b', 'j', 's', 'o', 'n'))).toBe('ubjson');
|
|
127
128
|
});
|
|
128
129
|
|
|
129
|
-
test('decode huge string [
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
test('decode huge string [int64 length]', async () => {
|
|
131
|
+
expect(await decode(toBuffer('S', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).toBe('x');
|
|
132
|
+
await expect(() => decode(toBuffer('S', 'L', 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).rejects.toThrow(
|
|
133
|
+
/Invalid length/,
|
|
132
134
|
);
|
|
133
135
|
});
|
|
134
136
|
|
|
@@ -345,9 +347,9 @@ test('decode array (int32, strongly typed, optimized) [use typed array]', async
|
|
|
345
347
|
});
|
|
346
348
|
|
|
347
349
|
test('decode array (int64, strongly typed, optimized) [use typed array]', async () => {
|
|
348
|
-
await
|
|
349
|
-
|
|
350
|
-
)
|
|
350
|
+
expect(await decode(toBuffer('[', '$', 'L', '#', 'i', 1, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98))).toEqual(
|
|
351
|
+
new BigInt64Array([0x1234_5678_fedc_ba98n]),
|
|
352
|
+
);
|
|
351
353
|
});
|
|
352
354
|
|
|
353
355
|
test('decode array (float32, strongly typed, optimized) [use typed array]', async () => {
|
package/tests/stream/encode.js
CHANGED
|
@@ -23,7 +23,11 @@ test('encode function', async () => {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test('encode bigint', async () => {
|
|
26
|
-
|
|
26
|
+
expect(toArray(await encodeAsync(1n))).toEqual(toArray('U', 1));
|
|
27
|
+
expect(toArray(await encodeAsync(0x1234_5678_8765_4321n))).toEqual(
|
|
28
|
+
toArray('L', 0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21),
|
|
29
|
+
);
|
|
30
|
+
await expect(encodeAsync(0x8234_5678_90ab_cdefn)).rejects.toThrow(/BigInt value out of range:/);
|
|
27
31
|
});
|
|
28
32
|
|
|
29
33
|
test('encode symbol', async () => {
|
|
@@ -263,7 +267,7 @@ test('encode array (uint64 typed array)', async () => {
|
|
|
263
267
|
});
|
|
264
268
|
|
|
265
269
|
test('encode array (int64 typed array)', async () => {
|
|
266
|
-
|
|
270
|
+
expect(toArray(await encodeAsync(new BigInt64Array()))).toEqual(toArray('[', '$', 'L', '#', 'i', 0));
|
|
267
271
|
});
|
|
268
272
|
|
|
269
273
|
test('encode object', async () => {
|