Skip to content

Commit 6be5c9c

Browse files
committed
refacor encode.ts to dispatch typeof map
this is to easily analyze profiling results
1 parent 6be9578 commit 6be5c9c

File tree

2 files changed

+58
-41
lines changed

2 files changed

+58
-41
lines changed

src/encode.ts

Lines changed: 58 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { utf8Encode } from "./utils/uf8Encode";
22
import { ExtensionCodec, ExtensionCodecType } from "./ExtensionCodec";
33
import { encodeUint32, encodeInt64, encodeInt32, encodeUint64 } from "./utils/int";
4-
import { isObject, isNodeJsBuffer } from "./utils/is";
4+
import { isNodeJsBuffer } from "./utils/is";
55
import { Writable } from "./utils/Writable";
66

77
export type EncodeOptions = Readonly<{
@@ -23,45 +23,44 @@ export function encode(value: unknown, options: Partial<EncodeOptions> = {}): Ar
2323
return output;
2424
}
2525

26-
export class Encoder {
26+
export class Encoder<OutputType extends Writable<number>> {
27+
readonly typeofMap = {
28+
"undefined": this.encodeNil,
29+
"boolean": this.encodeBoolean,
30+
"number": this.encodeNumber,
31+
"bigint": this.encodeBigInt,
32+
"string": this.encodeString,
33+
"object": this.encodeObject,
34+
} as Record<string, (this: Encoder<OutputType>, rv: OutputType, object: unknown, depth: number) => void>;
35+
2736
constructor(readonly maxDepth: number, readonly extensionCodec: ExtensionCodecType) {}
2837

29-
encode<OutputType extends Writable<number>>(rv: OutputType, object: unknown, depth: number): void {
38+
encode(rv: OutputType, object: unknown, depth: number): void {
3039
if (depth > this.maxDepth) {
3140
throw new Error(`Too deep objects in depth ${depth}`);
3241
}
3342

34-
if (object == null) {
35-
rv.push(0xc0);
36-
} else if (object === false) {
43+
const encodeFunc = this.typeofMap[typeof object];
44+
if (!encodeFunc) {
45+
throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);
46+
}
47+
48+
encodeFunc.call(this, rv, object, depth);
49+
}
50+
51+
encodeNil(rv: OutputType) {
52+
rv.push(0xc0);
53+
}
54+
55+
encodeBoolean(rv: OutputType, object: boolean) {
56+
if (object === false) {
3757
rv.push(0xc2);
38-
} else if (object === true) {
39-
rv.push(0xc3);
40-
} else if (typeof object === "number") {
41-
this.encodeNumber(rv, object);
42-
} else if (typeof object === "string") {
43-
this.encodeString(rv, object);
4458
} else {
45-
// try to encode objects with custom codec first of non-primitives
46-
const ext = this.extensionCodec.tryToEncode(object);
47-
if (ext != null) {
48-
this.encodeExtension(rv, ext);
49-
} else if (ArrayBuffer.isView(object)) {
50-
this.encodeBinary(rv, object);
51-
} else if (Array.isArray(object)) {
52-
this.encodeArray(rv, object, depth);
53-
} else if (isObject(object)) {
54-
this.encodeMap(rv, object, depth);
55-
} else {
56-
// not encodable unless ExtensionCodec handles it,
57-
// for example Symbol, Function, and so on.
58-
// Note that some objects, for example Symbol, throws errors by its own toString() method
59-
throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);
60-
}
59+
rv.push(0xc3);
6160
}
6261
}
6362

64-
encodeNumber<OutputType extends Writable<number>>(rv: OutputType, object: number) {
63+
encodeNumber(rv: OutputType, object: number) {
6564
if (Number.isSafeInteger(object)) {
6665
if (object >= 0) {
6766
if (object < 0x80) {
@@ -133,7 +132,12 @@ export class Encoder {
133132
}
134133
}
135134

136-
encodeString<OutputType extends Writable<number>>(rv: OutputType, object: string) {
135+
encodeBigInt(_rv: OutputType, _object: bigint) {
136+
// BigInt literals is not available here!
137+
throw new Error("BigInt is not yet implemented!");
138+
}
139+
140+
encodeString(rv: OutputType, object: string) {
137141
const bytes = utf8Encode(object);
138142
const size = bytes.length;
139143
if (size < 32) {
@@ -152,10 +156,30 @@ export class Encoder {
152156
} else {
153157
throw new Error(`Too long string: ${size} bytes in UTF-8`);
154158
}
159+
155160
rv.push(...bytes);
156161
}
157162

158-
encodeBinary<OutputType extends Writable<number>>(rv: OutputType, object: ArrayBufferView) {
163+
encodeObject(rv: OutputType, object: object | null, depth: number) {
164+
if (object === null) {
165+
this.encodeNil(rv);
166+
return;
167+
}
168+
169+
// try to encode objects with custom codec first of non-primitives
170+
const ext = this.extensionCodec.tryToEncode(object);
171+
if (ext != null) {
172+
this.encodeExtension(rv, ext);
173+
} else if (ArrayBuffer.isView(object)) {
174+
this.encodeBinary(rv, object);
175+
} else if (Array.isArray(object)) {
176+
this.encodeArray(rv, object, depth);
177+
} else {
178+
this.encodeMap(rv, object as Record<string, unknown>, depth);
179+
}
180+
}
181+
182+
encodeBinary(rv: OutputType, object: ArrayBufferView) {
159183
const size = object.byteLength;
160184
if (size < 0x100) {
161185
// bin 8
@@ -176,7 +200,7 @@ export class Encoder {
176200
}
177201
}
178202

179-
encodeArray<OutputType extends Writable<number>>(rv: OutputType, object: Array<unknown>, depth: number) {
203+
encodeArray(rv: OutputType, object: Array<unknown>, depth: number) {
180204
const size = object.length;
181205
if (size < 16) {
182206
// fixarray
@@ -196,7 +220,7 @@ export class Encoder {
196220
}
197221
}
198222

199-
encodeMap<OutputType extends Writable<number>>(rv: OutputType, object: Record<string, unknown>, depth: number) {
223+
encodeMap(rv: OutputType, object: Record<string, unknown>, depth: number) {
200224
const keys = Object.keys(object);
201225
const size = keys.length;
202226
// map
@@ -217,10 +241,7 @@ export class Encoder {
217241
}
218242
}
219243

220-
encodeExtension<OutputType extends Writable<number>>(
221-
rv: OutputType,
222-
ext: { type: number; data: ReadonlyArray<number> },
223-
) {
244+
encodeExtension(rv: OutputType, ext: { type: number; data: ReadonlyArray<number> }) {
224245
const size = ext.data.length;
225246
const typeByte = ext.type < 0 ? ext.type + 0x100 : ext.type;
226247
if (size === 1) {

src/utils/is.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11

2-
export function isObject(object: unknown): object is Record<string, unknown> {
3-
return typeof object === "object" && object !== null;
4-
}
5-
62
export function isNodeJsBuffer(object: unknown): object is Buffer {
73
return typeof Buffer !== "undefined" && Buffer.isBuffer(object);
84
}

0 commit comments

Comments
 (0)