diff --git a/.gitignore b/.gitignore index d2fa1d6a621..371a228895e 100644 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,9 @@ sign.json src/bake/generated.ts src/generated_enum_extractor.zig src/jsc/bindings-obj +# The two generators below were removed in the $zig -> $native rename, but a +# build of an older checkout can still leave these on disk; keep them ignored +# so they are never accidentally committed. src/jsc/bindings/GeneratedJS2Native.zig src/jsc/bindings/GeneratedBindings.zig src/bun.js/debug-bindings-obj diff --git a/CLAUDE.md b/CLAUDE.md index 4bee5917712..59813c19868 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -114,7 +114,7 @@ test("(multi-file test) my feature", async () => { - **TypeScript** (`src/js/`): Built-in JavaScript modules with special syntax (see JavaScript Modules section) - **Generated code**: Many `.rs` and `.cpp` files are auto-generated from `.classes.ts` and other sources. The build regenerates them automatically when their inputs change. -You will see `.zig` files alongside many `.rs` files (e.g. `fetch.zig` next to `fetch.rs`). These are the **original Zig implementation, kept only as a porting reference** — they are **not compiled** and **not shipped**. New code goes in `.rs`. When fixing a bug or porting a behavior, the `.zig` sibling is the source of truth for *intended semantics*: read it, then make the `.rs` match. Never add new behavior to a `.zig` file. +You will see `.zig` files alongside many `.rs` files (e.g. `fetch.zig` next to `fetch.rs`). These are the **original Zig implementation, kept only as a porting reference** — they are **not compiled**, **not shipped**, and not read by the build or codegen (the `$native()` JS-binding macro resolves `.rs` files). New code goes in `.rs`. When fixing a bug or porting a behavior, the `.zig` sibling is the source of truth for *intended semantics*: read it, then make the `.rs` match. Never add new behavior to a `.zig` file. ### Core Source Organization diff --git a/scripts/build/codegen.ts b/scripts/build/codegen.ts index 49c57c61e46..e7816289c7e 100644 --- a/scripts/build/codegen.ts +++ b/scripts/build/codegen.ts @@ -45,22 +45,6 @@ import { writeIfChanged } from "./fs.ts"; import type { Ninja } from "./ninja.ts"; import { quote, quoteArgs } from "./shell.ts"; -/** - * Codegen outputs that land in `src/` instead of `codegenDir`. The zig - * compiler refuses to import files outside its source tree, so these two - * generated `.zig` files live in `src/jsc/bindings/` (gitignored). - * - * Consumers of `sources.zig` (the `src/**\/*.zig` glob) must filter these - * out — they're OUTPUTS of codegen, not inputs. - * - * Paths are relative to repo root. This list is the single source of truth; - * `globAllSources()` does NOT hardcode these. - */ -export const zigFilesGeneratedIntoSrc = [ - "src/jsc/bindings/GeneratedBindings.zig", - "src/jsc/bindings/GeneratedJS2Native.zig", -] as const; - // The individual emit functions take these four params. Bundled to keep // signatures short. interface Ctx { @@ -132,8 +116,8 @@ export function registerCodegenRules(n: Ninja, cfg: Config): void { // ship with the build host's platform baked in. // // restat = 1 because most scripts use writeIfNotChanged(). Scripts that - // don't (generate-jssink, ci_info) always write → restat is a no-op for - // them, no harm. + // don't (generate-jssink) always write → restat is a no-op for them, no + // harm. const env = hostWin ? `set TARGET_PLATFORM=${platform}&& set TARGET_ARCH=${arch}&& ` : `TARGET_PLATFORM=${platform} TARGET_ARCH=${arch} `; @@ -210,10 +194,10 @@ export interface CodegenOutputs { /** All codegen outputs — use for phony target `codegen`. */ all: string[]; - /** Outputs that zig `@embedFile`s or imports. */ + /** Outputs the Rust build `include!`s or embeds. */ rustInputs: string[]; - /** Outputs that zig needs to exist but doesn't embed (debug bake runtime). */ + /** Outputs the Rust build needs to exist but doesn't embed (debug bake runtime). */ rustOrderOnly: string[]; /** Generated .cpp files. Compiled alongside handwritten C++ in bun.ts. */ @@ -245,9 +229,6 @@ export interface CodegenOutputs { /** The bindgenv2 .cpp outputs (compiled separately from handwritten C++). */ bindgenV2Cpp: string[]; - /** The bindgenv2 .zig outputs (legacy artifacts, retained for reference). */ - bindgenV2Zig: string[]; - /** * Stamp output from `bun install` at repo root. * The esbuild tool and the cppbind lezer parser live here. Any @@ -280,7 +261,6 @@ export function emitCodegen(n: Ninja, cfg: Config, sources: Sources): CodegenOut cppHeaders: [], cppAll: [], bindgenV2Cpp: [], - bindgenV2Zig: [], rootInstall, }; @@ -302,7 +282,6 @@ export function emitCodegen(n: Ninja, cfg: Config, sources: Sources): CodegenOut emitGeneratedClasses(ctx); emitHostExports(ctx); emitCppBind(ctx); - emitCiInfo(ctx); emitJsModules(ctx); emitBakeCodegen(ctx); emitBindgenV2(ctx); @@ -584,11 +563,7 @@ function emitErrorCode({ n, cfg, o, dirStamp }: Ctx): void { resolve(cfg.cwd, "src", "jsc", "bindings", "ErrorCode.h"), ]; - const outputs = [ - resolve(cfg.codegenDir, "ErrorCode+List.h"), - resolve(cfg.codegenDir, "ErrorCode+Data.h"), - resolve(cfg.codegenDir, "ErrorCode.zig"), - ]; + const outputs = [resolve(cfg.codegenDir, "ErrorCode+List.h"), resolve(cfg.codegenDir, "ErrorCode+Data.h")]; n.build({ outputs, @@ -597,13 +572,12 @@ function emitErrorCode({ n, cfg, o, dirStamp }: Ctx): void { orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: "ErrorCode.{zig,h}", + desc: "ErrorCode.h", args: shJoin(cfg, ["run", script, cfg.codegenDir]), }, }); o.all.push(...outputs); - o.rustInputs.push(...outputs); o.cppHeaders.push(outputs[0]!, outputs[1]!); } @@ -617,7 +591,6 @@ function emitGeneratedClasses({ n, cfg, sources, o, dirStamp }: Ctx): void { resolve(cfg.codegenDir, "ZigGeneratedClasses+DOMClientIsoSubspaces.h"), resolve(cfg.codegenDir, "ZigGeneratedClasses+DOMIsoSubspaces.h"), resolve(cfg.codegenDir, "ZigGeneratedClasses+lazyStructureImpl.h"), - resolve(cfg.codegenDir, "ZigGeneratedClasses.zig"), resolve(cfg.codegenDir, "ZigGeneratedClasses.lut.txt"), // Rust sibling: include!()'d by src/runtime/generated_classes.rs. Must be // a declared output so the cargo edge (which lists this in rustInputs) @@ -629,12 +602,12 @@ function emitGeneratedClasses({ n, cfg, sources, o, dirStamp }: Ctx): void { n.build({ outputs, rule: "codegen", - inputs: [script, ...sources.zigGeneratedClasses], + inputs: [script, ...sources.classesTs], orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: "ZigGeneratedClasses.{zig,cpp,h}", - args: shJoin(cfg, ["run", script, ...sources.zigGeneratedClasses, cfg.codegenDir]), + desc: "ZigGeneratedClasses.{cpp,h}", + args: shJoin(cfg, ["run", script, ...sources.classesTs, cfg.codegenDir]), }, }); @@ -677,15 +650,14 @@ function emitHostExports({ n, cfg, sources, o, dirStamp }: Ctx): void { o.all.push(output); // bun_runtime/build.rs panics if this file is absent, so the rust_build edge - // must wait on it — `rustInputs` is the implicit-dep list both zig and the - // cargo edge consume. + // must wait on it — `rustInputs` is the implicit-dep list the cargo edge + // consumes. o.rustInputs.push(output); } function emitCppBind({ n, cfg, sources, o, dirStamp }: Ctx): void { const script = resolve(cfg.cwd, "src", "codegen", "cppbind.ts"); - const output = resolve(cfg.codegenDir, "cpp.zig"); const outputRs = resolve(cfg.codegenDir, "cpp.rs"); // Write the .cpp file list for cppbind to scan. Build system owns the @@ -703,7 +675,7 @@ function emitCppBind({ n, cfg, sources, o, dirStamp }: Ctx): void { writeIfChanged(cxxSourcesFile, cxxSourcesLines.join("\n") + "\n"); n.build({ - outputs: [output, outputRs], + outputs: [outputRs], rule: "codegen", inputs: [script], // cppbind scans ALL .cpp files for [[ZIG_EXPORT]] annotations. Every @@ -723,39 +695,16 @@ function emitCppBind({ n, cfg, sources, o, dirStamp }: Ctx): void { orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: "cpp.{zig,rs} (cppbind)", + desc: "cpp.rs (cppbind)", // cppbind.ts takes: . No `run` — // direct script invocation (`${BUN_EXECUTABLE} ${script} ...`). args: shJoin(cfg, [script, resolve(cfg.cwd, "src"), cfg.codegenDir, cxxSourcesFile]), }, }); - o.all.push(output, outputRs); + o.all.push(outputRs); // bun_jsc `include!`s cpp.rs — the cargo edge must order after this. - o.rustInputs.push(output, outputRs); -} - -function emitCiInfo({ n, cfg, o, dirStamp }: Ctx): void { - const script = resolve(cfg.cwd, "src", "codegen", "ci_info.ts"); - const output = resolve(cfg.codegenDir, "ci_info.zig"); - - // CMake lists JavaScriptCodegenSources as deps here, but ci_info.ts doesn't - // read any of those files — it's a pure static data generator. The CMake - // dep list is wrong (copy-paste from bundle-modules). We use just the script. - n.build({ - outputs: [output], - rule: "codegen", - inputs: [script], - orderOnlyInputs: [dirStamp], - vars: { - cwd: cfg.cwd, - desc: "ci_info.zig", - args: shJoin(cfg, [script, output]), - }, - }); - - o.all.push(output); - o.rustInputs.push(output); + o.rustInputs.push(outputRs); } function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { @@ -767,9 +716,20 @@ function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { // ($makeErrorWithCode(N, ...)); without this dep an ErrorCode.ts edit leaves // stale error numbers in the JS bundles while the C++ enum regenerates. const errorCodeInput = resolve(cfg.cwd, "src", "jsc", "bindings", "ErrorCode.ts"); - - // Written into src/ (not codegenDir) — see zigFilesGeneratedIntoSrc at top. - const js2nativeZig = resolve(cfg.cwd, zigFilesGeneratedIntoSrc[1]); + // generate-js2native.ts scans .rs paths to resolve $native() keys and + // derive symbol/crate paths. Write the path set at configure time so an + // added/removed/renamed .rs file invalidates this edge without taking the + // full ~1400-file Rust glob as direct inputs. + mkdirSync(cfg.codegenDir, { recursive: true }); + const js2nativeRustSources = resolve(cfg.codegenDir, "js2native-rust-sources.txt"); + writeIfChanged( + js2nativeRustSources, + sources.rust + .filter(p => p.endsWith(".rs")) + .map(p => relative(cfg.cwd, p).replace(/\\/g, "/")) + .sort() + .join("\n") + "\n", + ); const outputs = [ resolve(cfg.codegenDir, "WebCoreJSBuiltins.cpp"), @@ -781,7 +741,6 @@ function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { resolve(cfg.codegenDir, "NativeModuleImpl.h"), resolve(cfg.codegenDir, "SyntheticModuleType.h"), resolve(cfg.codegenDir, "GeneratedJS2Native.h"), - js2nativeZig, // Rust sibling: include!()'d by src/runtime/generated_js2native.rs. Must be // a declared output so the cargo edge re-invokes when bundle-modules.ts / // generate-js2native.ts changes — the includer shim's mtime never moves. @@ -796,6 +755,7 @@ function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { outputs, rule: "codegen", inputs: [script, ...sources.js, ...sources.jsCodegen, extraInput, errorCodeInput], + implicitInputs: [js2nativeRustSources], orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, @@ -885,8 +845,7 @@ function emitBindgenV2({ n, cfg, sources, o, dirStamp }: Ctx): void { assert(allOutputs.length > 0, "bindgenv2 list-outputs returned no files"); const cppOutputs = allOutputs.filter(p => p.endsWith(".cpp")); - const zigOutputs = allOutputs.filter(p => p.endsWith(".zig")); - const other = allOutputs.filter(p => !p.endsWith(".cpp") && !p.endsWith(".zig")); + const other = allOutputs.filter(p => !p.endsWith(".cpp")); assert(other.length === 0, `bindgenv2 emitted unexpected output type: ${other.join(", ")}`); n.build({ @@ -909,35 +868,30 @@ function emitBindgenV2({ n, cfg, sources, o, dirStamp }: Ctx): void { o.all.push(...allOutputs); o.bindgenV2Cpp.push(...cppOutputs); - o.bindgenV2Zig.push(...zigOutputs); - o.rustInputs.push(...zigOutputs); } function emitBindgen({ n, cfg, sources, o, dirStamp }: Ctx): void { const script = resolve(cfg.cwd, "src", "codegen", "bindgen.ts"); - // Written into src/ (not codegenDir) — see zigFilesGeneratedIntoSrc at top. - const zigOut = resolve(cfg.cwd, zigFilesGeneratedIntoSrc[0]); const cppOut = resolve(cfg.codegenDir, "GeneratedBindings.cpp"); // bindgen.ts scans src/ for .bind.ts files itself — this list is only for // ninja dependency tracking. New .bind.ts files need a reconfigure to be // picked up (next glob gets them). n.build({ - outputs: [cppOut, zigOut], + outputs: [cppOut], rule: "codegen", inputs: [script, ...sources.bindgen], orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: ".bind.ts → GeneratedBindings.{cpp,zig}", + desc: ".bind.ts → GeneratedBindings.cpp", args: shJoin(cfg, ["run", script, debugFlag(cfg), `--codegen-root=${cfg.codegenDir}`]), }, }); - o.all.push(cppOut, zigOut); + o.all.push(cppOut); o.cppSources.push(cppOut); - o.rustInputs.push(zigOut); } function emitJsSink({ n, cfg, o, dirStamp }: Ctx): void { diff --git a/scripts/glob-sources.ts b/scripts/glob-sources.ts index 1f794a29580..6f84284c05a 100644 --- a/scripts/glob-sources.ts +++ b/scripts/glob-sources.ts @@ -45,7 +45,7 @@ const patterns = { paths: ["src/node-fallbacks/*.js"], }, /** `*.classes.ts` — input to generate-classes codegen */ - zigGeneratedClasses: { + classesTs: { paths: ["src/**/*.classes.ts"], }, /** built-in modules bundled at build time */ diff --git a/src/CLAUDE.md b/src/CLAUDE.md index 95e9613c997..31b17243858 100644 --- a/src/CLAUDE.md +++ b/src/CLAUDE.md @@ -14,7 +14,7 @@ bun_bin` (driven by `scripts/build/rust.ts`). Key crates: You will see `.zig` siblings next to many `.rs` files — those are the original implementation kept as a porting reference for _behavior_; they are not -compiled and are not where new code goes. +compiled, not read by the build or codegen, and are not where new code goes. Conventions: diff --git a/src/codegen/bindgen.ts b/src/codegen/bindgen.ts index 2584f2a3808..afe9b450408 100644 --- a/src/codegen/bindgen.ts +++ b/src/codegen/bindgen.ts @@ -1588,7 +1588,6 @@ writeIfNotChanged( path.join(codegenRoot, "GeneratedBindings.cpp"), [...headers].map(name => `#include ${str(name)}\n`).join("") + "\n" + cppInternal.buffer + "\n" + cpp.buffer, ); -writeIfNotChanged(path.join(src, "jsc/bindings/GeneratedBindings.zig"), zig.buffer + zigInternal.buffer); // Headers for (const [filename, { functions, typedefs }] of files) { diff --git a/src/codegen/bindgenv2/script.ts b/src/codegen/bindgenv2/script.ts index aafeacabb51..a057d1a0725 100755 --- a/src/codegen/bindgenv2/script.ts +++ b/src/codegen/bindgenv2/script.ts @@ -42,16 +42,6 @@ function cppSourcePath(type: NamedType): string { return `${codegenPath}/Generated${type.name}.cpp`; } -function zigSourcePath(typeOrNamespace: NamedType | string): string { - let ns: string; - if (typeof typeOrNamespace === "string") { - ns = typeOrNamespace; - } else { - ns = toZigNamespace(typeOrNamespace.name); - } - return `${codegenPath}/bindgen_generated/${ns}.zig`; -} - function toZigNamespace(name: string): string { const result = name .replace(/([^A-Z_])([A-Z])/g, "$1_$2") @@ -64,18 +54,15 @@ function toZigNamespace(name: string): string { } function listOutputs(): void { - const outputs: string[] = [`${codegenPath}/bindgen_generated.zig`]; + const outputs: string[] = []; for (const type of getNamedExports()) { if (type.hasCppSource) outputs.push(cppSourcePath(type)); - if (type.hasZigSource) outputs.push(zigSourcePath(type)); } process.stdout.write(outputs.join(";")); } function generate(): void { const names = new Set(); - const zigRoot: string[] = []; - const zigRootInternal: string[] = []; const namedExports = getNamedExports(); { @@ -111,34 +98,13 @@ function generate(): void { const cppHeader = type.cppHeader; const cppSource = type.cppSource; - const zigSource = type.zigSource; if (cppHeader) { helpers.writeIfNotChanged(cppHeaderPath(type), cppHeader); } if (cppSource) { helpers.writeIfNotChanged(cppSourcePath(type), cppSource); } - if (zigSource) { - zigRoot.push( - `pub const ${zigNamespace} = @import("./bindgen_generated/${zigNamespace}.zig");`, - `pub const ${type.name} = ${zigNamespace}.${type.name};`, - "", - ); - zigRootInternal.push(`pub const ${type.name} = ${zigNamespace}.Bindgen${type.name};`); - helpers.writeIfNotChanged(zigSourcePath(zigNamespace), zigSource); - } } - - helpers.writeIfNotChanged( - `${codegenPath}/bindgen_generated.zig`, - [ - ...zigRoot, - `pub const internal = struct {`, - ...zigRootInternal.map(s => " " + s), - `};`, - "", - ].join("\n"), - ); } function main(): void { diff --git a/src/codegen/bundle-modules.ts b/src/codegen/bundle-modules.ts index 1ddd7082fe1..45372839c33 100644 --- a/src/codegen/bundle-modules.ts +++ b/src/codegen/bundle-modules.ts @@ -15,7 +15,7 @@ import path from "path"; import jsclasses from "./../jsc/bindings/js_classes"; import { sliceSourceCode } from "./builtin-parser"; import { createAssertClientJS, createLogClientJS } from "./client-js"; -import { getJS2NativeCPP, getJS2NativeRust, getJS2NativeZig } from "./generate-js2native"; +import { getJS2NativeCPP, getJS2NativeRust } from "./generate-js2native"; import { cap, declareASCIILiteral, writeIfNotChanged } from "./helpers"; import { createInternalModuleRegistry } from "./internal-module-registry-scanner"; import { define } from "./replacements"; @@ -477,10 +477,6 @@ writeIfNotChanged( writeIfNotChanged(path.join(CODEGEN_DIR, "GeneratedJS2Native.h"), getJS2NativeCPP()); -// zig will complain if this file is outside of the module -const js2nativeZigPath = path.join(import.meta.dir, "../jsc/bindings/GeneratedJS2Native.zig"); -writeIfNotChanged(js2nativeZigPath, getJS2NativeZig(js2nativeZigPath)); - // Rust sibling: include!()'d by src/runtime/generated_js2native.rs writeIfNotChanged(path.join(CODEGEN_DIR, "generated_js2native.rs"), getJS2NativeRust()); diff --git a/src/codegen/ci_info.ts b/src/codegen/ci_info.ts deleted file mode 100644 index 4797ecd1a53..00000000000 --- a/src/codegen/ci_info.ts +++ /dev/null @@ -1,454 +0,0 @@ -type Vendor = { - name: string; - constant: string; - env: EnvMatch; - pr?: unknown; -}; -type EnvMatch = - | string - | EnvMatch[] - | { - env: string; - includes: string; - } - | { - any: string[]; - } - | Record; - -// The vendors list is copied from https://github.com/watson/ci-info/blob/master/vendors.json -// The extras list is copied and edited from https://github.com/watson/ci-info/blob/master/index.js line `exports.isCI = !!(...)` -// To update, copy the JSON again. -/* -The MIT License (MIT) - -Copyright (c) 2016 Thomas Watson Steen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -const extras: string[] = [ - "BUILD_ID", // Jenkins, Cloudbees - "BUILD_NUMBER", // Jenkins, TeamCity - "CI", // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari, Cloudflare Pages/Workers - "CI_APP_ID", // Appflow - "CI_BUILD_ID", // Appflow - "CI_BUILD_NUMBER", // Appflow - "CI_NAME", // Codeship and others - "CONTINUOUS_INTEGRATION", // Travis CI, Cirrus CI - "RUN_ID", // TaskCluster, dsari -]; -const vendors: Vendor[] = [ - { - "name": "Agola CI", - "constant": "AGOLA", - "env": "AGOLA_GIT_REF", - "pr": "AGOLA_PULL_REQUEST_ID", - }, - { - "name": "Appcircle", - "constant": "APPCIRCLE", - "env": "AC_APPCIRCLE", - "pr": { - "env": "AC_GIT_PR", - "ne": "false", - }, - }, - { - "name": "AppVeyor", - "constant": "APPVEYOR", - "env": "APPVEYOR", - "pr": "APPVEYOR_PULL_REQUEST_NUMBER", - }, - { - "name": "AWS CodeBuild", - "constant": "CODEBUILD", - "env": "CODEBUILD_BUILD_ARN", - "pr": { - "env": "CODEBUILD_WEBHOOK_EVENT", - "any": ["PULL_REQUEST_CREATED", "PULL_REQUEST_UPDATED", "PULL_REQUEST_REOPENED"], - }, - }, - { - "name": "Azure Pipelines", - "constant": "AZURE_PIPELINES", - "env": "TF_BUILD", - "pr": { - "BUILD_REASON": "PullRequest", - }, - }, - { - "name": "Bamboo", - "constant": "BAMBOO", - "env": "bamboo_planKey", - }, - { - "name": "Bitbucket Pipelines", - "constant": "BITBUCKET", - "env": "BITBUCKET_COMMIT", - "pr": "BITBUCKET_PR_ID", - }, - { - "name": "Bitrise", - "constant": "BITRISE", - "env": "BITRISE_IO", - "pr": "BITRISE_PULL_REQUEST", - }, - { - "name": "Buddy", - "constant": "BUDDY", - "env": "BUDDY_WORKSPACE_ID", - "pr": "BUDDY_EXECUTION_PULL_REQUEST_ID", - }, - { - "name": "Buildkite", - "constant": "BUILDKITE", - "env": "BUILDKITE", - "pr": { - "env": "BUILDKITE_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "CircleCI", - "constant": "CIRCLE", - "env": "CIRCLECI", - "pr": "CIRCLE_PULL_REQUEST", - }, - { - "name": "Cirrus CI", - "constant": "CIRRUS", - "env": "CIRRUS_CI", - "pr": "CIRRUS_PR", - }, - { - "name": "Cloudflare Pages", - "constant": "CLOUDFLARE_PAGES", - "env": "CF_PAGES", - }, - { - "name": "Cloudflare Workers", - "constant": "CLOUDFLARE_WORKERS", - "env": "WORKERS_CI", - }, - { - "name": "Codefresh", - "constant": "CODEFRESH", - "env": "CF_BUILD_ID", - "pr": { - "any": ["CF_PULL_REQUEST_NUMBER", "CF_PULL_REQUEST_ID"], - }, - }, - { - "name": "Codemagic", - "constant": "CODEMAGIC", - "env": "CM_BUILD_ID", - "pr": "CM_PULL_REQUEST", - }, - { - "name": "Codeship", - "constant": "CODESHIP", - "env": { - "CI_NAME": "codeship", - }, - }, - { - "name": "Drone", - "constant": "DRONE", - "env": "DRONE", - "pr": { - "DRONE_BUILD_EVENT": "pull_request", - }, - }, - { - "name": "dsari", - "constant": "DSARI", - "env": "DSARI", - }, - { - "name": "Earthly", - "constant": "EARTHLY", - "env": "EARTHLY_CI", - }, - { - "name": "Expo Application Services", - "constant": "EAS", - "env": "EAS_BUILD", - }, - { - "name": "Gerrit", - "constant": "GERRIT", - "env": "GERRIT_PROJECT", - }, - { - "name": "Gitea Actions", - "constant": "GITEA_ACTIONS", - "env": "GITEA_ACTIONS", - }, - { - "name": "GitHub Actions", - "constant": "GITHUB_ACTIONS", - "env": "GITHUB_ACTIONS", - "pr": { - "GITHUB_EVENT_NAME": "pull_request", - }, - }, - { - "name": "GitLab CI", - "constant": "GITLAB", - "env": "GITLAB_CI", - "pr": "CI_MERGE_REQUEST_ID", - }, - { - "name": "GoCD", - "constant": "GOCD", - "env": "GO_PIPELINE_LABEL", - }, - { - "name": "Google Cloud Build", - "constant": "GOOGLE_CLOUD_BUILD", - "env": "BUILDER_OUTPUT", - }, - { - "name": "Harness CI", - "constant": "HARNESS", - "env": "HARNESS_BUILD_ID", - }, - { - "name": "Heroku", - "constant": "HEROKU", - "env": { - "env": "NODE", - "includes": "/app/.heroku/node/bin/node", - }, - }, - { - "name": "Hudson", - "constant": "HUDSON", - "env": "HUDSON_URL", - }, - { - "name": "Jenkins", - "constant": "JENKINS", - "env": ["JENKINS_URL", "BUILD_ID"], - "pr": { - "any": ["ghprbPullId", "CHANGE_ID"], - }, - }, - { - "name": "LayerCI", - "constant": "LAYERCI", - "env": "LAYERCI", - "pr": "LAYERCI_PULL_REQUEST", - }, - { - "name": "Magnum CI", - "constant": "MAGNUM", - "env": "MAGNUM", - }, - { - "name": "Netlify CI", - "constant": "NETLIFY", - "env": "NETLIFY", - "pr": { - "env": "PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Nevercode", - "constant": "NEVERCODE", - "env": "NEVERCODE", - "pr": { - "env": "NEVERCODE_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Prow", - "constant": "PROW", - "env": "PROW_JOB_ID", - }, - { - "name": "ReleaseHub", - "constant": "RELEASEHUB", - "env": "RELEASE_BUILD_ID", - }, - { - "name": "Render", - "constant": "RENDER", - "env": "RENDER", - "pr": { - "IS_PULL_REQUEST": "true", - }, - }, - { - "name": "Sail CI", - "constant": "SAIL", - "env": "SAILCI", - "pr": "SAIL_PULL_REQUEST_NUMBER", - }, - { - "name": "Screwdriver", - "constant": "SCREWDRIVER", - "env": "SCREWDRIVER", - "pr": { - "env": "SD_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Semaphore", - "constant": "SEMAPHORE", - "env": "SEMAPHORE", - "pr": "PULL_REQUEST_NUMBER", - }, - { - "name": "Sourcehut", - "constant": "SOURCEHUT", - "env": { - "CI_NAME": "sourcehut", - }, - }, - { - "name": "Strider CD", - "constant": "STRIDER", - "env": "STRIDER", - }, - { - "name": "TaskCluster", - "constant": "TASKCLUSTER", - "env": ["TASK_ID", "RUN_ID"], - }, - { - "name": "TeamCity", - "constant": "TEAMCITY", - "env": "TEAMCITY_VERSION", - }, - { - "name": "Travis CI", - "constant": "TRAVIS", - "env": "TRAVIS", - "pr": { - "env": "TRAVIS_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Vela", - "constant": "VELA", - "env": "VELA", - "pr": { - "VELA_PULL_REQUEST": "1", - }, - }, - { - "name": "Vercel", - "constant": "VERCEL", - "env": { - "any": ["NOW_BUILDER", "VERCEL"], - }, - "pr": "VERCEL_GIT_PULL_REQUEST_ID", - }, - { - "name": "Visual Studio App Center", - "constant": "APPCENTER", - "env": "APPCENTER_BUILD_ID", - }, - { - "name": "Woodpecker", - "constant": "WOODPECKER", - "env": { - "CI": "woodpecker", - }, - "pr": { - "CI_BUILD_EVENT": "pull_request", - }, - }, - { - "name": "Xcode Cloud", - "constant": "XCODE_CLOUD", - "env": "CI_XCODE_PROJECT", - "pr": "CI_PULL_REQUEST_NUMBER", - }, - { - "name": "Xcode Server", - "constant": "XCODE_SERVER", - "env": "XCS", - }, -]; - -function genEnvCondition(env: EnvMatch): string { - if (typeof env === "string") { - return `bun.getenvZ(${JSON.stringify(env)}) != null`; - } else if (Array.isArray(env)) { - return env - .map(itm => { - const res = genEnvCondition(itm); - if (res.includes(" or ")) return `(${res})`; - return res; - }) - .join(" and "); - } else if (typeof env === "object") { - if ("env" in env) { - return `bun.strings.containsComptime(bun.getenvZ(${JSON.stringify(env.env)}) orelse "", ${JSON.stringify(env.includes)})`; - } else if ("any" in env) { - return (env.any as string[]).map(genEnvCondition).join(" or "); - } else { - return Object.entries(env) - .map( - ([key, value]) => - `bun.strings.eqlComptime(bun.getenvZ(${JSON.stringify(key)}) orelse "", ${JSON.stringify(value)})`, - ) - .join(" and "); - } - } else throw new Error("Not implemented"); -} - -let codegen: string[] = []; -codegen.push(`/// Generated by src/codegen/ci_info.ts\n`); -codegen.push(`pub fn isCIUncachedGenerated() bool {\n`); -for (const extra of extras) { - codegen.push(` if (${genEnvCondition(extra)}) return true;\n`); -} -codegen.push(` return false;\n`); -codegen.push(`}\n`); -codegen.push(`\n`); -codegen.push(`/// Generated by src/codegen/ci_info.ts\n`); -codegen.push(`pub fn detectUncachedGenerated() ?[]const u8 {\n`); -for (const vendor of vendors) { - // Names are changed to match what `npm publish` uses - // https://github.com/npm/cli/blob/63d6a732c3c0e9c19fd4d147eaa5cc27c29b168d/workspaces/config/lib/definitions/definitions.js#L2129 - const npm_style_name = vendor.name.toLowerCase().replaceAll(" ", "-"); - codegen.push(` if (${genEnvCondition(vendor.env)}) return ${JSON.stringify(npm_style_name)};\n`); -} -codegen.push(` return null;\n`); -codegen.push(`}\n`); -codegen.push(`\n`); -codegen.push(`const bun = @import("bun");\n`); -const result = codegen.join(""); - -if (import.meta.main) { - const args = process.argv.slice(2); - const out = args[0]; - if (out) { - await Bun.write(out, result); - } else { - console.log(result); - } -} diff --git a/src/codegen/class-definitions.ts b/src/codegen/class-definitions.ts index 86827d34c65..37d55b88783 100644 --- a/src/codegen/class-definitions.ts +++ b/src/codegen/class-definitions.ts @@ -95,10 +95,12 @@ export class ClassDefinition { * Which language implements the native side of this class. * * The C++ wrapper output (`ZigGeneratedClasses.{h,cpp}`) is byte-identical - * regardless of this flag — it only selects whether the implementer thunks - * land in `ZigGeneratedClasses.zig` or `generated_classes.rs`. + * regardless of this flag; it only selects whether the `#[no_mangle]` + * implementer thunks are emitted into `generated_classes.rs`. Classes with + * `lang: "zig"` are skipped by that emitter and must provide the matching + * symbols themselves (remaining `.zig` siblings are reference-only). * - * @default "zig" + * @default "rust" */ lang?: "zig" | "rust"; /** diff --git a/src/codegen/cppbind.ts b/src/codegen/cppbind.ts index f5b3f479d78..7f5fd86c317 100644 --- a/src/codegen/cppbind.ts +++ b/src/codegen/cppbind.ts @@ -81,7 +81,7 @@ type SyntaxNode = import("@lezer/common").SyntaxNode; const { parser: cppParser } = await import("@lezer/cpp"); const { mkdir } = await import("fs/promises"); const { join, relative } = await import("path"); -const { bannedTypes, sharedTypes, typeDeclarations } = await import("./shared-types"); +const { bannedTypes, sharedTypes } = await import("./shared-types"); type Point = { line: number; @@ -1129,18 +1129,6 @@ async function main() { console.error(); } - const resultFilePath = join(dstDir, "cpp.zig"); - const resultContents = - typeDeclarations + - "\n" + - resultBindings.join("\n") + - "\n\nconst raw = struct {\n" + - resultRaw.join("\n") + - "\n};\n"; - if ((await readFileOrEmpty(resultFilePath)) !== resultContents) { - await Bun.write(resultFilePath, resultContents); - } - const rustFilePath = join(dstDir, "cpp.rs"); const rustContents = "// generated by cppbind.ts from functions marked with [[ZIG_EXPORT(mode)]]\n" + @@ -1168,7 +1156,7 @@ async function main() { " ".repeat(sin) + (errors.length > 0 ? "✗" : "✓") + " cppbind.ts generated bindings to " + - resultFilePath + + rustFilePath + (errors.length > 0 ? " with errors" : "") + " in " + (now - start) + diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index b659bb334bf..84679e22fa9 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -3542,10 +3542,11 @@ function writeCppSerializers() { return output; } -// ── Rust output: per-class thunks for `lang === "rust"` (default). ───────── -// Zig output is still emitted for every class so the C++ side's `extern` -// declarations stay satisfied; the Zig thunks for rust-lang classes simply go -// unreferenced once the Rust crate links. +// ── Rust output: per-class `#[no_mangle]` thunks for `lang === "rust"` +// (default). These satisfy the `extern` declarations in +// ZigGeneratedClasses.{h,cpp}; `lang === "zig"` classes are skipped here and +// must provide the symbols by other means until the .zig reference siblings +// are removed. ────────────────────────────────────────────────────────────── { const rustClasses = classes.filter(a => (a.lang ?? "rust") === "rust"); let totalSyms = 0; @@ -3567,137 +3568,6 @@ function writeCppSerializers() { ); } -await writeIfNotChanged(`${outBase}/ZigGeneratedClasses.zig`, [ - ZIG_GENERATED_CLASSES_HEADER, - - ...classes.map(a => generateZig(a.name, a).trim()).join("\n"), - "\n", - ` -comptime { - ${classes.map(a => `_ = ${className(a.name)};`).join("\n ")} -} - - - -// -- Avoid instantiating these log functions too many times -fn log_zig_method_call(typename: []const u8, method_name: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.{s}({d} args)", .{typename, method_name, callframe.arguments().len}); - } -} - -fn log_zig_getter(typename: []const u8, property_name: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("get {s}.{s}", .{typename, property_name}); - } -} - -fn log_zig_setter(typename: []const u8, property_name: []const u8, value: jsc.JSValue) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("set {s}.{s} = {?s}", .{typename, property_name, bun.tagName(jsc.JSValue, value)}); - } -} - -fn log_zig_finalize(typename: []const u8, ptr: *const anyopaque) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("~{s} 0x{x:8}", .{typename, @intFromPtr(ptr)}); - } -} - -fn log_zig_function_call(typename: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}({d} args)", .{typename, callframe.arguments().len}); - } -} - -fn log_zig_constructor(typename: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("new {s}({d} args)", .{typename, callframe.arguments().len}); - } -} - -fn log_zig_call(typename: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}({d} args)", .{typename, callframe.arguments().len}); - } -} - -fn log_zig_get_internal_properties(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("getInternalProperties {s}", .{typename}); - } -} - -fn log_zig_method(typename: []const u8, method_name: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.{s}({d} args)", .{typename, method_name, callframe.arguments().len}); - } -} - -fn log_zig_structured_clone_serialize(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("structuredCloneSerialize {s}", .{typename}); - } -} - -fn log_zig_structured_clone_transfer(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("structuredCloneTransfer {s}", .{typename}); - } -} - -fn log_zig_structured_clone_deserialize(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("structuredCloneDeserialize {s}", .{typename}); - } -} - -fn log_zig_from_js(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.fromJS", .{typename}); - } -} - -fn log_zig_from_js_direct(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.fromJSDirect", .{typename}); - } -} - -fn log_zig_get_constructor(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.constructor", .{typename}); - } -} - - -fn log_zig_to_js(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.toJS", .{typename}); - } -} - -fn log_zig_class_method(typename: []const u8, method_name: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.{s}({d} args)", .{typename, method_name, callframe.arguments().len}); - } -} - -fn log_zig_class_getter(typename: []const u8, property_name: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("static get {s}.{s}", .{typename, property_name}); - } -} - -fn log_zig_class_setter(typename: []const u8, property_name: []const u8, value: jsc.JSValue) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("static set {s}.{s} = {?s}", .{typename, property_name, bun.tagName(jsc.JSValue, value)}); - } -} - - `, -]); - if (!process.env.ONLY_ZIG) { const allHeaders = classes.map(a => generateHeader(a.name, a)); await writeIfNotChanged(`${outBase}/ZigGeneratedClasses.h`, [ diff --git a/src/codegen/generate-js2native.ts b/src/codegen/generate-js2native.ts index 86bfed72577..703f51e5d6e 100644 --- a/src/codegen/generate-js2native.ts +++ b/src/codegen/generate-js2native.ts @@ -1,10 +1,10 @@ -// This file implements the global state for $zig and $cpp preprocessor macros +// This file implements the global state for $native and $cpp preprocessor macros // as well as all the code it generates. // // For the actual parsing, see replacements.ts import path, { basename, sep } from "path"; -import { cap, readdirRecursiveWithExclusionsAndExtensionsSync } from "./helpers"; +import { readdirRecursiveWithExclusionsAndExtensionsSync } from "./helpers"; // interface NativeCall { @@ -25,7 +25,7 @@ interface WrapperCall { filename: string; } -type NativeCallType = "zig" | "cpp" | "bind"; +type NativeCallType = "native" | "cpp" | "bind"; const nativeCalls: NativeCall[] = []; const wrapperCalls: WrapperCall[] = []; @@ -33,28 +33,43 @@ const wrapperCalls: WrapperCall[] = []; const sourceFiles = readdirRecursiveWithExclusionsAndExtensionsSync( path.join(import.meta.dir, "../"), ["deps", "node_modules", "WebKit"], - [".cpp", ".zig", ".bind.ts"], + [".cpp", ".rs", ".bind.ts"], ); function callBaseName(x: string) { return x.split(/[^A-Za-z0-9]/g).pop()!; } +const nativeCallExtensions: Record = { + native: ".rs", + cpp: ".cpp", + bind: ".bind.ts", +}; + function resolveNativeFileId(call_type: NativeCallType, filename: string) { - const ext = call_type === "bind" ? ".bind.ts" : `.${call_type}`; + const ext = nativeCallExtensions[call_type]; if (!filename.endsWith(ext)) { throw new Error(`Expected filename for $${call_type} to have ${ext} extension, got ${JSON.stringify(filename)}`); } filename = filename.replaceAll("/", sep); - const resolved = sourceFiles.find(file => file.endsWith(sep + filename)); - if (!resolved) { + const matches = sourceFiles.filter(file => file.endsWith(sep + filename)); + if (matches.length === 0) { const fnName = call_type === "bind" ? "bindgenFn" : call_type; throw new Error(`Could not find file ${filename} in $${fnName} call`); } - if (call_type === "zig") { - return resolved; + if (call_type === "native") { + // The resolved path feeds both the exported symbol name and the Rust + // thunk target, so a multi-match cannot be silently first-match resolved. + if (matches.length > 1) { + const srcDir = path.join(import.meta.dir, ".."); + throw new Error( + `Ambiguous filename ${JSON.stringify(filename)} in $native call. Qualify it with a directory, one of: ` + + matches.map(m => JSON.stringify(path.relative(srcDir, m).replaceAll(sep, "/"))).join(", "), + ); + } + return matches[0]; } return filename; @@ -103,8 +118,8 @@ export function registerNativeCall( } function symbol(call: Pick) { - return call.type === "zig" - ? `JS2Zig__${call.filename ? normalizeSymbolPathPrefix(call.filename) + "_" : ""}${call.symbol.replace(/[^A-Za-z]/g, "_")}` + return call.type === "native" + ? `JS2Native__${call.filename ? normalizeSymbolPathPrefix(call.filename) + "_" : ""}${call.symbol.replace(/[^A-Za-z]/g, "_")}` : call.symbol; } @@ -116,7 +131,7 @@ function normalizeSymbolPathPrefix(input: string) { input = input.slice(bunDir.length); } - return input.replaceAll(".zig", "_zig_").replace(/[^A-Za-z]/g, "_"); + return input.replace(/\.rs$/, "").replace(/[^A-Za-z]/g, "_"); } function cppPointer(call: NativeCall) { @@ -131,7 +146,7 @@ export function getJS2NativeCPP() { const externs: string[] = []; const nativeCallStrings = nativeCalls - .filter(x => x.type === "zig") + .filter(x => x.type === "native") .flatMap( call => ( externs.push(`extern "C" SYSV_ABI JSC::EncodedJSValue ${symbol(call)}_workaround(Zig::GlobalObject*);` + "\n"), @@ -146,10 +161,10 @@ export function getJS2NativeCPP() { const wrapperCallStrings = wrapperCalls.map(x => { if (x.wrap_kind === "new-function") { return [ - (x.type === "zig" && + (x.type === "native" && externs.push( `BUN_DECLARE_HOST_FUNCTION(${symbol({ - type: "zig", + type: "native", symbol: x.symbol_target, filename: x.filename, })});`, @@ -207,68 +222,29 @@ export function getJS2NativeCPP() { ].join("\n"); } -export function getJS2NativeZig(gs2NativeZigPath: string) { - return [ - "//! This file is generated by src/codegen/generate-js2native.ts based on seen calls to the $zig() JS macro", - `const bun = @import("bun");`, - `const jsc = bun.jsc;`, - ...nativeCalls - .filter(x => x.type === "zig") - .flatMap(call => [ - `export fn ${symbol(call)}_workaround(global: *jsc.JSGlobalObject) callconv(jsc.conv) jsc.JSValue {`, - ` return jsc.toJSHostCall(global, @src(), @import(${JSON.stringify(path.relative(path.dirname(gs2NativeZigPath), call.filename))}).${call.symbol}, .{global});`, - "}", - ]), - ...wrapperCalls - .filter(x => x.type === "zig") - .flatMap(x => [ - `export fn ${symbol({ - type: "zig", - symbol: x.symbol_target, - filename: x.filename, - })}(global: *jsc.JSGlobalObject, call_frame: *jsc.CallFrame) callconv(jsc.conv) jsc.JSValue {`, - ` const function = @import(${JSON.stringify(path.relative(path.dirname(gs2NativeZigPath), x.filename))});`, - ` return @call(bun.callmod_inline, jsc.toJSHostFn(function.${x.symbol_target}), .{global, call_frame});`, - "}", - ]), - "comptime {", - ...nativeCalls - .filter(x => x.type === "bind") - .flatMap(x => { - const base = basename(x.filename.replace(/\.bind\.ts$/, "")); - return [ - ` @export(&bun.gen.${base}.create${cap(x.symbol)}Callback, .{ .name = ${JSON.stringify( - `js2native_bindgen_${base}_${x.symbol}`, - )} });`, - ]; - }), - "}", - ].join("\n"); -} - // ────────────────────────────────────────────────────────────────────────── -// Rust emitter — sibling of getJS2NativeZig(). +// Rust emitter. // -// Emits, for every $zig() call site, a `#[unsafe(no_mangle)] extern "C"` +// Emits, for every $native() call site, a `#[unsafe(no_mangle)] extern "C"` // thunk whose unmangled name and signature is byte-identical to the extern // the C++ side declares in GeneratedJS2Native.h. The C++ output is invariant; // only the implementer of the symbol changes. // // Two ABI shapes: -// • nativeCalls (type "zig") → `${sym}_workaround(global) -> JSValue` -// • wrapperCalls (type "zig") → `${sym}(global, callframe) -> JSValue` +// • nativeCalls (type "native") → `${sym}_workaround(global) -> JSValue` +// • wrapperCalls (type "native") → `${sym}(global, callframe) -> JSValue` // // Each thunk calls the hand-ported Rust function directly at -// `crate::::` — no trait, no +// `crate::::` — no trait, no // runtime panic fallback. A missing function is a compile error. // ────────────────────────────────────────────────────────────────────────── export function getJS2NativeRust() { // Symbols already hand-exported in src/ (via `export_host_fn!` or - // `#[unsafe(export_name = "JS2Zig__…")]`) — skip emitting a thunk for these - // so the linker doesn't see two definitions. + // `#[unsafe(export_name = "JS2Native__…")]`) — skip emitting a thunk for + // these so the linker doesn't see two definitions. const handExported = new Set([ - "JS2Zig___src_runtime_dns_jsc_dns_zig__Resolver_getRuntimeDefaultResultOrderOption", - "JS2Zig___src_runtime_dns_jsc_dns_zig__Resolver_newResolver", + "JS2Native___src_runtime_dns_jsc_dns_Resolver_getRuntimeDefaultResultOrderOption", + "JS2Native___src_runtime_dns_jsc_dns_Resolver_newResolver", ]); const srcRoot = path.resolve(import.meta.dir, ".."); @@ -279,13 +255,14 @@ export function getJS2NativeRust() { .replace(/[.\-]/g, "_") .toLowerCase(); - // `src/runtime/node/node_util_binding.zig` + `parseEnv` + // `src/runtime/node/node_util_binding.rs` + `parseEnv` // → `crate::node::node_util_binding::parse_env` - // `src/ini/ini.zig` + `IniTestingAPIs.parse` (outside bun_runtime) - // → `crate::dispatch::js2native::ini_ini_testing_apis_parse` (single - // landing pad the port-agents fill in; still a compile error if missing). + // `src/install_jsc/ini_jsc.rs` + `IniTestingAPIs.parse` (outside bun_runtime) + // → `crate::dispatch::js2native::install_jsc_ini_jsc_ini_testing_ap_is_parse` + // (flat landing pad of `pub use` re-exports; a missing target is still a + // compile error). const rustTarget = (filename: string, sym: string) => { - const rel = path.relative(srcRoot, filename).replace(/\.zig$/, ""); + const rel = path.relative(srcRoot, filename).replace(/\.rs$/, ""); const segs = rel.split(path.sep); const fn = sym .split(".") @@ -306,13 +283,13 @@ export function getJS2NativeRust() { const thunks: string[] = []; const seen = new Set(); - for (const call of nativeCalls.filter(x => x.type === "zig")) { + for (const call of nativeCalls.filter(x => x.type === "native")) { const sym = `${symbol(call)}_workaround`; if (seen.has(sym)) continue; seen.add(sym); const target = rustTarget(call.filename, call.symbol); thunks.push( - `// $zig(${path.basename(call.filename)}, ${call.symbol})`, + `// $native(${path.basename(call.filename)}, ${call.symbol})`, `bun_jsc::jsc_host_abi! {`, ` #[unsafe(no_mangle)]`, ` pub unsafe fn ${sym}(global: &JSGlobalObject) -> JSValue {`, @@ -323,8 +300,8 @@ export function getJS2NativeRust() { ); } - for (const x of wrapperCalls.filter(x => x.type === "zig")) { - const sym = symbol({ type: "zig", symbol: x.symbol_target, filename: x.filename }); + for (const x of wrapperCalls.filter(x => x.type === "native")) { + const sym = symbol({ type: "native", symbol: x.symbol_target, filename: x.filename }); if (seen.has(sym)) continue; seen.add(sym); if (handExported.has(sym)) { @@ -333,7 +310,7 @@ export function getJS2NativeRust() { } const target = rustTarget(x.filename, x.symbol_target); thunks.push( - `// $zig(${path.basename(x.filename)}, ${x.symbol_target})`, + `// $native(${path.basename(x.filename)}, ${x.symbol_target})`, `bun_jsc::jsc_host_abi! {`, ` #[unsafe(no_mangle)]`, ` pub unsafe fn ${sym}(global: &JSGlobalObject, callframe: &CallFrame) -> JSValue {`, @@ -347,7 +324,7 @@ export function getJS2NativeRust() { return [ `// Auto-generated by src/codegen/generate-js2native.ts — DO NOT EDIT.`, `//`, - `// \`#[unsafe(no_mangle)] extern "C"\` thunks satisfying the JS2Zig__* externs`, + `// \`#[unsafe(no_mangle)] extern "C"\` thunks satisfying the JS2Native__* externs`, `// declared by GeneratedJS2Native.h (the JS-module → native dispatch table).`, `// Each thunk calls the hand-ported Rust function directly; a missing`, `// function is a compile error in \`cargo check -p bun_runtime\`.`, @@ -365,17 +342,31 @@ export function getJS2NativeRust() { } export function getJS2NativeDTS() { + // Accept both the bare basename and the full src-relative path: call sites + // use the latter to disambiguate when two files share a basename. A + // basename that appears in more than one directory is rejected by + // resolveNativeFileId, so don't offer it as a valid key. + const srcDir = path.join(import.meta.dir, ".."); + const rustFiles = sourceFiles.filter(f => f.endsWith(".rs")); + const basenameCounts = new Map(); + for (const file of rustFiles) { + const name = basename(file); + basenameCounts.set(name, (basenameCounts.get(name) ?? 0) + 1); + } + const rustNames = new Set(); + for (const file of rustFiles) { + const name = basename(file); + if (basenameCounts.get(name) === 1) rustNames.add(name); + rustNames.add(path.relative(srcDir, file).replaceAll(sep, "/")); + } + return [ "declare type NativeFilenameCPP = " + sourceFiles .filter(x => x.endsWith("cpp")) .map(x => JSON.stringify(basename(x))) .join("|"), - "declare type NativeFilenameZig = " + - sourceFiles - .filter(x => x.endsWith("zig")) - .map(x => JSON.stringify(basename(x))) - .join("|"), + "declare type NativeFilenameRust = " + [...rustNames].map(x => JSON.stringify(x)).join("|"), "", ].join("\n"); } diff --git a/src/codegen/generate-node-errors.ts b/src/codegen/generate-node-errors.ts index 4bab0c5cf38..7180204ef5c 100644 --- a/src/codegen/generate-node-errors.ts +++ b/src/codegen/generate-node-errors.ts @@ -174,5 +174,4 @@ declare function $${code}(message: string): ${namedError};\n`; writeIfNotChanged(path.join(outputDir, "ErrorCode+List.h"), enumHeader); writeIfNotChanged(path.join(outputDir, "ErrorCode+Data.h"), listHeader); -writeIfNotChanged(path.join(outputDir, "ErrorCode.zig"), zig); writeIfNotChanged(path.join(outputDir, "ErrorCode.d.ts"), dts); diff --git a/src/codegen/replacements.ts b/src/codegen/replacements.ts index 10dc18c4fbe..6af9ac548a1 100644 --- a/src/codegen/replacements.ts +++ b/src/codegen/replacements.ts @@ -165,8 +165,8 @@ export interface ReplacementRule { export const function_replacements = [ "$debug", "$assert", - "$zig", - "$newZigFunction", + "$native", + "$newNativeFunction", "$cpp", "$newCppFunction", "$isPromiseFulfilled", @@ -222,8 +222,8 @@ export function applyReplacements(src: string, length: number) { rest2, true, ]; - } else if (["zig", "cpp", "newZigFunction", "newCppFunction"].includes(name)) { - const kind = name.includes("ig") ? "zig" : "cpp"; + } else if (["native", "cpp", "newNativeFunction", "newCppFunction"].includes(name)) { + const kind = name === "native" || name === "newNativeFunction" ? "native" : "cpp"; const is_create_fn = name.startsWith("new"); const inner = sliceSourceCode(rest, true); diff --git a/src/js/builtins/Ipc.ts b/src/js/builtins/Ipc.ts index 8971d6290f0..65e380007e9 100644 --- a/src/js/builtins/Ipc.ts +++ b/src/js/builtins/Ipc.ts @@ -191,7 +191,7 @@ export function serialize(_message, _handle, _options) { // Remove handle from socket object, it will be closed when the socket // will be sent if (!options?.keepOpen) { - // we can use a $newZigFunction to have it unset the callback + // we can use a $newNativeFunction to have it unset the callback internal_handle.onread = nop; socket._handle = null; socket.setTimeout(0); @@ -212,7 +212,7 @@ export function serialize(_message, _handle, _options) { * @returns {void} */ export function parseHandle(target, serialized, fd) { - const emit = $newZigFunction("ipc.zig", "emitHandleIPCMessage", 3); + const emit = $newNativeFunction("ipc.rs", "emitHandleIPCMessage", 3); const net = require("node:net"); // const dgram = require("node:dgram"); switch (serialized.type) { diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index bae5774be76..56abd1cb085 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -489,7 +489,7 @@ export function windowsEnv( export function getChannel() { const EventEmitter = require("node:events"); - const setRef = $newZigFunction("node_cluster_binding.zig", "setRef", 1); + const setRef = $newNativeFunction("node_cluster_binding.rs", "setRef", 1); return new (class Control extends EventEmitter { constructor() { super(); diff --git a/src/js/bun/ffi.ts b/src/js/bun/ffi.ts index 07886f902b7..f354dc3b60c 100644 --- a/src/js/bun/ffi.ts +++ b/src/js/bun/ffi.ts @@ -421,7 +421,7 @@ const native = { }, }; -const ccFn = $newZigFunction("ffi.zig", "Bun__FFI__cc", 1); +const ccFn = $newNativeFunction("ffi_body.rs", "Bun__FFI__cc", 1); function normalizePath(path) { if (typeof path === "string" && path?.startsWith?.("file:")) { diff --git a/src/js/internal-for-testing.ts b/src/js/internal-for-testing.ts index 2f9a0fa67b6..f4fbaa4e6bc 100644 --- a/src/js/internal-for-testing.ts +++ b/src/js/internal-for-testing.ts @@ -26,15 +26,17 @@ export const xxHash3ForTesting: (view: ArrayBufferView, seed?: number | bigint) export const SQL = $cpp("JSSQLStatement.cpp", "createJSSQLStatementConstructor"); export const patchInternals = { - parse: $newZigFunction("patch.zig", "TestingAPIs.parse", 1), - apply: $newZigFunction("patch.zig", "TestingAPIs.apply", 2), - makeDiff: $newZigFunction("patch.zig", "TestingAPIs.makeDiff", 2), + parse: $newNativeFunction("patch_jsc/testing.rs", "TestingAPIs.parse", 1), + apply: $newNativeFunction("patch_jsc/testing.rs", "TestingAPIs.apply", 2), + makeDiff: $newNativeFunction("patch_jsc/testing.rs", "TestingAPIs.makeDiff", 2), }; export const internalSourceMap = { - fromVLQ: $newZigFunction("sourcemap/InternalSourceMap.zig", "TestingAPIs.fromVLQ", 1) as (vlq: string) => Uint8Array, - toVLQ: $newZigFunction("sourcemap/InternalSourceMap.zig", "TestingAPIs.toVLQ", 1) as (blob: Uint8Array) => string, - find: $newZigFunction("sourcemap/InternalSourceMap.zig", "TestingAPIs.find", 3) as ( + fromVLQ: $newNativeFunction("sourcemap/InternalSourceMap.rs", "TestingAPIs.fromVLQ", 1) as ( + vlq: string, + ) => Uint8Array, + toVLQ: $newNativeFunction("sourcemap/InternalSourceMap.rs", "TestingAPIs.toVLQ", 1) as (blob: Uint8Array) => string, + find: $newNativeFunction("sourcemap/InternalSourceMap.rs", "TestingAPIs.find", 3) as ( blob: Uint8Array, line: number, col: number, @@ -47,14 +49,14 @@ export const internalSourceMap = { } | null, }; -const shellLex = $newZigFunction("shell.zig", "TestingAPIs.shellLex", 2); -const shellParse = $newZigFunction("shell.zig", "TestingAPIs.shellParse", 2); +const shellLex = $newNativeFunction("shell_body.rs", "TestingAPIs.shellLex", 2); +const shellParse = $newNativeFunction("shell_body.rs", "TestingAPIs.shellParse", 2); -export const sslCtxLiveCount = $newZigFunction("SecureContext.zig", "jsLiveCount", 0); +export const sslCtxLiveCount = $newNativeFunction("SecureContext.rs", "jsLiveCount", 0); -export const escapeRegExp = $newZigFunction("escapeRegExp.zig", "jsEscapeRegExp", 1); -export const escapeRegExpForPackageNameMatching = $newZigFunction( - "escapeRegExp.zig", +export const escapeRegExp = $newNativeFunction("escapeRegExp.rs", "jsEscapeRegExp", 1); +export const escapeRegExpForPackageNameMatching = $newNativeFunction( + "escapeRegExp.rs", "jsEscapeRegExpForPackageNameMatching", 1, ); @@ -70,33 +72,33 @@ export const shellInternals = { * const isDisabled = builtinDisabled("cp") * ``` */ - builtinDisabled: $newZigFunction("shell.zig", "TestingAPIs.disabledOnThisPlatform", 1), + builtinDisabled: $newNativeFunction("shell_body.rs", "TestingAPIs.disabledOnThisPlatform", 1), }; export const subprocessInternals = { - injectStdioReadError: $newZigFunction("subprocess.zig", "TestingAPIs.injectStdioReadError", 2) as ( + injectStdioReadError: $newNativeFunction("subprocess.rs", "TestingAPIs.injectStdioReadError", 2) as ( subprocess: import("bun").Subprocess, kind: "stdout" | "stderr", ) => boolean, }; export const iniInternals = { - parse: $newZigFunction("ini.zig", "IniTestingAPIs.parse", 1), - loadNpmrc: $newZigFunction("ini.zig", "IniTestingAPIs.loadNpmrcFromJS", 2), + parse: $newNativeFunction("ini_jsc.rs", "IniTestingAPIs.parse", 1), + loadNpmrc: $newNativeFunction("ini_jsc.rs", "IniTestingAPIs.loadNpmrcFromJS", 2), }; export const cssInternals = { - minifyTestWithOptions: $newZigFunction("css_internals.zig", "minifyTestWithOptions", 3), - minifyErrorTestWithOptions: $newZigFunction("css_internals.zig", "minifyErrorTestWithOptions", 3), - testWithOptions: $newZigFunction("css_internals.zig", "testWithOptions", 3), - prefixTestWithOptions: $newZigFunction("css_internals.zig", "prefixTestWithOptions", 3), - minifyTest: $newZigFunction("css_internals.zig", "minifyTest", 3), - prefixTest: $newZigFunction("css_internals.zig", "prefixTest", 3), - _test: $newZigFunction("css_internals.zig", "_test", 3), - attrTest: $newZigFunction("css_internals.zig", "attrTest", 3), + minifyTestWithOptions: $newNativeFunction("css_internals.rs", "minifyTestWithOptions", 3), + minifyErrorTestWithOptions: $newNativeFunction("css_internals.rs", "minifyErrorTestWithOptions", 3), + testWithOptions: $newNativeFunction("css_internals.rs", "testWithOptions", 3), + prefixTestWithOptions: $newNativeFunction("css_internals.rs", "prefixTestWithOptions", 3), + minifyTest: $newNativeFunction("css_internals.rs", "minifyTest", 3), + prefixTest: $newNativeFunction("css_internals.rs", "prefixTest", 3), + _test: $newNativeFunction("css_internals.rs", "_test", 3), + attrTest: $newNativeFunction("css_internals.rs", "attrTest", 3), }; -export const crash_handler = $zig("crash_handler.zig", "js_bindings.generate") as { +export const crash_handler = $native("crash_handler_jsc.rs", "js_bindings.generate") as { getMachOImageZeroOffset: () => number; segfault: () => void; panic: () => void; @@ -105,12 +107,12 @@ export const crash_handler = $zig("crash_handler.zig", "js_bindings.generate") a raiseIgnoringPanicHandler: () => void; }; -export const upgrade_test_helpers = $zig("upgrade_command.zig", "upgrade_js_bindings.generate") as { +export const upgrade_test_helpers = $native("upgrade_command.rs", "upgrade_js_bindings.generate") as { openTempDirWithoutSharingDelete: () => void; closeTempDirHandle: () => void; }; -export const install_test_helpers = $zig("install_binding.zig", "bun_install_js_bindings.generate") as { +export const install_test_helpers = $native("install_binding.rs", "bun_install_js_bindings.generate") as { /** * Returns the lockfile at the given path as an object. */ @@ -126,25 +128,25 @@ export const nativeFrameForTesting: (callback: () => void) => void = $cpp( // Linux-only. Create an in-memory file descriptor with a preset size. // You should call fs.closeSync(fd) when you're done with it. -export const memfd_create: (size: number) => number = $newZigFunction( - "node_fs_binding.zig", +export const memfd_create: (size: number) => number = $newNativeFunction( + "node_fs_binding.rs", "createMemfdForTesting", 1, ); -export const createStatsForIno: (ino: bigint, big: boolean) => any = $newZigFunction( - "Stat.zig", +export const createStatsForIno: (ino: bigint, big: boolean) => any = $newNativeFunction( + "Stat.rs", "createStatsForIno", 2, ); -export const setSyntheticAllocationLimitForTesting: (limit: number) => number = $newZigFunction( - "virtual_machine_exports.zig", +export const setSyntheticAllocationLimitForTesting: (limit: number) => number = $newNativeFunction( + "virtual_machine_exports.rs", "Bun__setSyntheticAllocationLimitForTesting", 1, ); -export const npm_manifest_test_helpers = $zig("npm.zig", "PackageManifest.bindings.generate") as { +export const npm_manifest_test_helpers = $native("npm.rs", "PackageManifest.bindings.generate") as { /** * Returns the parsed manifest file. Currently only returns an array of available versions. */ @@ -153,32 +155,28 @@ export const npm_manifest_test_helpers = $zig("npm.zig", "PackageManifest.bindin // Like npm-package-arg, sort of https://www.npmjs.com/package/npm-package-arg export type Dependency = any; -export const npa: (name: string) => Dependency = $newZigFunction("dependency.zig", "fromJS", 1); +export const npa: (name: string) => Dependency = $newNativeFunction("dependency.rs", "fromJS", 1); export const npmTag: ( name: string, ) => undefined | "npm" | "dist_tag" | "tarball" | "folder" | "symlink" | "workspace" | "git" | "github" = - $newZigFunction("dependency.zig", "Version.Tag.inferFromJS", 1); + $newNativeFunction("dependency.rs", "Version.Tag.inferFromJS", 1); -export const readTarball: (tarball: string) => any = $newZigFunction("pack_command.zig", "bindings.jsReadTarball", 1); +export const readTarball: (tarball: string) => any = $newNativeFunction("pack_command.rs", "bindings.jsReadTarball", 1); -export const isArchitectureMatch: (architecture: string[]) => boolean = $newZigFunction( - "npm.zig", +export const isArchitectureMatch: (architecture: string[]) => boolean = $newNativeFunction( + "npm.rs", "Architecture.jsFunctionArchitectureIsMatch", 1, ); -export const isOperatingSystemMatch: (operatingSystem: string[]) => boolean = $newZigFunction( - "npm.zig", +export const isOperatingSystemMatch: (operatingSystem: string[]) => boolean = $newNativeFunction( + "npm.rs", "OperatingSystem.jsFunctionOperatingSystemIsMatch", 1, ); -export const createSocketPair: () => [number, number] = $newZigFunction( - "runtime/socket/socket.zig", - "jsCreateSocketPair", - 0, -); +export const createSocketPair: () => [number, number] = $newNativeFunction("socket_body.rs", "jsCreateSocketPair", 0); export const isModuleResolveFilenameSlowPathEnabled: () => boolean = $newCppFunction( "NodeModuleModule.cpp", @@ -186,14 +184,14 @@ export const isModuleResolveFilenameSlowPathEnabled: () => boolean = $newCppFunc 0, ); -export const frameworkRouterInternals = $zig("FrameworkRouter.zig", "JSFrameworkRouter.getBindings") as { +export const frameworkRouterInternals = $native("FrameworkRouter.rs", "JSFrameworkRouter.getBindings") as { parseRoutePattern: (style: string, pattern: string) => null | { kind: string; pattern: string }; FrameworkRouter: { new (opts: any): any; }; }; -export const bindgen = $zig("bindgen_test.zig", "getBindgenTestFunctions") as { +export const bindgen = $native("bindgen_test.rs", "getBindgenTestFunctions") as { add: (a: any, b: any) => number; requiredAndOptionalArg: (a: any, b?: any, c?: any, d?: any) => number; }; @@ -237,7 +235,7 @@ export const arrayBufferViewHasBuffer = $newCppFunction( ); export const timerInternals = { - timerClockMs: $newZigFunction("runtime/timer/Timer.zig", "internal_bindings.timerClockMs", 0), + timerClockMs: $newNativeFunction("runtime/timer/Timer.rs", "internal_bindings.timerClockMs", 0), }; export const decodeURIComponentSIMD = $newCppFunction( @@ -247,9 +245,9 @@ export const decodeURIComponentSIMD = $newCppFunction( ); export const getDevServerDeinitCount = $bindgenFn("DevServer.bind.ts", "getDeinitCountForTesting"); -export const getCounters = $newZigFunction("Counters.zig", "createCountersObject", 0); -export const linearFifoOrderedRemoveProbe = $newZigFunction( - "collections/linear_fifo.zig", +export const getCounters = $newNativeFunction("Counters.rs", "createCountersObject", 0); +export const linearFifoOrderedRemoveProbe = $newNativeFunction( + "collections/linear_fifo.rs", "TestingAPIs.orderedRemoveProbe", 1, ) as (scenario: number) => number[]; @@ -260,11 +258,7 @@ interface setSocketOptionsFn { (socket: Bun.Socket, recvBuffer: 2, size: number): void; } -export const setSocketOptions: setSocketOptionsFn = $newZigFunction( - "runtime/socket/socket.zig", - "jsSetSocketOptions", - 3, -); +export const setSocketOptions: setSocketOptionsFn = $newNativeFunction("socket_body.rs", "jsSetSocketOptions", 3); type SerializationContext = "worker" | "window" | "postMessage" | "default"; export const structuredCloneAdvanced: ( value: any, @@ -291,27 +285,27 @@ export const lowercaseHeaderNameSIMD: (name: string) => string = $newCppFunction ); export const getEventLoopStats: () => { activeTasks: number; concurrentRef: number; numPolls: number } = - $newZigFunction("event_loop.zig", "getActiveTasks", 0); + $newNativeFunction("event_loop.rs", "getActiveTasks", 0); export const hostedGitInfo = { - parseUrl: $newZigFunction("hosted_git_info.zig", "TestingAPIs.jsParseUrl", 1), - fromUrl: $newZigFunction("hosted_git_info.zig", "TestingAPIs.jsFromUrl", 1), + parseUrl: $newNativeFunction("hosted_git_info.rs", "TestingAPIs.jsParseUrl", 1), + fromUrl: $newNativeFunction("hosted_git_info.rs", "TestingAPIs.jsFromUrl", 1), }; -export const translateUVErrorToE: (code: number) => string | undefined = $newZigFunction( - "sys.zig", +export const translateUVErrorToE: (code: number) => string | undefined = $newNativeFunction( + "sys/Error.rs", "TestingAPIs.translateUVErrorToE", 1, ); -export const translateNtStatusToE: (status: number) => string | undefined = $newZigFunction( - "sys.zig", +export const translateNtStatusToE: (status: number) => string | undefined = $newNativeFunction( + "sys/Error.rs", "TestingAPIs.translateNtStatusToE", 1, ); -export const sysErrorNameFromLibuv: (errno: number) => string | undefined = $newZigFunction( - "sys/Error.zig", +export const sysErrorNameFromLibuv: (errno: number) => string | undefined = $newNativeFunction( + "sys/Error.rs", "TestingAPIs.sysErrorNameFromLibuv", 1, ); @@ -322,7 +316,7 @@ export const sigactionLayout: () => installed: { handler: number; flags: number }; readback: { handler: number; flags: number }; sizeof: number; - } = $newZigFunction("sys.zig", "TestingAPIs.sigactionLayout", 0); + } = $newNativeFunction("sys/Error.rs", "TestingAPIs.sigactionLayout", 0); export const stringsInternals = { /** @@ -331,25 +325,27 @@ export const stringsInternals = { * path is otherwise only reachable from Windows `bun build --compile` * metadata, so this binding lets us exercise it on all platforms. */ - toUTF16AllocSentinel: $newZigFunction("string/immutable/unicode.zig", "TestingAPIs.toUTF16AllocSentinel", 1) as ( - bytes: Uint8Array, - ) => string, + toUTF16AllocSentinel: $newNativeFunction( + "bun_core/string/immutable/unicode.rs", + "TestingAPIs.toUTF16AllocSentinel", + 1, + ) as (bytes: Uint8Array) => string, }; export const fetchH2Internals = { - liveCounts: $newZigFunction("http/H2Client.zig", "TestingAPIs.liveCounts", 0) as () => { + liveCounts: $newNativeFunction("http/H2Client.rs", "TestingAPIs.liveCounts", 0) as () => { sessions: number; streams: number; }, }; export const fetchH3Internals = { - liveCounts: $newZigFunction("http/H3Client.zig", "TestingAPIs.quicLiveCounts", 0) as () => { + liveCounts: $newNativeFunction("http/H3Client.rs", "TestingAPIs.quicLiveCounts", 0) as () => { sessions: number; streams: number; }, }; export const fileSinkInternals = { - liveCount: $newZigFunction("runtime/webcore/FileSink.zig", "TestingAPIs.fileSinkLiveCount", 0) as () => number, + liveCount: $newNativeFunction("runtime/webcore/FileSink.rs", "TestingAPIs.fileSinkLiveCount", 0) as () => number, }; diff --git a/src/js/internal/assert/myers_diff.ts b/src/js/internal/assert/myers_diff.ts index f47b61c41a1..75d4de0ebed 100644 --- a/src/js/internal/assert/myers_diff.ts +++ b/src/js/internal/assert/myers_diff.ts @@ -27,7 +27,7 @@ declare namespace Internal { const kNopLinesToCollapse = 5; -const { myersDiff } = $zig("node_assert_binding.zig", "generate") as typeof Internal; +const { myersDiff } = $native("node_assert_binding.rs", "generate") as typeof Internal; function printSimpleMyersDiff(diff: Diff[]) { let message = ""; diff --git a/src/js/internal/cluster/RoundRobinHandle.ts b/src/js/internal/cluster/RoundRobinHandle.ts index 36c39a87b08..9c943b35916 100644 --- a/src/js/internal/cluster/RoundRobinHandle.ts +++ b/src/js/internal/cluster/RoundRobinHandle.ts @@ -3,7 +3,7 @@ const { kHandle } = require("internal/shared"); let net; -const sendHelper = $newZigFunction("node_cluster_binding.zig", "sendHelperPrimary", 4); +const sendHelper = $newNativeFunction("node_cluster_binding.rs", "sendHelperPrimary", 4); const ArrayIsArray = Array.isArray; diff --git a/src/js/internal/cluster/child.ts b/src/js/internal/cluster/child.ts index 24c102da762..4e48dc98988 100644 --- a/src/js/internal/cluster/child.ts +++ b/src/js/internal/cluster/child.ts @@ -2,8 +2,8 @@ const EventEmitter = require("node:events"); const Worker = require("internal/cluster/Worker"); const path = require("node:path"); -const sendHelper = $newZigFunction("node_cluster_binding.zig", "sendHelperChild", 3); -const onInternalMessage = $newZigFunction("node_cluster_binding.zig", "onInternalMessageChild", 2); +const sendHelper = $newNativeFunction("node_cluster_binding.rs", "sendHelperChild", 3); +const onInternalMessage = $newNativeFunction("node_cluster_binding.rs", "onInternalMessageChild", 2); const FunctionPrototype = Function.prototype; const ArrayPrototypeJoin = Array.prototype.join; @@ -36,7 +36,7 @@ cluster._setupWorker = function () { // make sure the process.once("disconnect") doesn't count as a ref // before calling, check if the channel is refd. if it isn't, then unref it after calling process.once(); - $newZigFunction("node_cluster_binding.zig", "channelIgnoreOneDisconnectEventListener", 0)(); + $newNativeFunction("node_cluster_binding.rs", "channelIgnoreOneDisconnectEventListener", 0)(); process.once("disconnect", () => { process.channel = null; worker.emit("disconnect"); diff --git a/src/js/internal/cluster/primary.ts b/src/js/internal/cluster/primary.ts index 9a046c8a875..4db5d478b06 100644 --- a/src/js/internal/cluster/primary.ts +++ b/src/js/internal/cluster/primary.ts @@ -4,8 +4,8 @@ const RoundRobinHandle = require("internal/cluster/RoundRobinHandle"); const path = require("node:path"); const { throwNotImplemented, kHandle } = require("internal/shared"); -const sendHelper = $newZigFunction("node_cluster_binding.zig", "sendHelperPrimary", 4); -const onInternalMessage = $newZigFunction("node_cluster_binding.zig", "onInternalMessagePrimary", 3); +const sendHelper = $newNativeFunction("node_cluster_binding.rs", "sendHelperPrimary", 4); +const onInternalMessage = $newNativeFunction("node_cluster_binding.rs", "onInternalMessagePrimary", 3); let child_process; diff --git a/src/js/internal/fs/binding.ts b/src/js/internal/fs/binding.ts index 656eabc8504..bdb6d6a767a 100644 --- a/src/js/internal/fs/binding.ts +++ b/src/js/internal/fs/binding.ts @@ -1,3 +1,3 @@ // The native `node:fs` binding (`createBinding`), created once here // and shared by `node:fs`, `node:fs/promises`, and the lazily loaded `internal/fs/*` modules. -export default $zig("node_fs_binding.zig", "createBinding") as $ZigGeneratedClasses.NodeJSFS; +export default $native("node_fs_binding.rs", "createBinding") as $ZigGeneratedClasses.NodeJSFS; diff --git a/src/js/internal/http.ts b/src/js/internal/http.ts index 761a880ded4..5d9471906c9 100644 --- a/src/js/internal/http.ts +++ b/src/js/internal/http.ts @@ -350,8 +350,8 @@ function emitErrorNt(msg, err, callback) { msg.emit("error", err); } } -const setMaxHTTPHeaderSize = $newZigFunction("node_http_binding.zig", "setMaxHTTPHeaderSize", 1); -const getMaxHTTPHeaderSize = $newZigFunction("node_http_binding.zig", "getMaxHTTPHeaderSize", 0); +const setMaxHTTPHeaderSize = $newNativeFunction("node_http_binding.rs", "setMaxHTTPHeaderSize", 1); +const getMaxHTTPHeaderSize = $newNativeFunction("node_http_binding.rs", "getMaxHTTPHeaderSize", 0); const kOutHeaders = Symbol("kOutHeaders"); const kNeedDrain = Symbol("kNeedDrain"); const kProxyConfig = Symbol("kProxyConfig"); diff --git a/src/js/internal/sql/mysql.ts b/src/js/internal/sql/mysql.ts index 187efe17d0e..fac478d8e60 100644 --- a/src/js/internal/sql/mysql.ts +++ b/src/js/internal/sql/mysql.ts @@ -18,7 +18,7 @@ const { createConnection: createMySQLConnection, createQuery: createMySQLQuery, init: initMySQL, -} = $zig("mysql.zig", "createBinding") as MySQLDotZig; +} = $native("mysql.rs", "createBinding") as MySQLNativeBinding; function wrapError(error: Error | MySQLErrorOptions) { if (Error.isError(error)) { @@ -79,7 +79,7 @@ initMySQL( }, ); -export interface MySQLDotZig { +export interface MySQLNativeBinding { init: ( onResolveQuery: ( query: Query, diff --git a/src/js/internal/sql/postgres.ts b/src/js/internal/sql/postgres.ts index c06ba2d60de..45242cdb94d 100644 --- a/src/js/internal/sql/postgres.ts +++ b/src/js/internal/sql/postgres.ts @@ -26,7 +26,7 @@ const { createConnection: createPostgresConnection, createQuery: createPostgresQuery, init: initPostgres, -} = $zig("postgres.zig", "createBinding") as PostgresDotZig; +} = $native("postgres.rs", "createBinding") as PostgresNativeBinding; const cmds = ["", "INSERT", "DELETE", "UPDATE", "MERGE", "SELECT", "MOVE", "FETCH", "COPY"]; @@ -308,7 +308,7 @@ initPostgres( }, ); -export interface PostgresDotZig { +export interface PostgresNativeBinding { init: ( onResolveQuery: ( query: Query, diff --git a/src/js/internal/streams/iter/transform.ts b/src/js/internal/streams/iter/transform.ts index bada684f555..3ce1a716179 100644 --- a/src/js/internal/streams/iter/transform.ts +++ b/src/js/internal/streams/iter/transform.ts @@ -13,9 +13,9 @@ const { isArrayBufferView, isAnyArrayBuffer } = require("node:util/types"); const { kValidatedTransform } = require("internal/streams/iter/types"); const { checkRangesOrGetDefault, validateFiniteNumber, validateObject } = require("internal/validators"); -const NativeZlib = $zig("node_zlib_binding.zig", "NativeZlib"); -const NativeBrotli = $zig("node_zlib_binding.zig", "NativeBrotli"); -const NativeZstd = $zig("node_zlib_binding.zig", "NativeZstd"); +const NativeZlib = $native("node_zlib_binding.rs", "NativeZlib"); +const NativeBrotli = $native("node_zlib_binding.rs", "NativeBrotli"); +const NativeZstd = $native("node_zlib_binding.rs", "NativeZstd"); const constants = process.binding("constants").zlib; const Uint8ArraySlice = Uint8Array.prototype.slice; diff --git a/src/js/internal/util/inspect.js b/src/js/internal/util/inspect.js index d531a40b744..2abe92fd6b2 100644 --- a/src/js/internal/util/inspect.js +++ b/src/js/internal/util/inspect.js @@ -143,8 +143,8 @@ const ONLY_ENUMERABLE = 2; * * @type {(value: string) => string[] | undefined} */ -const extractedSplitNewLinesFastPathStringsOnly = $newZigFunction( - "node_util_binding.zig", +const extractedSplitNewLinesFastPathStringsOnly = $newNativeFunction( + "node_util_binding.rs", "extractedSplitNewLinesFastPathStringsOnly", 1, ); diff --git a/src/js/internal/webstreams_adapters.ts b/src/js/internal/webstreams_adapters.ts index 002c257ff0e..5cdbde0cefc 100644 --- a/src/js/internal/webstreams_adapters.ts +++ b/src/js/internal/webstreams_adapters.ts @@ -19,7 +19,7 @@ const { isAnyArrayBuffer } = require("node:util/types"); const eos = require("internal/streams/end-of-stream"); const { kEosNodeSynchronousCallback } = eos; -const normalizeEncoding = $newZigFunction("node_util_binding.zig", "normalizeEncoding", 1); +const normalizeEncoding = $newNativeFunction("node_util_binding.rs", "normalizeEncoding", 1); const ArrayPrototypeFilter = Array.prototype.filter; const ArrayPrototypeMap = Array.prototype.map; diff --git a/src/js/node/_http2_upgrade.ts b/src/js/node/_http2_upgrade.ts index 74a1c522ece..38692b3cadf 100644 --- a/src/js/node/_http2_upgrade.ts +++ b/src/js/node/_http2_upgrade.ts @@ -1,5 +1,5 @@ const { Duplex } = require("node:stream"); -const upgradeDuplexToTLS = $newZigFunction("runtime/socket/socket.zig", "jsUpgradeDuplexToTLS", 2); +const upgradeDuplexToTLS = $newNativeFunction("socket_body.rs", "jsUpgradeDuplexToTLS", 2); interface NativeHandle { resume(): void; diff --git a/src/js/node/_http_server.ts b/src/js/node/_http_server.ts index 0cc07212035..c4bdd477072 100644 --- a/src/js/node/_http_server.ts +++ b/src/js/node/_http_server.ts @@ -76,8 +76,8 @@ const { kIncomingMessage } = require("node:_http_common"); const kConnectionsCheckingInterval = Symbol("http.server.connectionsCheckingInterval"); const kTrackedConnections = Symbol("http.server.trackedConnections"); -const getBunServerAllClosedPromise = $newZigFunction("node_http_binding.zig", "getBunServerAllClosedPromise", 1); -const sendHelper = $newZigFunction("node_cluster_binding.zig", "sendHelperChild", 3); +const getBunServerAllClosedPromise = $newNativeFunction("node_http_binding.rs", "getBunServerAllClosedPromise", 1); +const sendHelper = $newNativeFunction("node_cluster_binding.rs", "sendHelperChild", 3); const kServerResponse = Symbol("ServerResponse"); const kChunkedEncoding = Symbol("kChunkedEncoding"); diff --git a/src/js/node/child_process.ts b/src/js/node/child_process.ts index 2044365655d..5dc5240cd79 100644 --- a/src/js/node/child_process.ts +++ b/src/js/node/child_process.ts @@ -634,8 +634,8 @@ function spawnSync(file, args, options) { return result; } -const etimedoutErrorCode = $newZigFunction("node_util_binding.zig", "etimedoutErrorCode", 0); -const enobufsErrorCode = $newZigFunction("node_util_binding.zig", "enobufsErrorCode", 0); +const etimedoutErrorCode = $newNativeFunction("node_util_binding.rs", "etimedoutErrorCode", 0); +const enobufsErrorCode = $newNativeFunction("node_util_binding.rs", "enobufsErrorCode", 0); /** * Spawns a file as a shell synchronously. diff --git a/src/js/node/crypto.ts b/src/js/node/crypto.ts index 8b5edca9cf3..7fcca2193d5 100644 --- a/src/js/node/crypto.ts +++ b/src/js/node/crypto.ts @@ -65,9 +65,9 @@ const { getHashes, scrypt, scryptSync, -} = $zig("node_crypto_binding.zig", "createNodeCryptoBindingZig"); +} = $native("node_crypto_binding.rs", "createNodeCryptoBindingZig"); -const normalizeEncoding = $newZigFunction("node_util_binding.zig", "normalizeEncoding", 1); +const normalizeEncoding = $newNativeFunction("node_util_binding.rs", "normalizeEncoding", 1); const { validateString } = require("internal/validators"); diff --git a/src/js/node/dgram.ts b/src/js/node/dgram.ts index 025ab8770e2..eb0f80d864a 100644 --- a/src/js/node/dgram.ts +++ b/src/js/node/dgram.ts @@ -397,7 +397,7 @@ function _connect(port, address, callback) { state.handle.lookup(address, afterDns); } -const connectFn = $newZigFunction("udp_socket.zig", "UDPSocket.jsConnect", 2); +const connectFn = $newNativeFunction("udp_socket.rs", "UDPSocket.jsConnect", 2); function doConnect(ex, self, ip, address, port, callback) { const state = self[kStateSymbol]; @@ -427,7 +427,7 @@ function doConnect(ex, self, ip, address, port, callback) { process.nextTick(() => self.emit("connect")); } -const disconnectFn = $newZigFunction("udp_socket.zig", "UDPSocket.jsDisconnect", 0); +const disconnectFn = $newNativeFunction("udp_socket.rs", "UDPSocket.jsDisconnect", 0); Socket.prototype.disconnect = function () { const state = this[kStateSymbol]; diff --git a/src/js/node/dns.ts b/src/js/node/dns.ts index dd3f00d6ba2..afc4df33a99 100644 --- a/src/js/node/dns.ts +++ b/src/js/node/dns.ts @@ -65,17 +65,17 @@ function setServers(servers) { return setServersOn(servers, dns); } -const getRuntimeDefaultResultOrderOption = $newZigFunction( - "runtime/dns_jsc/dns.zig", +const getRuntimeDefaultResultOrderOption = $newNativeFunction( + "runtime/dns_jsc/dns.rs", "Resolver.getRuntimeDefaultResultOrderOption", 0, ); function newResolver(options) { - if (!newResolver.zig) { - newResolver.zig = $newZigFunction("runtime/dns_jsc/dns.zig", "Resolver.newResolver", 1); + if (!newResolver.native) { + newResolver.native = $newNativeFunction("runtime/dns_jsc/dns.rs", "Resolver.newResolver", 1); } - return newResolver.zig(options); + return newResolver.native(options); } function defaultResultOrder() { diff --git a/src/js/node/fs.ts b/src/js/node/fs.ts index bcbd183d398..25de1f1c2be 100644 --- a/src/js/node/fs.ts +++ b/src/js/node/fs.ts @@ -664,7 +664,7 @@ const realpathSync: typeof import("node:fs").realpathSync = if (typeof options === "string") encoding = options; else encoding = options?.encoding; if (encoding) { - (assertEncodingForWindows ?? $newZigFunction("runtime/node/types.zig", "jsAssertEncodingValid", 1))( + (assertEncodingForWindows ?? $newNativeFunction("runtime/node/types.rs", "jsAssertEncodingValid", 1))( encoding, ); } @@ -787,7 +787,7 @@ const realpath: typeof import("node:fs").realpath = if (typeof options === "string") encoding = options; else encoding = options?.encoding; if (encoding) { - (assertEncodingForWindows ?? $newZigFunction("runtime/node/types.zig", "jsAssertEncodingValid", 1))( + (assertEncodingForWindows ?? $newNativeFunction("runtime/node/types.rs", "jsAssertEncodingValid", 1))( encoding, ); } diff --git a/src/js/node/http2.ts b/src/js/node/http2.ts index daea2b34d26..92a49fc7f82 100644 --- a/src/js/node/http2.ts +++ b/src/js/node/http2.ts @@ -87,8 +87,8 @@ const ObjectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty; const DatePrototypeToUTCString = Date.prototype.toUTCString; const DatePrototypeGetMilliseconds = Date.prototype.getMilliseconds; -const H2FrameParser = $zig("h2_frame_parser.zig", "H2FrameParserConstructor"); -const _nativeAssertSettings = $newZigFunction("h2_frame_parser.zig", "jsAssertSettings", 1); +const H2FrameParser = $native("h2_frame_parser.rs", "H2FrameParserConstructor"); +const _nativeAssertSettings = $newNativeFunction("h2_frame_parser.rs", "jsAssertSettings", 1); const { upgradeRawSocketToH2 } = require("node:_http2_upgrade"); const kSettingNames = { diff --git a/src/js/node/net.ts b/src/js/node/net.ts index e6299e42623..b95e7d0d99b 100644 --- a/src/js/node/net.ts +++ b/src/js/node/net.ts @@ -50,10 +50,10 @@ const MathMax = Math.max; const { UV_ECANCELED, UV_ETIMEDOUT } = process.binding("uv"); const isWindows = process.platform === "win32"; -const getDefaultAutoSelectFamily = $zig("node_net_binding.zig", "getDefaultAutoSelectFamily"); -const setDefaultAutoSelectFamily = $zig("node_net_binding.zig", "setDefaultAutoSelectFamily"); -const getDefaultAutoSelectFamilyAttemptTimeout = $zig("node_net_binding.zig", "getDefaultAutoSelectFamilyAttemptTimeout"); // prettier-ignore -const setDefaultAutoSelectFamilyAttemptTimeout = $zig("node_net_binding.zig", "setDefaultAutoSelectFamilyAttemptTimeout"); // prettier-ignore +const getDefaultAutoSelectFamily = $native("node_net_binding.rs", "getDefaultAutoSelectFamily"); +const setDefaultAutoSelectFamily = $native("node_net_binding.rs", "setDefaultAutoSelectFamily"); +const getDefaultAutoSelectFamilyAttemptTimeout = $native("node_net_binding.rs", "getDefaultAutoSelectFamilyAttemptTimeout"); // prettier-ignore +const setDefaultAutoSelectFamilyAttemptTimeout = $native("node_net_binding.rs", "setDefaultAutoSelectFamilyAttemptTimeout"); // prettier-ignore /** * `--tls-keylog=`: every TLS socket appends its NSS key-log lines here, @@ -103,15 +103,15 @@ function appendTlsKeylog(line: Buffer) { } } } -const SocketAddress = $zig("node_net_binding.zig", "SocketAddress"); -const BlockList = $zig("node_net_binding.zig", "BlockList"); -const newDetachedSocket = $newZigFunction("node_net_binding.zig", "newDetachedSocket", 1); -const doConnect = $newZigFunction("node_net_binding.zig", "doConnect", 2); - -const addServerName = $newZigFunction("Listener.zig", "jsAddServerName", 3); -const upgradeDuplexToTLS = $newZigFunction("runtime/socket/socket.zig", "jsUpgradeDuplexToTLS", 2); -const isNamedPipeSocket = $newZigFunction("runtime/socket/socket.zig", "jsIsNamedPipeSocket", 1); -const getBufferedAmount = $newZigFunction("runtime/socket/socket.zig", "jsGetBufferedAmount", 1); +const SocketAddress = $native("node_net_binding.rs", "SocketAddress"); +const BlockList = $native("node_net_binding.rs", "BlockList"); +const newDetachedSocket = $newNativeFunction("node_net_binding.rs", "newDetachedSocket", 1); +const doConnect = $newNativeFunction("node_net_binding.rs", "doConnect", 2); + +const addServerName = $newNativeFunction("Listener.rs", "jsAddServerName", 3); +const upgradeDuplexToTLS = $newNativeFunction("socket_body.rs", "jsUpgradeDuplexToTLS", 2); +const isNamedPipeSocket = $newNativeFunction("socket_body.rs", "jsIsNamedPipeSocket", 1); +const getBufferedAmount = $newNativeFunction("socket_body.rs", "jsGetBufferedAmount", 1); const bunTlsSymbol = Symbol.for("::buntls::"); const bunSocketServerOptions = Symbol.for("::bunnetserveroptions::"); diff --git a/src/js/node/os.ts b/src/js/node/os.ts index 9995113e333..4daeb085cca 100644 --- a/src/js/node/os.ts +++ b/src/js/node/os.ts @@ -152,7 +152,7 @@ function bound(binding) { }; } -const out = bound($zig("node_os.zig", "createNodeOsBinding")); +const out = bound($native("node_os.rs", "createNodeOsBinding")); symbolToStringify(out, "arch"); symbolToStringify(out, "availableParallelism"); diff --git a/src/js/node/tls.ts b/src/js/node/tls.ts index a1f7608e08a..3f24276c658 100644 --- a/src/js/node/tls.ts +++ b/src/js/node/tls.ts @@ -3,7 +3,7 @@ const { isArrayBufferView } = require("node:util/types"); const net = require("node:net"); const Duplex = require("internal/streams/duplex"); const EventEmitter = require("node:events"); -const addServerName = $newZigFunction("Listener.zig", "jsAddServerName", 3); +const addServerName = $newNativeFunction("Listener.rs", "jsAddServerName", 3); const { throwNotImplemented } = require("internal/shared"); const { throwOnInvalidTLSArray } = require("internal/tls"); const { @@ -614,7 +614,7 @@ function checkServerIdentity(hostname, cert) { // — Postgres, Valkey, `Bun.connect`, …), so identical options return the same // native handle and the same `SSL_CTX*`. Replaces the SHA-256/WeakRef cache // that used to live in this file. -const NativeSecureContext = $zig("SecureContext.zig", "js.getConstructor"); +const NativeSecureContext = $native("SecureContext.rs", "js.getConstructor"); // Node treats any falsy key/cert/ca as "not provided" (test-tls-options- // boolean-check.js exercises false/0/""). The bindgen SSLConfigFile union only @@ -1613,7 +1613,7 @@ function cacheBundledRootCertificates(): string[] { bundledRootCertificates ||= getBundledRootCertificates() as string[]; return bundledRootCertificates; } -const getUseSystemCA = $newZigFunction("bun.zig", "getUseSystemCA", 0); +const getUseSystemCA = $newNativeFunction("runtime/cli/Arguments.rs", "getUseSystemCA", 0); let defaultCACertificates: string[] | undefined; function cacheDefaultCACertificates() { diff --git a/src/js/node/util.ts b/src/js/node/util.ts index da282f6f359..748c32e5cbd 100644 --- a/src/js/node/util.ts +++ b/src/js/node/util.ts @@ -7,8 +7,8 @@ const { validateString, validateOneOf } = require("internal/validators"); const { MIMEType, MIMEParams } = require("internal/util/mime"); const { deprecate } = require("internal/util/deprecate"); -const internalErrorName = $newZigFunction("node_util_binding.zig", "internalErrorName", 1); -const parseEnv = $newZigFunction("node_util_binding.zig", "parseEnv", 1); +const internalErrorName = $newNativeFunction("node_util_binding.rs", "internalErrorName", 1); +const parseEnv = $newNativeFunction("node_util_binding.rs", "parseEnv", 1); const NumberIsSafeInteger = Number.isSafeInteger; const ObjectKeys = Object.keys; @@ -25,7 +25,7 @@ function isFunction(value) { const deepEquals = Bun.deepEquals; const isDeepStrictEqual = (a, b) => deepEquals(a, b, true); -const parseArgs = $newZigFunction("parse_args.zig", "parseArgs", 1); +const parseArgs = $newNativeFunction("parse_args.rs", "parseArgs", 1); const inspect = utl.inspect; const formatWithOptions = utl.formatWithOptions; diff --git a/src/js/node/zlib.ts b/src/js/node/zlib.ts index 76a9c39cd2d..4663d1cee68 100644 --- a/src/js/node/zlib.ts +++ b/src/js/node/zlib.ts @@ -2,10 +2,10 @@ const BufferModule = require("node:buffer"); -const crc32 = $newZigFunction("node_zlib_binding.zig", "crc32", 1); -const NativeZlib = $zig("node_zlib_binding.zig", "NativeZlib"); -const NativeBrotli = $zig("node_zlib_binding.zig", "NativeBrotli"); -const NativeZstd = $zig("node_zlib_binding.zig", "NativeZstd"); +const crc32 = $newNativeFunction("node_zlib_binding.rs", "crc32", 1); +const NativeZlib = $native("node_zlib_binding.rs", "NativeZlib"); +const NativeBrotli = $native("node_zlib_binding.rs", "NativeBrotli"); +const NativeZstd = $native("node_zlib_binding.rs", "NativeZstd"); const ObjectKeys = Object.keys; const ArrayPrototypePush = Array.prototype.push; diff --git a/src/js/private.d.ts b/src/js/private.d.ts index 2c0d72d5dc9..d3ed01a24c1 100644 --- a/src/js/private.d.ts +++ b/src/js/private.d.ts @@ -203,7 +203,7 @@ interface JSCommonJSModule { * * Binding files are located in `src/jsc/bindings` * - * @see {@link $zig} for native zig bindings. + * @see {@link $native} for native Rust bindings. * @see `src/codegen/replacements.ts` for the script that performs replacement of this funciton. * * @param filename name of the c++ file containing the function. Do not pass a path. @@ -214,31 +214,31 @@ interface JSCommonJSModule { */ declare function $cpp(filename: NativeFilenameCPP, symbol: string): T; /** - * Call a native zig binding function, getting whatever it returns. + * Call a native Rust binding function, getting whatever it returns. * * This is more like a macro; it is replaced with a WebKit intrisic during - * codegen. Passing a template parameter will break codegen. Prefer `$zig(...) + * codegen. Passing a template parameter will break codegen. Prefer `$native(...) * as Foo` instead. * - * Binding files are located in `src/jsc/bindings` - * * @see {@link $cpp} for native c++ bindings. * @see `src/codegen/replacements.ts` for the script that performs replacement of this funciton. * - * @param filename name of the zig file containing the function. Do not pass a path. + * @param filename name of the `.rs` file containing the function: the bare + * basename, or a path relative to `src/` when the basename is + * ambiguous. * @param symbol The name of the binding function. Use `dot.notation` to access * member symbols. * * @returns whatever the binding function returns. */ -declare function $zig(filename: NativeFilenameZig, symbol: string): T; +declare function $native(filename: NativeFilenameRust, symbol: string): T; declare function $newCppFunction any>( filename: NativeFilenameCPP, symbol: string, argCount: number, ): T; -declare function $newZigFunction any>( - filename: NativeFilenameZig, +declare function $newNativeFunction any>( + filename: NativeFilenameRust, symbol: string, argCount: number, ): T; diff --git a/src/jsc/Counters.rs b/src/jsc/Counters.rs index adcbe915694..d97a5015dff 100644 --- a/src/jsc/Counters.rs +++ b/src/jsc/Counters.rs @@ -32,7 +32,7 @@ impl Counters { } } -// Called through the `$zig(...)` js2native codegen, which emits the extern +// Called through the `$native(...)` js2native codegen, which emits the extern // trampoline (`generate-js2native.ts` wraps this in `host_fn::host_fn_static`), // so no `#[bun_jsc::host_fn]` attribute is needed here. pub fn create_counters_object(global: &JSGlobalObject, _frame: &CallFrame) -> JsResult { diff --git a/src/runtime/api.rs b/src/runtime/api.rs index c29dcadc58b..f981a96094e 100644 --- a/src/runtime/api.rs +++ b/src/runtime/api.rs @@ -159,7 +159,7 @@ pub mod bun { pub mod h2_frame_parser { pub use crate::api::h2_frame_parser_body::ErrorCode; pub use crate::api::h2_frame_parser_body::H2FrameParser; - // js2native thunks (`$zig(h2_frame_parser.zig, …)` in generated_js2native.rs). + // js2native thunks (`$native(h2_frame_parser.rs, …)` in generated_js2native.rs). pub use crate::api::h2_frame_parser_body::h2_frame_parser_constructor; pub use crate::api::h2_frame_parser_body::js_assert_settings; pub use crate::api::h2_frame_parser_body::js_get_packed_settings; diff --git a/src/runtime/api/bun/SecureContext.rs b/src/runtime/api/bun/SecureContext.rs index eba8704ffc3..4b31c08ea35 100644 --- a/src/runtime/api/bun/SecureContext.rs +++ b/src/runtime/api/bun/SecureContext.rs @@ -22,7 +22,7 @@ use bun_jsc::{CallFrame, JSGlobalObject, JSValue, JsResult}; use bun_uws as uws; /// Re-export the codegen-emitted module so -/// `$zig(SecureContext.zig, js.getConstructor)` in +/// `$native(SecureContext.rs, js.getConstructor)` in /// `generated_js2native.rs` resolves as `secure_context::js::get_constructor`. pub use crate::generated_classes::js_SecureContext as js; diff --git a/src/runtime/api/bun/h2_frame_parser.rs b/src/runtime/api/bun/h2_frame_parser.rs index 5cbbe97b2ad..aedc1195616 100644 --- a/src/runtime/api/bun/h2_frame_parser.rs +++ b/src/runtime/api/bun/h2_frame_parser.rs @@ -1182,7 +1182,7 @@ impl Handlers { } pub use JSH2FrameParser::get_constructor as H2FrameParserConstructor; -/// snake_case alias for the codegen'd `$zig(h2_frame_parser.zig, H2FrameParserConstructor)` +/// snake_case alias for the codegen'd `$native(h2_frame_parser.rs, H2FrameParserConstructor)` /// thunk in `generated_js2native.rs` (the generator snake-cases the export name). pub use JSH2FrameParser::get_constructor as h2_frame_parser_constructor; diff --git a/src/runtime/cli/Arguments.rs b/src/runtime/cli/Arguments.rs index 8a8ce7b5088..5bdb336e682 100644 --- a/src/runtime/cli/Arguments.rs +++ b/src/runtime/cli/Arguments.rs @@ -697,6 +697,16 @@ pub(crate) static Bun__Node__CAStore: core::sync::atomic::AtomicU8 = pub(crate) static Bun__Node__UseSystemCA: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false); +/// `$newNativeFunction("runtime/cli/Arguments.rs", "getUseSystemCA", 0)` in +/// `node:tls` — see `generated_js2native.rs`. +pub(crate) fn get_use_system_ca( + _global: &bun_jsc::JSGlobalObject, + _frame: &bun_jsc::CallFrame, +) -> bun_jsc::JsResult { + let v = Bun__Node__UseSystemCA.load(core::sync::atomic::Ordering::Relaxed); + Ok(bun_jsc::JSValue::js_boolean(v)) +} + // ─── bunfig loading ────────────────────────────────────────────────────────── // their private helpers moved to `bun_bunfig::arguments` so `bun_install` can // call them without a tier-6 dependency. Re-export here so existing diff --git a/src/runtime/cli/ci_info.rs b/src/runtime/cli/ci_info.rs index 49db88695b8..2478c31d862 100644 --- a/src/runtime/cli/ci_info.rs +++ b/src/runtime/cli/ci_info.rs @@ -1,10 +1,9 @@ // A modified port of ci-info@4.0.0 (https://github.com/watson/ci-info) // Only gets the CI name, `isPR` is not implemented. -// Main implementation is in src/codegen/ci_info.ts use bun_core::env_var; -// The CI table in `cli::ci_info_generated` mirrors the generated module -// produced by src/codegen/ci_info.ts. +// The CI table in `cli::ci_info_generated` is maintained by hand from +// ci-info's vendors.json (see mod.rs). use super::ci_info_generated as generated; static DETECT_CI_ONCE: bun_core::Once> = diff --git a/src/runtime/cli/mod.rs b/src/runtime/cli/mod.rs index b04b1d19e11..ec8a847d459 100644 --- a/src/runtime/cli/mod.rs +++ b/src/runtime/cli/mod.rs @@ -13,9 +13,9 @@ use bun_core::{pretty, pretty_error, pretty_errorln}; // ─── compiling submodules ──────────────────────────────────────────────────── #[path = "ci_info.rs"] pub mod ci_info; -/// CI-provider detection table, copied from watson/ci-info@4.0.0; since the -/// Rust build has no codegen hook for this yet, the table is maintained by -/// hand. Keep in sync with `src/codegen/ci_info.ts`. +/// CI-provider detection table, copied from watson/ci-info@4.0.0. The table +/// is maintained by hand; keep in sync with upstream vendors.json +/// (https://github.com/watson/ci-info/blob/master/vendors.json). pub(crate) mod ci_info_generated { use bun_core::{getenv_z, zstr}; diff --git a/src/runtime/dispatch_js2native.rs b/src/runtime/dispatch_js2native.rs index a56fa37c95a..1ef9efa25d7 100644 --- a/src/runtime/dispatch_js2native.rs +++ b/src/runtime/dispatch_js2native.rs @@ -1,27 +1,22 @@ //! `crate::dispatch::js2native` — flat re-export landing pad for the -//! `JS2Zig__*` thunks emitted into `generated_js2native.rs`. +//! `JS2Native__*` thunks emitted into `generated_js2native.rs`. //! -//! `src/codegen/generate-js2native.ts::rustTarget()` routes every `$zig(...)` -//! call site whose source file lives **outside** `src/runtime/` through -//! `crate::dispatch::js2native::` instead of the file's own crate -//! path. `bun_runtime` is the highest-tier crate (already depends on every -//! `*_jsc` bridge crate plus `bun_jsc` itself), so the cross-crate fan-out -//! lands here without introducing a dep cycle. Each entry below is a `pub use` -//! of the real hand-ported function — there are no local bodies and no -//! fallback panics; a missing target stays a compile error in the owning +//! `src/codegen/generate-js2native.ts::rustTarget()` routes every +//! `$native(...)` call site whose source file lives **outside** `src/runtime/` +//! through `crate::dispatch::js2native::` instead of the file's own +//! crate path. `bun_runtime` is the highest-tier crate (already depends on +//! every `*_jsc` bridge crate plus `bun_jsc` itself), so the cross-crate +//! fan-out lands here without introducing a dep cycle. Each entry below is a +//! `pub use` of the real hand-ported function — there are no local bodies and +//! no fallback panics; a missing target stays a compile error in the owning //! crate. //! //! Naming: the mangled identifier is `snake(.join("_")) ++ "_" //! ++ snake(symbol).replace("::", "_")` (see `generate-js2native.ts`). -use bun_jsc::{CallFrame, JSGlobalObject, JSValue, JsResult}; - pub use bun_sql_jsc::mysql::create_binding as sql_jsc_mysql_create_binding; pub use bun_sql_jsc::postgres::create_binding as sql_jsc_postgres_create_binding; -// The real body already lives in this crate. -pub use crate::api::crash_handler_jsc::js_bindings::generate as crash_handler_crash_handler_js_bindings_generate; - pub use bun_install_jsc::dependency_jsc::dependency_from_js as install_dependency_from_js; pub use bun_install_jsc::dependency_jsc::tag_infer_from_js as install_dependency_version_tag_infer_from_js; pub use bun_install_jsc::hosted_git_info_jsc::js_from_url as install_hosted_git_info_testing_ap_is_js_from_url; @@ -33,8 +28,8 @@ pub use bun_install_jsc::npm_jsc::package_manifest_bindings_generate as install_ // The `*_jsc` bodies live in `bun_install_jsc::ini_jsc` // (ini's only JSC consumer is `bun install`'s npmrc loader). -pub use bun_install_jsc::ini_jsc::ini_testing_load_npmrc_from_js as ini_ini_ini_testing_ap_is_load_npmrc_from_js; -pub use bun_install_jsc::ini_jsc::ini_testing_parse as ini_ini_ini_testing_ap_is_parse; +pub use bun_install_jsc::ini_jsc::ini_testing_load_npmrc_from_js as install_jsc_ini_jsc_ini_testing_ap_is_load_npmrc_from_js; +pub use bun_install_jsc::ini_jsc::ini_testing_parse as install_jsc_ini_jsc_ini_testing_ap_is_parse; pub use bun_jsc::bindgen_test::get_bindgen_test_functions as jsc_bindgen_test_get_bindgen_test_functions; pub use bun_jsc::counters::create_counters_object as jsc_counters_create_counters_object; @@ -44,39 +39,26 @@ pub use bun_jsc::virtual_machine_exports::Bun__setSyntheticAllocationLimitForTes // because it dereferences `Subprocess`, a runtime type. pub use crate::ipc_host::emit_handle_ipc_message as jsc_ipc_emit_handle_ipc_message; -pub use bun_jsc::bun_string_jsc::js_escape_reg_exp as string_escape_reg_exp_js_escape_reg_exp; -pub use bun_jsc::bun_string_jsc::js_escape_reg_exp_for_package_name_matching as string_escape_reg_exp_js_escape_reg_exp_for_package_name_matching; +pub use bun_jsc::bun_string_jsc::js_escape_reg_exp as bun_core_string_escape_reg_exp_js_escape_reg_exp; +pub use bun_jsc::bun_string_jsc::js_escape_reg_exp_for_package_name_matching as bun_core_string_escape_reg_exp_js_escape_reg_exp_for_package_name_matching; pub use bun_jsc::bun_string_jsc::unicode_testing_apis::to_utf16_alloc_sentinel as bun_core_string_immutable_unicode_testing_ap_is_to_utf16_alloc_sentinel; -pub use bun_patch_jsc::testing::patch_apply as patch_patch_testing_ap_is_apply; -pub use bun_patch_jsc::testing::patch_make_diff as patch_patch_testing_ap_is_make_diff; -pub use bun_patch_jsc::testing::patch_parse as patch_patch_testing_ap_is_parse; +pub use bun_patch_jsc::testing::patch_apply as patch_jsc_testing_testing_ap_is_apply; +pub use bun_patch_jsc::testing::patch_make_diff as patch_jsc_testing_testing_ap_is_make_diff; +pub use bun_patch_jsc::testing::patch_parse as patch_jsc_testing_testing_ap_is_parse; pub use bun_sourcemap_jsc::internal_jsc::testing_find as sourcemap_internal_source_map_testing_ap_is_find; pub use bun_sourcemap_jsc::internal_jsc::testing_from_vlq as sourcemap_internal_source_map_testing_ap_is_from_vlq; pub use bun_sourcemap_jsc::internal_jsc::testing_to_vlq as sourcemap_internal_source_map_testing_ap_is_to_vlq; -pub use bun_sys_jsc::error_jsc::TestingAPIs::sigaction_layout as sys_sys_testing_ap_is_sigaction_layout; +pub use bun_sys_jsc::error_jsc::TestingAPIs::sigaction_layout as sys_error_testing_ap_is_sigaction_layout; pub use bun_sys_jsc::error_jsc::TestingAPIs::sys_error_name_from_libuv as sys_error_testing_ap_is_sys_error_name_from_libuv; -pub use bun_sys_jsc::error_jsc::TestingAPIs::translate_nt_status_to_e as sys_sys_testing_ap_is_translate_nt_status_to_e; -pub use bun_sys_jsc::error_jsc::TestingAPIs::translate_uv_error_to_e as sys_sys_testing_ap_is_translate_uv_error_to_e; +pub use bun_sys_jsc::error_jsc::TestingAPIs::translate_nt_status_to_e as sys_error_testing_ap_is_translate_nt_status_to_e; +pub use bun_sys_jsc::error_jsc::TestingAPIs::translate_uv_error_to_e as sys_error_testing_ap_is_translate_uv_error_to_e; pub use bun_http_jsc::headers_jsc::h2_live_counts as http_h2_client_testing_ap_is_live_counts; pub use bun_http_jsc::headers_jsc::h3_quic_live_counts as http_h3_client_testing_ap_is_quic_live_counts; -/// Lives here (not in `src/bun.rs`) -/// because the flag it reads — `cli::Arguments::Bun__Node__UseSystemCA` — is -/// owned by `bun_runtime`; placing the body in a lower crate would invert the -/// dependency edge. -pub(crate) fn bun_get_use_system_ca( - _global: &JSGlobalObject, - _frame: &CallFrame, -) -> JsResult { - let v = - crate::cli::Arguments::Bun__Node__UseSystemCA.load(core::sync::atomic::Ordering::Relaxed); - Ok(JSValue::js_boolean(v)) -} - mod css { pub use bun_css_jsc::css_internals::{ _test, attr_test, minify_error_test_with_options, minify_test, minify_test_with_options, diff --git a/src/runtime/dns_jsc/dns.rs b/src/runtime/dns_jsc/dns.rs index 145e2a5aaa7..c85d8c12e18 100644 --- a/src/runtime/dns_jsc/dns.rs +++ b/src/runtime/dns_jsc/dns.rs @@ -6077,12 +6077,12 @@ export_host_fn!(Resolver::global_reverse, "Bun__DNS__reverse"); export_host_fn!(Resolver::global_lookup_service, "Bun__DNS__lookupService"); export_host_fn!(internal::prefetch_from_js, "Bun__DNS__prefetch"); export_host_fn!(internal::get_dns_cache_stats, "Bun__DNS__getCacheStats"); -// JS2Native ($newZigFunction) entry points — see GeneratedJS2Native.h +// JS2Native ($newNativeFunction) entry points — see GeneratedJS2Native.h export_host_fn!( Resolver::new_resolver, - "JS2Zig___src_runtime_dns_jsc_dns_zig__Resolver_newResolver" + "JS2Native___src_runtime_dns_jsc_dns_Resolver_newResolver" ); export_host_fn!( Resolver::get_runtime_default_result_order_option, - "JS2Zig___src_runtime_dns_jsc_dns_zig__Resolver_getRuntimeDefaultResultOrderOption" + "JS2Native___src_runtime_dns_jsc_dns_Resolver_getRuntimeDefaultResultOrderOption" ); diff --git a/src/runtime/ffi/ffi_body.rs b/src/runtime/ffi/ffi_body.rs index d3645a35ea7..2057db0a492 100644 --- a/src/runtime/ffi/ffi_body.rs +++ b/src/runtime/ffi/ffi_body.rs @@ -2760,7 +2760,7 @@ static WORKAROUND: MyFunctionSStructWorkAround = MyFunctionSStructWorkAround { // ─── exports ──────────────────────────────────────────────────────────────── /// `Bun__FFI__cc` — module-level re-export of `FFI::bun_ffi_cc`, so the -/// `js2native` codegen can resolve it as `crate::ffi::ffi::bun__ffi__cc`. +/// `js2native` codegen can resolve it as `crate::ffi::ffi_body::bun__ffi__cc`. #[allow(non_snake_case)] #[inline] pub fn bun__ffi__cc(global: &JSGlobalObject, callframe: &CallFrame) -> JsResult { diff --git a/src/runtime/ffi/mod.rs b/src/runtime/ffi/mod.rs index aef170b7c5b..40f81fa0e81 100644 --- a/src/runtime/ffi/mod.rs +++ b/src/runtime/ffi/mod.rs @@ -19,16 +19,7 @@ pub use host_fns::{generate_symbol_for_function, generate_symbols}; // ─── implementation modules ────────────────────────────────────────────────── #[path = "ffi_body.rs"] -mod ffi_body; - -/// `js2native` codegen resolves `$zig(ffi.zig, Bun__FFI__cc)` to -/// `crate::ffi::ffi::bun__ffi__cc`; the module name maps the `.zig` basename. -/// `FFI::bun_ffi_cc` lives in `ffi_body` — re-export it under -/// the codegen-expected path so the dispatch table links without forcing the -/// generator to special-case `ffi/ffi.zig`. -pub mod ffi { - pub use super::ffi_body::bun__ffi__cc; -} +pub mod ffi_body; #[path = "FFIObject.rs"] pub mod ffi_object_draft; diff --git a/src/runtime/generated_js2native.rs b/src/runtime/generated_js2native.rs index 995b1aa2c37..5b4df7aa9d8 100644 --- a/src/runtime/generated_js2native.rs +++ b/src/runtime/generated_js2native.rs @@ -3,13 +3,12 @@ //! `src/codegen/generate-js2native.ts::getJS2NativeRust()` (driven by //! `bundle-modules.ts`) writes `${BUN_CODEGEN_DIR}/generated_js2native.rs`; //! this module `include!`s it so the `#[unsafe(no_mangle)] extern "C"` -//! `JS2Zig__*` symbols land in `bun_runtime` and satisfy the externs declared -//! by `GeneratedJS2Native.h` (the JS-module → native dispatch table). +//! `JS2Native__*` symbols land in `bun_runtime` and satisfy the externs +//! declared by `GeneratedJS2Native.h` (the JS-module → native dispatch table). //! -//! Mirrors `generated_classes.rs` exactly: thunks dispatch through a -//! `Js2NativeImpl` trait whose default method bodies panic with a "not yet -//! ported" message; porting a `$zig()` call site means overriding the -//! matching method on `Js2Native`. +//! Each thunk calls the Rust function named by its `$native()` call site +//! directly (resolved from the `.rs` path + symbol); a missing function is a +//! compile error in `cargo check -p bun_runtime`. #![allow( non_snake_case, non_camel_case_types, diff --git a/src/runtime/linear_fifo_testing.rs b/src/runtime/linear_fifo_testing.rs index 86c4750ef93..62b919bedfa 100644 --- a/src/runtime/linear_fifo_testing.rs +++ b/src/runtime/linear_fifo_testing.rs @@ -11,8 +11,8 @@ //! //! Lives in `bun_runtime` (not `bun_collections`) because it needs the JSC //! types; `bun_runtime` already depends on both `bun_collections` and -//! `bun_jsc`. Registered via `$newZigFunction("collections/linear_fifo.zig", -//! "TestingAPIs.orderedRemoveProbe", 1)` — the `.zig` path is only the codegen +//! `bun_jsc`. Registered via `$newNativeFunction("collections/linear_fifo.rs", +//! "TestingAPIs.orderedRemoveProbe", 1)` — the `.rs` path is only the codegen //! key; the implementation is this Rust function (see `dispatch_js2native.rs`). use bun_collections::linear_fifo::{LinearFifo, StaticBuffer}; diff --git a/src/runtime/shell/mod.rs b/src/runtime/shell/mod.rs index 41adb7cc422..7276141950f 100644 --- a/src/runtime/shell/mod.rs +++ b/src/runtime/shell/mod.rs @@ -17,8 +17,6 @@ #[path = "shell_body.rs"] pub mod shell_body; -// Codegen (`generated_js2native.rs`) addresses this as `crate::shell::shell::*`. -pub use shell_body as shell; // ─── submodules ────────────────────────────────────────────────────────────── #[path = "EnvMap.rs"] diff --git a/src/runtime/socket/mod.rs b/src/runtime/socket/mod.rs index 431a6f072d6..c2c68ab19b2 100644 --- a/src/runtime/socket/mod.rs +++ b/src/runtime/socket/mod.rs @@ -7,7 +7,7 @@ // ─── submodules ────────────────────────────────────────────────────────────── #[path = "socket_body.rs"] -mod socket_body; +pub mod socket_body; #[path = "SocketAddress.rs"] pub mod socket_address; @@ -89,8 +89,9 @@ pub use windows_named_pipe_context::WindowsNamedPipeContext; /// `generated_js2native.rs` (`crate::socket::udp_socket::udp_socket::js_connect`) /// resolve against the real struct, not an opaque placeholder. pub mod udp_socket { - /// `generated_js2native.rs` lowers `$zig(udp_socket.zig, UDPSocket.jsConnect)` - /// to `crate::socket::udp_socket::udp_socket::js_connect`. The inner + /// `generated_js2native.rs` lowers `$newNativeFunction("udp_socket.rs", + /// "UDPSocket.jsConnect", ..)` to + /// `crate::socket::udp_socket::udp_socket::js_connect`. The inner /// `udp_socket` segment is the snake-cased struct name; aliasing the type /// lets the associated-fn path resolve directly. pub use super::udp_socket_draft::UDPSocket as udp_socket; @@ -98,20 +99,6 @@ pub mod udp_socket { } pub use udp_socket::UDPSocket; -/// Codegen path alias. -/// -/// `generated_js2native.rs` lowers `$zig(socket.zig, fnName)` to -/// `crate::socket::socket::fn_name(...)` (one path segment per directory plus -/// the file stem). The Rust port placed the bodies in `socket_body.rs` to keep -/// `mod.rs` as the wiring layer, so re-export the js2native entry points under -/// the name the generator expects rather than special-casing the generator. -pub mod socket { - pub use super::socket_body::{ - js_create_socket_pair, js_get_buffered_amount, js_is_named_pipe_socket, - js_set_socket_options, js_upgrade_duplex_to_tls, - }; -} - // ─── RawSocketEvents glue ──────────────────────────────────────────────────── // `uws_handlers::RawSocketEvents` is the raw-pointer dispatch trait the // vtable layer requires of `api::NewSocket` (routed via `RawPtrHandler`, diff --git a/src/runtime/timer/mod.rs b/src/runtime/timer/mod.rs index fde3b11531c..fdfd97a7a3e 100644 --- a/src/runtime/timer/mod.rs +++ b/src/runtime/timer/mod.rs @@ -25,7 +25,7 @@ use crate::jsc::JSValue; // ─── JS-facing surface (`impl All { set_timeout / clear_* / … }`) ──────────── // Named `timer` so codegen (`generated_js2native.rs`) resolves // `crate::timer::timer::internal_bindings::timer_clock_ms` per the -// `$zig(Timer.zig, …)` → `crate::::` path-mapping. +// `$native(Timer.rs, …)` → `crate::::` path-mapping. #[path = "Timer.rs"] pub mod timer; diff --git a/test/internal/js2native-codegen.test.ts b/test/internal/js2native-codegen.test.ts new file mode 100644 index 00000000000..5bb55970068 --- /dev/null +++ b/test/internal/js2native-codegen.test.ts @@ -0,0 +1,80 @@ +/** + * Codegen contract tests for the $native()/$newNativeFunction() JS-to-native + * binding macros (src/codegen/generate-js2native.ts + replacements.ts). + * + * These exercise the build-time resolution logic only: a key names the + * implementing `.rs` file, is validated against the source tree, and produces + * the JS2Native__* symbol shared by the generated C++ extern and the Rust + * thunk. The `.zig` porting references are not consulted. + * https://github.com/oven-sh/bun/issues/32210 + */ +import { expect, test } from "bun:test"; + +import { sliceSourceCode } from "../../src/codegen/builtin-parser.ts"; +import { + getJS2NativeCPP, + getJS2NativeDTS, + getJS2NativeRust, + registerNativeCall, +} from "../../src/codegen/generate-js2native.ts"; + +test("$native() lowers to a lazy intrinsic and resolves its .rs key", () => { + const out = sliceSourceCode(`{ const binding = $native("mysql.rs", "createBinding"); }`, true); + expect(out.result).toContain("__intrinsic__lazy("); +}); + +test("$newNativeFunction() lowers to a lazy intrinsic", () => { + const out = sliceSourceCode(`{ const fn = $newNativeFunction("node_util_binding.rs", "parseEnv", 1); }`, true); + expect(out.result).toContain("__intrinsic__lazy("); +}); + +test("keys must name a real .rs file", () => { + expect(() => registerNativeCall("native", "not_a_real_file.rs", "foo", null)).toThrow( + /Could not find file not_a_real_file\.rs/, + ); +}); + +test(".zig keys are rejected", () => { + expect(() => registerNativeCall("native", "mysql.zig", "createBinding", null)).toThrow(/\.rs extension/); +}); + +test("ambiguous basenames are rejected instead of first-match resolved", () => { + // lib.rs exists in nearly every crate under src/. + expect(() => registerNativeCall("native", "lib.rs", "foo", null)).toThrow(/Ambiguous filename "lib\.rs"/); +}); + +test("C++ externs and Rust thunks share JS2Native__ symbols derived from the .rs path", () => { + registerNativeCall("native", "mysql.rs", "createBinding", null); + registerNativeCall("native", "node_util_binding.rs", "parseEnv", 1); + const cpp = getJS2NativeCPP(); + const rust = getJS2NativeRust(); + // Direct call: src/sql_jsc/mysql.rs + createBinding. + expect(cpp).toContain("JS2Native___src_sql_jsc_mysql_createBinding_workaround"); + expect(rust).toContain("JS2Native___src_sql_jsc_mysql_createBinding_workaround"); + // Wrapped host function: src/runtime/node/node_util_binding.rs + parseEnv. + expect(cpp).toContain("JS2Native___src_runtime_node_node_util_binding_parseEnv"); + expect(rust).toContain("JS2Native___src_runtime_node_node_util_binding_parseEnv"); + expect(cpp).not.toContain("JS2Zig"); + expect(rust).not.toContain("JS2Zig"); +}); + +test("Rust thunks call the crate path derived from the .rs file", () => { + registerNativeCall("native", "mysql.rs", "createBinding", null); + registerNativeCall("native", "node_util_binding.rs", "parseEnv", 1); + const rust = getJS2NativeRust(); + // src/runtime/node/node_util_binding.rs -> bun_runtime's own module tree. + expect(rust).toContain("crate::node::node_util_binding::parse_env"); + // src/sql_jsc/mysql.rs lives outside bun_runtime -> flat dispatch re-export. + expect(rust).toContain("crate::dispatch::js2native::sql_jsc_mysql_create_binding"); +}); + +test("generated d.ts types the keys as .rs filenames", () => { + const dts = getJS2NativeDTS(); + expect(dts).toContain("declare type NativeFilenameRust = "); + expect(dts).toContain('"mysql.rs"'); + expect(dts).toContain('"sql_jsc/mysql.rs"'); + // Ambiguous basenames are rejected by the resolver, so the d.ts must not + // offer the bare form as a valid key (the src-relative forms are still in). + expect(dts).not.toContain('"lib.rs"'); + expect(dts).not.toContain("NativeFilenameZig"); +});