Skip to content

Commit

Permalink
Experiment with fast json stringify
Browse files Browse the repository at this point in the history
  • Loading branch information
DZakh committed May 11, 2024
1 parent cad31f0 commit 4fe60bf
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 57 deletions.
79 changes: 57 additions & 22 deletions packages/tests/src/benchmark/Benchmark.bs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ function run(suite) {
})).run();
}

function makeNestedTestObject() {
return (Object.freeze({
foo: 'bar',
num: 1,
bool: false,
}));
}

function makeTestObject() {
return (Object.freeze({
number: 1,
Expand All @@ -30,6 +38,16 @@ function makeTestObject() {
}));
}

function makeNestedSchema() {
return S$RescriptSchema.object(function (s) {
return {
foo: s.f("foo", S$RescriptSchema.string),
num: s.f("num", S$RescriptSchema.$$float),
bool: s.f("bool", S$RescriptSchema.bool)
};
});
}

function makeAdvancedObjectSchema() {
return S$RescriptSchema.object(function (s) {
return {
Expand Down Expand Up @@ -114,37 +132,54 @@ S$RescriptSchema.serializeWith(data, schema);

console.timeEnd("s: 3");

run(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(new (Benchmark.default.Suite)(), "Parse string", (function () {
return function () {
return S$RescriptSchema.parseAnyOrRaiseWith("Hello world!", S$RescriptSchema.string);
};
})), "Serialize string", (function () {
return function () {
return S$RescriptSchema.serializeOrRaiseWith("Hello world!", S$RescriptSchema.string);
};
})).add("Advanced object schema factory", makeAdvancedObjectSchema), "Parse advanced object", (function () {
run(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(addWithPrepare(new (Benchmark.default.Suite)(), "Parse string", (function () {
return function () {
return S$RescriptSchema.parseAnyOrRaiseWith("Hello world!", S$RescriptSchema.string);
};
})), "Serialize string", (function () {
return function () {
return S$RescriptSchema.serializeOrRaiseWith("Hello world!", S$RescriptSchema.string);
};
})).add("Advanced object schema factory", makeAdvancedObjectSchema), "Parse advanced object", (function () {
var schema = makeAdvancedObjectSchema();
var data = makeTestObject();
return function () {
return S$RescriptSchema.parseAnyOrRaiseWith(data, schema);
};
})), "Create and parse advanced object", (function () {
var data = makeTestObject();
return function () {
var schema = makeAdvancedObjectSchema();
return S$RescriptSchema.parseAnyOrRaiseWith(data, schema);
};
})), "Parse advanced strict object", (function () {
var schema = makeAdvancedStrictObjectSchema();
var data = makeTestObject();
return function () {
return S$RescriptSchema.parseAnyOrRaiseWith(data, schema);
};
})), "Serialize advanced object", (function () {
var schema = makeAdvancedObjectSchema();
var data = makeTestObject();
return function () {
return S$RescriptSchema.parseAnyOrRaiseWith(data, schema);
return S$RescriptSchema.serializeOrRaiseWith(data, schema);
};
})), "Create and parse advanced object", (function () {
var data = makeTestObject();
})), "Stringify with JSON.stringify", (function () {
var data = makeNestedTestObject();
return function () {
var schema = makeAdvancedObjectSchema();
return S$RescriptSchema.parseAnyOrRaiseWith(data, schema);
return JSON.stringify(data);
};
})), "Parse advanced strict object", (function () {
var schema = makeAdvancedStrictObjectSchema();
var data = makeTestObject();
})), "Stringify with S.serializeToJsonStringWith", (function () {
var data = makeNestedTestObject();
var schema = makeNestedSchema();
return function () {
return S$RescriptSchema.parseAnyOrRaiseWith(data, schema);
return S$RescriptSchema.serializeToJsonStringWith(data, schema, undefined);
};
})), "Serialize advanced object", (function () {
var schema = makeAdvancedObjectSchema();
var data = makeTestObject();
})), "Stringify with S.jsonString", (function () {
var data = makeNestedTestObject();
var schema = S$RescriptSchema.jsonString(makeNestedSchema(), undefined);
return function () {
return S$RescriptSchema.serializeOrRaiseWith(data, schema);
return S$RescriptSchema.serializeToUnknownWith(data, schema);
};
})));

