Skip to content

Commit 754edeb

Browse files
committed
update readme
1 parent 8cafd86 commit 754edeb

File tree

3 files changed

+64
-33
lines changed

3 files changed

+64
-33
lines changed

.vscode/settings.json

+2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"source.fixAll.eslint": true
77
},
88
"cSpell.words": [
9+
"instanceof",
910
"tsdoc",
11+
"typeof",
1012
"whatwg"
1113
]
1214
}

README.md

+41-20
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,14 @@ console.log(buffer);
112112
Name|Type|Default
113113
----|----|----
114114
extensionCodec | ExtensionCodec | `ExtensionCodec.defaultCodec`
115+
context | user-defined | -
116+
useBigInt64 | boolean | false
115117
maxDepth | number | `100`
116118
initialBufferSize | number | `2048`
117119
sortKeys | boolean | false
118120
forceFloat32 | boolean | false
119121
forceIntegerToFloat | boolean | false
120122
ignoreUndefined | boolean | false
121-
context | user-defined | -
122123

123124
### `decode(buffer: ArrayLike<number> | BufferSource, options?: DecoderOptions): unknown`
124125

@@ -145,12 +146,13 @@ NodeJS `Buffer` is also acceptable because it is a subclass of `Uint8Array`.
145146
Name|Type|Default
146147
----|----|----
147148
extensionCodec | ExtensionCodec | `ExtensionCodec.defaultCodec`
149+
context | user-defined | -
150+
useBigInt64 | boolean | false
148151
maxStrLength | number | `4_294_967_295` (UINT32_MAX)
149152
maxBinLength | number | `4_294_967_295` (UINT32_MAX)
150153
maxArrayLength | number | `4_294_967_295` (UINT32_MAX)
151154
maxMapLength | number | `4_294_967_295` (UINT32_MAX)
152155
maxExtLength | number | `4_294_967_295` (UINT32_MAX)
153-
context | user-defined | -
154156

155157
You can use `max${Type}Length` to limit the length of each type decoded.
156158

@@ -350,32 +352,48 @@ const decoded = decode(encoded, { extensionCodec, context });
350352

351353
#### Handling BigInt with ExtensionCodec
352354

353-
This library does not handle BigInt by default, but you can handle it with `ExtensionCodec` like this:
355+
This library does not handle BigInt by default, but you have two options to handle it:
356+
357+
* Set `useBigInt64: true` to map bigint to MessagePack's int64/uint64
358+
* Define a custom `ExtensionCodec` to map bigint to a MessagePack's extension type
359+
360+
`useBigInt64: true` is the simplest way to handle bigint, but it has limitations:
361+
362+
* A bigint is encoded in 8 byte binaries even if it's a small integer
363+
* A bigint must be smaller than the max value of the uint64 and larger than the min value of the int64. Otherwise the behavior is undefined.
364+
365+
So you might want to define a custom codec to handle bigint like this:
354366

