aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/scripts/generate-classes.ts
diff options
context:
space:
mode:
authorGravatar Dylan Conway <35280289+dylan-conway@users.noreply.github.com> 2023-07-14 19:37:22 -0700
committerGravatar GitHub <noreply@github.com> 2023-07-14 19:37:22 -0700
commitc39c11e1011b682c2c4e48594c7d6110cfc3343c (patch)
tree8808ca4cd6684949423f28f3cd4d90aedb605cb7 /src/bun.js/scripts/generate-classes.ts
parent25512104265aa568ca98e5bd89a977203ee261a6 (diff)
downloadbun-c39c11e1011b682c2c4e48594c7d6110cfc3343c.tar.gz
bun-c39c11e1011b682c2c4e48594c7d6110cfc3343c.tar.zst
bun-c39c11e1011b682c2c4e48594c7d6110cfc3343c.zip
structured clone (#3637)
* copy `SerializedScriptValue` * format * make `SerializedScriptValue` compile * add `transfer` option * tests * serialize/deserialize blobs * tests for blobs * serialize/deserialize file blobs * more tests * small cleanup * format * small changes + serialize offset * slice helper * map and set test
Diffstat (limited to 'src/bun.js/scripts/generate-classes.ts')
-rw-r--r--src/bun.js/scripts/generate-classes.ts138
1 files changed, 133 insertions, 5 deletions
diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts
index ff6954753..fb4419642 100644
--- a/src/bun.js/scripts/generate-classes.ts
+++ b/src/bun.js/scripts/generate-classes.ts
@@ -345,6 +345,25 @@ ${
JSC_DECLARE_CUSTOM_GETTER(js${typeName}Constructor);`
: ""
}
+
+${
+ obj.structuredClone
+ ? `extern "C" void ${symbolName(
+ typeName,
+ "onStructuredCloneSerialize",
+ )}(void*, JSC::JSGlobalObject*, void*, void (*) (CloneSerializer*, const uint8_t*, uint32_t));`
+ : ""
+}
+
+${
+ obj.structuredClone
+ ? `extern "C" JSC::EncodedJSValue ${symbolName(
+ typeName,
+ "onStructuredCloneDeserialize",
+ )}(JSC::JSGlobalObject*, const uint8_t*, const uint8_t*);`
+ : ""
+}
+
${"finalize" in obj ? `extern "C" void ${classSymbolName(typeName, "finalize")}(void*);` : ""}
${obj.call ? `extern "C" JSC_DECLARE_HOST_FUNCTION(${classSymbolName(typeName, "call")});` : ""}
@@ -1200,6 +1219,7 @@ function generateZig(
call = false,
values = [],
hasPendingActivity = false,
+ structuredClone = false,
} = {} as ClassDefinition,
) {
const exports = new Map<string, string>();
@@ -1226,6 +1246,16 @@ function generateZig(
Object.values(klass).map(a => appendSymbols(exports, name => classSymbolName(typeName, name), a));
Object.values(proto).map(a => appendSymbols(exports, name => protoSymbolName(typeName, name), a));
+ if (structuredClone) {
+ exports.set("onStructuredCloneSerialize", symbolName(typeName, "onStructuredCloneSerialize"));
+
+ if (structuredClone === "transferrable") {
+ exports.set("onStructuredCloneTransfer", symbolName(typeName, "onStructuredCloneTransfer"));
+ }
+
+ exports.set("onStructuredCloneDeserialize", symbolName(typeName, "onStructuredCloneDeserialize"));
+ }
+
const externs = Object.entries({
...proto,
...Object.fromEntries((values || []).map(a => [a, { internal: true }])),
@@ -1269,6 +1299,29 @@ function generateZig(
`;
}
+ if (structuredClone) {
+ output += `
+ if (@TypeOf(${typeName}.onStructuredCloneSerialize) != (fn(*${typeName}, globalThis: *JSC.JSGlobalObject, ctx: *anyopaque, writeBytes: *const fn(*anyopaque, ptr: [*]const u8, len: u32) callconv(.C) void) callconv(.C) void)) {
+ @compileLog("${typeName}.onStructuredCloneSerialize is not a structured clone serialize function");
+ }
+ `;
+
+ if (structuredClone === "transferrable") {
+ exports.set("structuredClone", symbolName(typeName, "onTransferrableStructuredClone"));
+ output += `
+ if (@TypeOf(${typeName}.onStructuredCloneTransfer) != (fn(*${typeName}, globalThis: *JSC.JSGlobalObject, ctx: *anyopaque, write: *const fn(*anyopaque, ptr: [*]const u8, len: usize) callconv(.C) void) callconv(.C) void)) {
+ @compileLog("${typeName}.onStructuredCloneTransfer is not a structured clone transfer function");
+ }
+ `;
+ }
+
+ output += `
+ if (@TypeOf(${typeName}.onStructuredCloneDeserialize) != (fn(globalThis: *JSC.JSGlobalObject, ptr: [*]u8, end: [*]u8) callconv(.C) JSC.JSValue)) {
+ @compileLog("${typeName}.onStructuredCloneDeserialize is not a structured clone deserialize function");
+ }
+ `;
+ }
+
if (construct && !noConstructor) {
output += `
if (@TypeOf(${typeName}.constructor) != (fn(*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*${typeName})) {
@@ -1532,6 +1585,7 @@ namespace Zig {
#include "JSDOMWrapper.h"
#include <wtf/NeverDestroyed.h>
+#include "SerializedScriptValue.h"
`,
`
@@ -1543,11 +1597,6 @@ using namespace JSC;
`,
];
-const GENERATED_CLASSES_FOOTER = `
-}
-
-`;
-
const GENERATED_CLASSES_IMPL_HEADER = `
// GENERATED CODE - DO NOT MODIFY BY HAND
// Generated by make codegen
@@ -1676,6 +1725,84 @@ function writeAndUnlink(path, content) {
return Bun.write(path, content);
}
+const GENERATED_CLASSES_FOOTER = `
+
+class StructuredCloneableSerialize {
+ public:
+
+ void (*cppWriteBytes)(CloneSerializer*, const uint8_t*, uint32_t);
+
+ std::function<void(void*, JSC::JSGlobalObject*, void*, void (*)(CloneSerializer*, const uint8_t*, uint32_t))> zigFunction;
+
+ uint8_t tag;
+
+ // the type from zig
+ void* impl;
+
+ static std::optional<StructuredCloneableSerialize> fromJS(JSC::JSValue);
+ void write(CloneSerializer* serializer, JSC::JSGlobalObject* globalObject)
+ {
+ zigFunction(impl, globalObject, serializer, cppWriteBytes);
+ }
+};
+
+class StructuredCloneableDeserialize {
+ public:
+ static std::optional<JSC::EncodedJSValue> fromTagDeserialize(uint8_t tag, JSC::JSGlobalObject*, const uint8_t*, const uint8_t*);
+};
+
+}
+
+`;
+
+function writeCppSerializers() {
+ var output = ``;
+
+ var structuredClonable = classes
+ .filter(a => a.structuredClone)
+ .sort((a, b) => a.structuredClone.tag < b.structuredClone.tag);
+
+ function fromJSForEachClass(klass) {
+ return `
+ if (auto* result = jsDynamicCast<${className(klass.name)}*>(value)) {
+ return StructuredCloneableSerialize { .cppWriteBytes = SerializedScriptValue::writeBytesForBun, .zigFunction = ${symbolName(
+ klass.name,
+ "onStructuredCloneSerialize",
+ )}, .tag = ${klass.structuredClone.tag}, .impl = result->wrapped() };
+ }
+ `;
+ }
+
+ function fromTagDeserializeForEachClass(klass) {
+ return `
+ if (tag == ${klass.structuredClone.tag}) {
+ return ${symbolName(klass.name, "onStructuredCloneDeserialize")}(globalObject, ptr, end);
+ }
+ `;
+ }
+
+ output += `
+ std::optional<StructuredCloneableSerialize> StructuredCloneableSerialize::fromJS(JSC::JSValue value)
+ {
+ ${structuredClonable.map(fromJSForEachClass).join("\n").trim()}
+ return std::nullopt;
+ }
+ `;
+
+ output += `
+ std::optional<JSC::EncodedJSValue> StructuredCloneableDeserialize::fromTagDeserialize(uint8_t tag, JSC::JSGlobalObject* globalObject, const uint8_t* ptr, const uint8_t* end)
+ {
+ ${structuredClonable.map(fromTagDeserializeForEachClass).join("\n").trim()}
+ return std::nullopt;
+ }
+ `;
+
+ for (let klass of classes) {
+ }
+
+ return output;
+}
+
await writeAndUnlink(`${import.meta.dir}/../bindings/generated_classes.zig`, [
ZIG_GENERATED_CLASSES_HEADER,
@@ -1699,6 +1826,7 @@ await writeAndUnlink(`${import.meta.dir}/../bindings/ZigGeneratedClasses.h`, [
await writeAndUnlink(`${import.meta.dir}/../bindings/ZigGeneratedClasses.cpp`, [
GENERATED_CLASSES_IMPL_HEADER,
...classes.map(a => generateImpl(a.name, a)),
+ writeCppSerializers(classes),
GENERATED_CLASSES_IMPL_FOOTER,
]);
await writeAndUnlink(