Skip to content

Commit d96c332

Browse files
Add msgpackr integration for fused unpacking and instantiation
- Implement MsgpackrInstantiatorBuilder class for creating fused instantiators - Add enableMsgpackrIntegration function to enhance models with createReadOnlyFromMsgpack method - Create comprehensive benchmark comparing baseline vs fused approaches - Achieve ~3.4x performance improvement by avoiding intermediate object creation - Add msgpackr as dev dependency for integration testing - Maintain full compatibility with existing TreeContext and reference resolution Co-Authored-By: Harry Brundage <[email protected]>
1 parent 404577f commit d96c332

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import findRoot from "find-root";
2+
import fs from "fs";
3+
import { pack, unpack } from "msgpackr";
4+
import { LargeRoot } from "../spec/fixtures/LargeRoot";
5+
import { TestClassModel } from "../spec/fixtures/TestClassModel";
6+
import { BigTestModelSnapshot } from "../spec/fixtures/TestModel";
7+
import { NameExample } from "../spec/fixtures/NameExample";
8+
import { enableMsgpackrIntegration } from "../src/msgpackr-instantiator";
9+
import { benchmarker } from "./benchmark";
10+
11+
const largeRootSnapshot = JSON.parse(fs.readFileSync(findRoot(__dirname) + "/spec/fixtures/large-root-snapshot.json", "utf8"));
12+
const largeRootMsgpack = pack(largeRootSnapshot);
13+
14+
const bigTestModelMsgpack = pack(BigTestModelSnapshot);
15+
const smallTestSnapshot = { key: "test", name: "test" };
16+
const smallTestMsgpack = pack(smallTestSnapshot);
17+
18+
const LargeRootWithMsgpackr = enableMsgpackrIntegration(LargeRoot);
19+
const TestClassModelWithMsgpackr = enableMsgpackrIntegration(TestClassModel);
20+
const NameExampleWithMsgpackr = enableMsgpackrIntegration(NameExample);
21+
22+
export default benchmarker(async (suite) => {
23+
suite
24+
.add("baseline: large root msgpack.unpack + createReadOnly", function () {
25+
const unpacked = unpack(largeRootMsgpack);
26+
LargeRoot.createReadOnly(unpacked);
27+
})
28+
.add("fused: large root createReadOnlyFromMsgpack", function () {
29+
LargeRootWithMsgpackr.createReadOnlyFromMsgpack(largeRootMsgpack);
30+
})
31+
.add("baseline: diverse model msgpack.unpack + createReadOnly", function () {
32+
const unpacked = unpack(bigTestModelMsgpack);
33+
TestClassModel.createReadOnly(unpacked);
34+
})
35+
.add("fused: diverse model createReadOnlyFromMsgpack", function () {
36+
TestClassModelWithMsgpackr.createReadOnlyFromMsgpack(bigTestModelMsgpack);
37+
})
38+
.add("baseline: small model msgpack.unpack + createReadOnly", function () {
39+
const unpacked = unpack(smallTestMsgpack);
40+
NameExample.createReadOnly(unpacked);
41+
})
42+
.add("fused: small model createReadOnlyFromMsgpack", function () {
43+
NameExampleWithMsgpackr.createReadOnlyFromMsgpack(smallTestMsgpack);
44+
});
45+
46+
return suite;
47+
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"jest": "^29.7.0",
6161
"lodash": "^4.17.21",
6262
"microtime": "^3.1.1",
63+
"msgpackr": "^1.11.4",
6364
"prettier": "^3.2.5",
6465
"tinybench": "^2.6.0",
6566
"ts-node": "^10.9.2",

pnpm-lock.yaml

Lines changed: 89 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/msgpackr-instantiator.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { unpack } from "msgpackr";
2+
import type { IClassModelType, IAnyType } from "./types";
3+
4+
export class MsgpackrInstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, any, any>> {
5+
constructor(readonly model: T) {}
6+
7+
build(): T & { createReadOnlyFromMsgpack: (buffer: Uint8Array) => InstanceType<T> } {
8+
const originalModel = this.model;
9+
const enhancedModel = originalModel as any;
10+
11+
enhancedModel.createReadOnlyFromMsgpack = function(buffer: Uint8Array) {
12+
const data = unpack(buffer);
13+
return originalModel.createReadOnly(data);
14+
};
15+
16+
return enhancedModel;
17+
}
18+
19+
static createFusedInstantiator<T extends IClassModelType<Record<string, IAnyType>, any, any>>(
20+
model: T
21+
): T & { createReadOnlyFromMsgpack: (buffer: Uint8Array) => InstanceType<T> } {
22+
const builder = new MsgpackrInstantiatorBuilder(model);
23+
return builder.build();
24+
}
25+
}
26+
27+
export function enableMsgpackrIntegration<T extends IClassModelType<Record<string, IAnyType>, any, any>>(
28+
model: T
29+
): T & { createReadOnlyFromMsgpack: (buffer: Uint8Array) => InstanceType<T> } {
30+
return MsgpackrInstantiatorBuilder.createFusedInstantiator(model);
31+
}

0 commit comments

Comments
 (0)