Expand Down
40 changes: 40 additions & 0 deletions packages/tests/src/benchmark/Benchmark.res
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ module Suite = {
}
}

let makeNestedTestObject = () => {
%raw(`Object.freeze({
foo: 'bar',
num: 1,
bool: false,
})`)
}

let makeTestObject = () => {
%raw(`Object.freeze({
number: 1,
Expand All @@ -53,6 +61,15 @@ let makeTestObject = () => {
})`)
}

let makeNestedSchema = () =>
S.object(s =>
{
"foo": s.field("foo", S.string),
"num": s.field("num", S.float),
"bool": s.field("bool", S.bool),
}
)

let makeAdvancedObjectSchema = () => {
S.object(s =>
{
Expand Down Expand Up @@ -166,4 +183,27 @@ Suite.make()
data->S.serializeOrRaiseWith(schema)
}
})
// V6.2 x 277,905 ops/sec
->Suite.addWithPrepare("Stringify with JSON.stringify", () => {
let data = makeNestedTestObject()
() => {
data->Js.Json.stringifyAny
}
})
// V6.2 x 277,250 ops/sec
->Suite.addWithPrepare("Stringify with S.serializeToJsonStringWith", () => {
let data = makeNestedTestObject()
let schema = makeNestedSchema()
() => {
data->S.serializeToJsonStringWith(schema)
}
})
// V6.2 x 277,401 ops/sec
->Suite.addWithPrepare("Stringify with S.jsonString", () => {
let data = makeNestedTestObject()
let schema = S.jsonString(makeNestedSchema())
() => {
data->S.serializeToUnknownWith(schema)
}
})
->Suite.run
40 changes: 38 additions & 2 deletions packages/tests/src/core/S_jsonString_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ test("Successfully parses JSON", t => {
t->Assert.deepEqual(`"Foo"`->S.parseAnyWith(S.jsonString(schema)), Ok("Foo"), ())
})

test("Successfully serializes JSON", t => {
test("Successfully serializes string to JSON", t => {
let schema = S.string

t->Assert.deepEqual(
Expand All @@ -17,6 +17,36 @@ test("Successfully serializes JSON", t => {
)
})

test("Successfully serializes string literal to JSON", t => {
let schema = S.literal("foo")

t->Assert.deepEqual(
`foo`->S.serializeToUnknownWith(S.jsonString(schema)),
Ok(%raw(`'"foo"'`)),
(),
)
})

test("Successfully serializes float to JSON", t => {
let schema = S.float

t->Assert.deepEqual(
123.4->S.serializeToUnknownWith(S.jsonString(schema)),
Ok(%raw(`'123.4'`)),
(),
)
})

test("Successfully serializes tuple", t => {
let schema = S.tuple2(S.int, S.string)

t->Assert.deepEqual(
(12, "foo")->S.serializeToUnknownWith(S.jsonString(schema)),
Ok(%raw(`'[12,"foo"]'`)),
(),
)
})

test("Successfully serializes JSON object", t => {
let schema = S.schema(_ =>
{
Expand All @@ -33,6 +63,12 @@ test("Successfully serializes JSON object", t => {
Ok(%raw(`'{"foo":"bar","baz":[1,3]}'`)),
(),
)
t->U.assertCompiledCode(
~schema=S.jsonString(schema),
~op=#serialize,
// FIXME: Checks??
`i=>{return \'{"foo":\'+"\\"bar\\""+\',"baz":\'+JSON.stringify(i["baz"])+\'}\'}`,
)
})

test("Successfully serializes JSON object with space", t => {
Expand Down Expand Up @@ -88,7 +124,7 @@ test("Compiled async parse code snapshot", t => {
test("Compiled serialize code snapshot", t => {
let schema = S.jsonString(S.bool)

t->U.assertCompiledCode(~schema, ~op=#serialize, `i=>{return JSON.stringify(i)}`)
t->U.assertCompiledCode(~schema, ~op=#serialize, `i=>{return (i?"true":"false")}`)
})

test("Compiled serialize code snapshot with space", t => {
Expand Down
Loading

0 comments on commit 4fe60bf

Please sign in to comment.