From ff4acb181888c20794d4834102051dc0fec63161 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Thu, 19 Dec 2024 21:52:38 -0800 Subject: [PATCH 1/4] build(bindgen): check for corresponding .zig file --- src/codegen/bindgen-lib-internal.ts | 7 +++++++ src/codegen/bindgen-lib.ts | 25 +++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/codegen/bindgen-lib-internal.ts b/src/codegen/bindgen-lib-internal.ts index 7c4ee555fa49c2..2c9ac7d8d3d0b1 100644 --- a/src/codegen/bindgen-lib-internal.ts +++ b/src/codegen/bindgen-lib-internal.ts @@ -4,6 +4,7 @@ // always produce correct code, or bail with an error. import { expect } from "bun:test"; import type { FuncOptions, Type, t } from "./bindgen-lib"; +import fs from "node:fs"; import * as path from "node:path"; import assert from "node:assert"; @@ -806,6 +807,12 @@ export function registerFunction(opts: FuncOptions) { const filename = stackTraceFileName(snapshot); expect(filename).toEndWith(".bind.ts"); const zigFile = path.relative(src, filename.replace(/\.bind\.ts$/, ".zig")); + if (!fs.existsSync(zigFile)) { + const bindName = path.basename(filename); + throw new Error( + `$[bindName] is missing a corresponding Zig file at ${zigFile}. Please create it and make sure it matches signatures in ${bindName}.`, + ); + } let file = files.get(zigFile); if (!file) { file = { functions: [], typedefs: [] }; diff --git a/src/codegen/bindgen-lib.ts b/src/codegen/bindgen-lib.ts index 483e6d2531e53f..b028a1143edb1b 100644 --- a/src/codegen/bindgen-lib.ts +++ b/src/codegen/bindgen-lib.ts @@ -1,5 +1,9 @@ -// This is the public API for `bind.ts` files -// It is aliased as `import {} from 'bindgen'` +/** + * This is the public API for `bind.ts` files + * It is aliased as `import {} from 'bindgen'` + * @see https://bun.sh/docs/project/bindgen + */ + import { isType, dictionaryImpl, @@ -196,6 +200,23 @@ export namespace t { export const ByteString = builtinType()("ByteString"); /** * DOMString but encoded as `[]const u8` + * + * @example + * ```ts + * // foo.bind.ts + * import { fn, t } from "bindgen"; + * + * export const foo = fn({ + * args: { bar: t.UTF8String }, + * }) + * ``` + * + * ```zig + * // foo.zig + * pub fn foo(bar: []const u8) void { + * // ... + * } + * ``` */ export const UTF8String = builtinType()("UTF8String"); From 1f1c7a3de9de8bc789bcdc842cc8a2f9a8a48e49 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Thu, 19 Dec 2024 22:04:17 -0800 Subject: [PATCH 2/4] fixes --- src/codegen/bindgen.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/codegen/bindgen.ts b/src/codegen/bindgen.ts index f9f9d5e4023f45..b3d8be92c67098 100644 --- a/src/codegen/bindgen.ts +++ b/src/codegen/bindgen.ts @@ -4,6 +4,7 @@ // Generated bindings are available in `bun.generated..*` in Zig, // or `Generated::::*` in C++ from including `Generated.h`. import * as path from "node:path"; +import fs from "node:fs"; import { CodeWriter, TypeImpl, @@ -1076,7 +1077,15 @@ const unsortedFiles = readdirRecursiveWithExclusionsAndExtensionsSync(src, ["nod // Sort for deterministic output for (const fileName of [...unsortedFiles].sort()) { const zigFile = path.relative(src, fileName.replace(/\.bind\.ts$/, ".zig")); + const zigFilePath = path.join(src, zigFile); let file = files.get(zigFile); + if (!fs.existsSync(zigFilePath)) { + // It would be nice if this would generate the file with the correct boilerplate + const bindName = path.basename(fileName); + throw new Error( + `${bindName} is missing a corresponding Zig file at ${zigFile}. Please create it and make sure it matches signatures in ${bindName}.`, + ); + } if (!file) { file = { functions: [], typedefs: [] }; files.set(zigFile, file); From b9c12fb6f1fcddc66d749c7321e0a2a2b9192153 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Thu, 19 Dec 2024 22:11:09 -0800 Subject: [PATCH 3/4] doc improvements --- src/codegen/bindgen-lib-internal.ts | 7 ------- src/codegen/bindgen-lib.ts | 31 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/codegen/bindgen-lib-internal.ts b/src/codegen/bindgen-lib-internal.ts index 2c9ac7d8d3d0b1..7c4ee555fa49c2 100644 --- a/src/codegen/bindgen-lib-internal.ts +++ b/src/codegen/bindgen-lib-internal.ts @@ -4,7 +4,6 @@ // always produce correct code, or bail with an error. import { expect } from "bun:test"; import type { FuncOptions, Type, t } from "./bindgen-lib"; -import fs from "node:fs"; import * as path from "node:path"; import assert from "node:assert"; @@ -807,12 +806,6 @@ export function registerFunction(opts: FuncOptions) { const filename = stackTraceFileName(snapshot); expect(filename).toEndWith(".bind.ts"); const zigFile = path.relative(src, filename.replace(/\.bind\.ts$/, ".zig")); - if (!fs.existsSync(zigFile)) { - const bindName = path.basename(filename); - throw new Error( - `$[bindName] is missing a corresponding Zig file at ${zigFile}. Please create it and make sure it matches signatures in ${bindName}.`, - ); - } let file = files.get(zigFile); if (!file) { file = { functions: [], typedefs: [] }; diff --git a/src/codegen/bindgen-lib.ts b/src/codegen/bindgen-lib.ts index b028a1143edb1b..b133c3b41f5e97 100644 --- a/src/codegen/bindgen-lib.ts +++ b/src/codegen/bindgen-lib.ts @@ -165,35 +165,35 @@ export namespace t { /** * The DOMString type corresponds to strings. * - * **Note**: A DOMString value might include unmatched surrogate code points. + * @note A DOMString value might include unmatched surrogate code points. * Use USVString if this is not desirable. * - * https://webidl.spec.whatwg.org/#idl-DOMString + * @see https://webidl.spec.whatwg.org/#idl-DOMString */ export const DOMString = builtinType()("DOMString"); - /* - * The USVString type corresponds to scalar value strings. Depending on the + /** + * The {@link USVString} type corresponds to scalar value strings. Depending on the * context, these can be treated as sequences of code units or scalar values. * * Specifications should only use USVString for APIs that perform text * processing and need a string of scalar values to operate on. Most APIs that - * use strings should instead be using DOMString, which does not make any + * use strings should instead be using {@link DOMString}, which does not make any * interpretations of the code units in the string. When in doubt, use - * DOMString + * {@link DOMString} * - * https://webidl.spec.whatwg.org/#idl-USVString + * @see https://webidl.spec.whatwg.org/#idl-USVString */ export const USVString = builtinType()("USVString"); /** * The ByteString type corresponds to byte sequences. * - * WARNING: Specifications should only use ByteString for interfacing with protocols - * that use bytes and strings interchangeably, such as HTTP. In general, - * strings should be represented with DOMString values, even if it is expected - * that values of the string will always be in ASCII or some 8-bit character - * encoding. Sequences or frozen arrays with octet or byte elements, - * Uint8Array, or Int8Array should be used for holding 8-bit data rather than - * ByteString. + * WARNING: Specifications should only use ByteString for interfacing with + * protocols that use bytes and strings interchangeably, such as HTTP. In + * general, strings should be represented with {@link DOMString} values, even + * if it is expected that values of the string will always be in ASCII or some + * 8-bit character encoding. Sequences or frozen arrays with octet or byte + * elements, {@link Uint8Array}, or {@link Int8Array} should be used for + * holding 8-bit data rather than `ByteString`. * * https://webidl.spec.whatwg.org/#idl-ByteString */ @@ -201,7 +201,6 @@ export namespace t { /** * DOMString but encoded as `[]const u8` * - * @example * ```ts * // foo.bind.ts * import { fn, t } from "bindgen"; @@ -238,7 +237,7 @@ export namespace t { /** * Reference a type by string name instead of by object reference. This is - * required in some siutations like `Request` which can take an existing + * required in some siutations like {@link Request} which can take an existing * request object in as itself. */ export function ref(name: string): Type { From 57d04a0717aac89aa4e2695d358d6ac628e33d51 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Thu, 19 Dec 2024 22:25:18 -0800 Subject: [PATCH 4/4] even more docs --- src/codegen/bindgen-lib.ts | 47 ++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/codegen/bindgen-lib.ts b/src/codegen/bindgen-lib.ts index b133c3b41f5e97..5594df29fc9ec6 100644 --- a/src/codegen/bindgen-lib.ts +++ b/src/codegen/bindgen-lib.ts @@ -295,13 +295,46 @@ export namespace t { } } -export type FuncOptions = FuncMetadata & - ( - | { - variants: FuncVariant[]; - } - | FuncVariant - ); +interface FuncOptionsWithVariant extends FuncMetadata { + /** + * Declare a function with multiple overloads. Each overload gets its own + * native function named "name`n`" where `n` is the 1-based index of the + * overload. + * + * ## Example + * ```ts + * // foo.bind.ts + * import { fn } from "bindgen"; + * + * export const foo = fn({ + * variants: [ + * { + * args: { a: t.i32 }, + * ret: t.i32, + * }, + * { + * args: { a: t.i32, b: t.i32 }, + * ret: t.boolean, + * } + * ] + * }); + * ``` + * + * ```zig + * // foo.zig + * pub fn foo1(a: i32) i32 { + * return a; + * } + * + * pub fn foo2(a: i32, b: i32) bool { + * return a == b; + * } + * ``` + */ + variants: FuncVariant[]; +} +type FuncWithoutOverloads = FuncMetadata & FuncVariant; +type FuncOptions = FuncOptionsWithVariant | FuncWithoutOverloads; export interface FuncMetadata { /**