Skip to content

Commit ac2529e

Browse files
committed
make Encoder to handle bigint with ExtensionCodec
1 parent 2c660a0 commit ac2529e

File tree

3 files changed

+81
-15
lines changed

3 files changed

+81
-15
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,37 @@ const decoded = decode(encoded, { extensionCodec });
106106

107107
Not that extension types for custom objects must be `[0, 127]`, while `[-1, -128]` is reserved for MessagePack itself.
108108

109+
#### Handling BigInt with ExtensionCodec
110+
111+
This library does not handle BigInt by default, but you can handle it with `ExtensionCodec` like this:
112+
113+
```typescript
114+
import { deepStrictEqual } from "assert";
115+
import { encode, decode, ExtensionCodec } from "../src";
116+
117+
const BIGINT_EXT_TYPE = 0; // Any in 0-127
118+
119+
const extensionCodec = new ExtensionCodec();
120+
extensionCodec.register({
121+
type: BIGINT_EXT_TYPE,
122+
encode: (input: unknown) => {
123+
// eslint-disable-next-line valid-typeof
124+
if (typeof input === "bigint") {
125+
return encode(input.toString());
126+
} else {
127+
return null;
128+
}
129+
},
130+
decode: (data: Uint8Array) => {
131+
return BigInt(decode(data));
132+
},
133+
});
134+
135+
const value = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
136+
const encoded: = encode(value, { extensionCodec });
137+
deepStrictEqual(decode(encoded, { extensionCodec }), value);
138+
```
139+
109140
### MessagePack Mapping Table
110141

111142
The following table shows how JavaScript values are mapped to [MessagePack formats](https://github.com/msgpack/msgpack/blob/master/spec.md) and vice versa.

src/Encoder.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,10 @@ export class Encoder {
2222
this.encodeBoolean(object);
2323
} else if (typeof object === "number") {
2424
this.encodeNumber(object);
25-
26-
// eslint-disable-next-line valid-typeof
27-
} else if (typeof object === "bigint") {
28-
this.encodeBigInt(object);
2925
} else if (typeof object === "string") {
3026
this.encodeString(object);
31-
} else if (typeof object === "object") {
32-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
33-
this.encodeObject(object!, depth);
3427
} else {
35-
throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);
28+
this.encodeObject(object, depth);
3629
}
3730
}
3831

@@ -118,11 +111,6 @@ export class Encoder {
118111
}
119112
}
120113

121-
encodeBigInt(_object: bigint) {
122-
// BigInt literals is not available here!
123-
throw new Error("BigInt is not yet implemented!");
124-
}
125-
126114
encodeString(object: string) {
127115
const byteLength = utf8Count(object);
128116
if (byteLength < 32) {
@@ -149,7 +137,7 @@ export class Encoder {
149137
this.pos += byteLength;
150138
}
151139

152-
encodeObject(object: object, depth: number) {
140+
encodeObject(object: unknown, depth: number) {
153141
// try to encode objects with custom codec first of non-primitives
154142
const ext = this.extensionCodec.tryToEncode(object);
155143
if (ext != null) {
@@ -158,8 +146,11 @@ export class Encoder {
158146
this.encodeBinary(object);
159147
} else if (Array.isArray(object)) {
160148
this.encodeArray(object, depth);
161-
} else {
149+
} else if (typeof object === "object") {
162150
this.encodeMap(object as Record<string, unknown>, depth);
151+
} else {
152+
// symbol, function and other special object come here unless extensionCodec handles them.
153+
throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);
163154
}
164155
}
165156

test/codec-bigint.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import assert from "assert";
2+
import { encode, decode, ExtensionCodec } from "../src";
3+
4+
const extensionCodec = new ExtensionCodec();
5+
extensionCodec.register({
6+
type: 0,
7+
encode: (input: unknown) => {
8+
// eslint-disable-next-line valid-typeof
9+
if (typeof input === "bigint") {
10+
return encode(input.toString());
11+
} else {
12+
return null;
13+
}
14+
},
15+
decode: (data: Uint8Array) => {
16+
return BigInt(decode(data));
17+
},
18+
});
19+
20+
describe("codec BigInt", () => {
21+
before(function() {
22+
if (typeof BigInt === "undefined") {
23+
this.skip();
24+
}
25+
});
26+
27+
it("encodes and decodes 0n", () => {
28+
const value = BigInt(0);
29+
const encoded = encode(value, { extensionCodec });
30+
assert.deepStrictEqual(decode(encoded, { extensionCodec }), value);
31+
});
32+
33+
it("encodes and decodes MAX_SAFE_INTEGER+1", () => {
34+
const value = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
35+
const encoded = encode(value, { extensionCodec });
36+
assert.deepStrictEqual(decode(encoded, { extensionCodec }), value);
37+
});
38+
39+
it("encodes and decodes MIN_SAFE_INTEGER-1", () => {
40+
const value = BigInt(Number.MIN_SAFE_INTEGER) - BigInt(1);
41+
const encoded = encode(value, { extensionCodec });
42+
assert.deepStrictEqual(decode(encoded, { extensionCodec }), value);
43+
});
44+
});

0 commit comments

Comments
 (0)