feat(config): enum-as-shorthand backend resolution (#386 Phase 5) - #412
Conversation
Completes the Phase-5 resolver seam: a built-in `.backend` enum tag is now a *shorthand* for a provider, not a hardwired bundled slot. Adds: - `config.builtinProvider(Backend) ?PluginDep` — the extraction table. Every built-in maps to `null` (bundled) today, so behavior is unchanged. - `config.effectiveBackendPackage()` — `backend_package orelse builtinProvider(backend)`: the ONE place that composes an explicit external package with the enum-shorthand. `backendName()`, `isExternal()`, and `backend_registry.resolveBackendPackage` all route through it, so they agree on whether a backend is external and which package it is. Effect today: none — `builtinProvider` returns null for all six built-ins, so `.backend = .<tag>` resolves to the bundled `backends/<tag>` slot exactly as before (golden suites byte-identical). The point is what it UNBLOCKS: extracting a backend out-of-tree (Phase 6c) becomes a one-line entry here, after which `.backend = .bgfx` transparently fetches the `labelle-bgfx` provider package (isExternal ⇒ true; manifest path + 6b contract guard + self-contained staging all activate) with zero change to existing project configs. Deferred to the actual extraction PR: the bgfx repo move itself + handling the shared `../sdl_gamepad` / `../android_gamepad` sub-packages (bgfx/raylib/sokol share them in-tree — an external bgfx can't reference `../`), which is the open decision gating Phase 6c. Tests: every built-in tag is still bundled (behavior-preservation guard that flips visibly when a tag is extracted); an explicit backend_package still wins over the enum at the seam.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces the "enum-as-shorthand" seam (Phase 5 of epic #386) to allow built-in backend enum tags to eventually resolve to external provider packages. It introduces builtinProvider and effectiveBackendPackage methods on ProjectConfig and updates backendName, isExternal, and resolveBackendPackage to use them. A critical issue was identified in src/config.zig where calling builtinProvider directly without qualifying it with the struct name ProjectConfig will cause a compile-time error in Zig.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| pub fn effectiveBackendPackage(self: ProjectConfig) ?PluginDep { | ||
| return self.backend_package orelse builtinProvider(self.backend); | ||
| } |
There was a problem hiding this comment.
In Zig, struct-level namespace declarations (associated functions/static methods) are not automatically in scope as bare identifiers within the struct's methods. Calling builtinProvider(self.backend) directly will result in a compile-time error (use of undeclared identifier 'builtinProvider').\n\nTo fix this, qualify the call with the struct name: ProjectConfig.builtinProvider(self.backend).
pub fn effectiveBackendPackage(self: ProjectConfig) ?PluginDep {\n return self.backend_package orelse ProjectConfig.builtinProvider(self.backend);\n }
There was a problem hiding this comment.
This is a false positive. In Zig, declarations within a container (struct) are in scope as bare identifiers from that container's other declarations — builtinProvider is a decl of ProjectConfig, so a sibling method (effectiveBackendPackage) calls it by bare name without a ProjectConfig. qualifier. Evidence: this exact code compiles — zig build + zig build test are green locally and all five CI build/test jobs (build-and-test ubuntu+macos, bgfx macOS + Android, Examples integration) passed on this commit. A genuine use of undeclared identifier would have failed every one. Leaving as-is.
… (#418) Pluggable-backends Phases 5+6 (epic #386): the assembler can now FETCH, verify, and build out-of-tree backend packages, and bgfx is extracted to its own repo. - #409 6a: remote .backend_package cache-fetch (fetched like a plugin) - #410 6b: contract-verify an external backend (assertBackend/Window/Input) - #411: conform raylib + null windows to the canonical window contract - #412 Phase 5: enum-as-shorthand resolution (a built-in tag can resolve to a package) - #413 6c: bgfx extracted -> github.com/labelle-toolkit/labelle-bgfx; opt-in CI-verified - #414: select the GUI bridge by backend name, not the enum (external backends) - #415: labelle-bgfx v0.2.0 — gamepad sources extracted to their own packages - #416/#417: the two flip-blockers (callback-external guard; android enum-fallthrough) Opt-in today via .backend_package; built-in .backend = .bgfx still ships bundled (the default-flip is a follow-up gated on this release). Built-in backends are byte-identical. External bgfx validated on-device (Galaxy Tab A7): builds, runs crash-free, behaves identically to bundled.
Phase 5 — enum-as-shorthand backend resolution
Completes the Phase-5 resolver seam so a built-in
.backendenum tag is a shorthand for a provider, not a hardwired bundled slot. This is the backward-compatibility hinge that lets a backend be extracted out-of-tree (Phase 6c) without breaking existing.backend = .bgfxprojects (Flying Platform).What it adds
config.builtinProvider(Backend) ?PluginDep— the extraction table. Every built-in maps tonull(bundled) today.config.effectiveBackendPackage()=backend_package orelse builtinProvider(backend)— the single place that composes an explicit external package with the enum-shorthand.backendName(),isExternal(), andbackend_registry.resolveBackendPackageall route through it, so they can't disagree about whether a backend is external or which package it is.Effect today: none (by design)
builtinProviderreturnsnullfor all six built-ins, so.backend = .<tag>resolves to the bundledbackends/<tag>slot exactly as before — generated output is byte-identical (golden suites green).What it unblocks
Extracting a backend (Phase 6c) becomes a one-line entry here:
After that,
.backend = .bgfxtransparently fetches the provider package —isExternal()⇒ true, so the manifest path + the #386 Phase-6b contract guard + self-contained staging all activate — with zero change to existing project configs.Deferred to the actual extraction PR
The bgfx repo move itself, and handling the shared
../sdl_gamepad/../android_gamepadsub-packages (bgfx/raylib/sokol share them in-tree; an external bgfx can't reference../). That sub-package decision is the open item gating Phase 6c — intentionally not in this PR.Tests
!isExternal(), no effective package, named by enum tag) — a behavior-preservation guard that flips visibly the moment a tag is extracted.backend_packagestill wins over the enum at the seam.zig build testgreen.Summary by CodeRabbit