355367
```typescript
356368
import { deepStrictEqual } from "assert";
357369
import { encode, decode, ExtensionCodec } from "@msgpack/msgpack";
358370

371+
// to define a custom codec:
359372
const BIGINT_EXT_TYPE = 0; // Any in 0-127
360373
const extensionCodec = new ExtensionCodec();
361374
extensionCodec.register({
362-
type: BIGINT_EXT_TYPE,
363-
encode: (input: unknown) => {
364-
if (typeof input === "bigint") {
365-
if (input <= Number.MAX_SAFE_INTEGER && input >= Number.MIN_SAFE_INTEGER) {
366-
return encode(parseInt(input.toString(), 10));
367-
} else {
368-
return encode(input.toString());
369-
}
370-
} else {
371-
return null;
372-
}
373-
},
374-
decode: (data: Uint8Array) => {
375-
return BigInt(decode(data));
376-
},
375+
type: BIGINT_EXT_TYPE,
376+
encode(input: unknown): Uint8Array | null {
377+
if (typeof input === "bigint") {
378+
if (input <= Number.MAX_SAFE_INTEGER && input >= Number.MIN_SAFE_INTEGER) {
379+
return encode(Number(input));
380+
} else {
381+
return encode(String(input));
382+
}
383+
} else {
384+
return null;
385+
}
386+
},
387+
decode(data: Uint8Array): bigint {
388+
const val = decode(data);
389+
if (!(typeof val === "string" || typeof val === "number")) {
390+
throw new DecodeError(`unexpected BigInt source: ${val} (${typeof val})`);
391+
}
392+
return BigInt(val);
393+
},
377394
});
378395

396+
// to use it:
379397
const value = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
380398
const encoded: = encode(value, { extensionCodec });
381399
deepStrictEqual(decode(encoded, { extensionCodec }), value);
@@ -401,10 +419,11 @@ import {
401419
decodeTimestampToTimeSpec,
402420
} from "@msgpack/msgpack";
403421

422+
// to define a custom codec
404423
const extensionCodec = new ExtensionCodec();
405424
extensionCodec.register({
406425
type: EXT_TIMESTAMP, // override the default behavior!
407-
encode: (input: any) => {
426+
encode(input: unknown): Uint8Array | null {
408427
if (input instanceof Instant) {
409428
const sec = input.seconds;
410429
const nsec = Number(input.nanoseconds - BigInt(sec) * BigInt(1e9));
@@ -413,14 +432,15 @@ extensionCodec.register({
413432
return null;
414433
}
415434
},
416-
decode: (data: Uint8Array) => {
435+
decode(data: Uint8Array): Instant {
417436
const timeSpec = decodeTimestampToTimeSpec(data);
418437
const sec = BigInt(timeSpec.sec);
419438
const nsec = BigInt(timeSpec.nsec);
420439
return Instant.fromEpochNanoseconds(sec * BigInt(1e9) + nsec);
421440
},
422441
});
423442

443+
// to use it
424444
const instant = Instant.fromEpochMilliseconds(Date.now());
425445
const encoded = encode(instant, { extensionCodec });
426446
const decoded = decode(encoded, { extensionCodec });
@@ -518,6 +538,7 @@ This is a universal JavaScript library that supports major browsers and NodeJS.
518538
* Typed arrays (ES2015)
519539
* Async iterations (ES2018)
520540
* Features added in ES2015-ES2022
541+
* whatwg encodings (`TextEncoder` and `TextDecoder`)
521542

522543
ES2022 standard library used in this library can be polyfilled with [core-js](https://github.com/zloirock/core-js).
523544

test/codec-bigint.test.ts

+21-13
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
import assert from "assert";
22
import { encode, decode, ExtensionCodec, DecodeError } from "../src";
33

4-
// This test is provided for backward compatibility since this library now has
5-
// native bigint support with `useBigInt64: true` option.
4+
// There's a built-in `useBigInt64: true` option, but a custom codec might be
5+
// better if you'd like to encode bigint to reduce the size of binaries.
6+
7+
const BIGINT_EXT_TYPE = 0; // Any in 0-127
68

79
const extensionCodec = new ExtensionCodec();
810
extensionCodec.register({
9-
type: 0,
10-
encode: (input: unknown) => {
11+
type: BIGINT_EXT_TYPE,
12+
encode(input: unknown): Uint8Array | null {
1113
if (typeof input === "bigint") {
1214
if (input <= Number.MAX_SAFE_INTEGER && input >= Number.MIN_SAFE_INTEGER) {
13-
return encode(parseInt(input.toString(), 10));
15+
return encode(Number(input));
1416
} else {
15-
return encode(input.toString());
17+
return encode(String(input));
1618
}
1719
} else {
1820
return null;
1921
}
2022
},
21-
decode: (data: Uint8Array) => {
23+
decode(data: Uint8Array): bigint {
2224
const val = decode(data);
2325
if (!(typeof val === "string" || typeof val === "number")) {
2426
throw new DecodeError(`unexpected BigInt source: ${val} (${typeof val})`);
@@ -28,18 +30,24 @@ extensionCodec.register({
2830
});
2931

3032
describe("codec BigInt", () => {
31-
before(function () {
32-
if (typeof BigInt === "undefined") {
33-
this.skip();
34-
}
35-
});
36-
3733
it("encodes and decodes 0n", () => {
3834
const value = BigInt(0);
3935
const encoded = encode(value, { extensionCodec });
4036
assert.deepStrictEqual(decode(encoded, { extensionCodec }), value);
4137
});
4238

39+
it("encodes and decodes 100n", () => {
40+
const value = BigInt(100);
41+
const encoded = encode(value, { extensionCodec });
42+
assert.deepStrictEqual(decode(encoded, { extensionCodec }), value);
43+
});
44+
45+
it("encodes and decodes -100n", () => {
46+
const value = BigInt(-100);
47+
const encoded = encode(value, { extensionCodec });
48+
assert.deepStrictEqual(decode(encoded, { extensionCodec }), value);
49+
});
50+
4351
it("encodes and decodes MAX_SAFE_INTEGER+1", () => {
4452
const value = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
4553
const encoded = encode(value, { extensionCodec });

0 commit comments

Comments
 (0)