Skip to content

fix(gui): select the GUI bridge by backend name, not the enum (#386) - #414

Merged
apotema merged 2 commits into
mainfrom
fix/386-external-backend-gui-bridge
Jun 29, 2026
Merged

apotema merged 2 commits into
mainfrom
fix/386-external-backend-gui-bridge

Conversation

@apotema

@apotema apotema commented Jun 29, 2026 •

Copy link
Copy Markdown
Contributor

External backends pulled the wrong GUI bridge

Found by validating Flying Platform (bgfx + imgui) against the extracted out-of-tree labelle-bgfx package — the first real-game test of the extraction.

getBridgeForBackend selected the imgui bridge variant from the closed config.Backend enum. An external .backend_package leaves cfg.backend at its .raylib enum default (the tag is meaningless for a named package), so an out-of-tree bgfx game resolved the raylib (rlImGui) bridge — dragging in an old, Zig-0.16-incompatible raylib-zig (std.mem.trimLeft / std.process.getEnvVarOwned removed) and failing the build. Same class of bug as the preview-readback gate fixed in Phase 6b.

Fix

Select by cfg.backendName() over the same named Bridges fields:

  • external "bgfx" → bridges.bgfx ✓
  • built-ins unchanged (their name is the enum tag) → byte-identical
  • a name with no declared bridge (null backend, or a third-party backend the GUI plugin doesn't bridge) → null → the caller's existing "no bridge for backend X" diagnostic

Verification

  • Isolated: same assembler, only the config differs — external backend_package staged rlimgui_bridge (raylib-zig 5.6.0-dev), bundled .backend = .bgfx staged bgfx_imgui_bridge. After the fix, external bgfx stages bgfx_imgui_bridge (0 raylib refs).
  • End-to-end: Flying Platform (bgfx + imgui + zig_ecs + many plugins) now builds fully against labelle-bgfx — BUILD_RC=0, 37 MB binary linking the external package.
  • Regression test added (getBridgeForBackendName); zig build test green.

Summary by CodeRabbit

  • Bug Fixes
    • Improved backend selection so the GUI now resolves the correct bridge using the backend’s name, including external backends.
    • Built-in backends continue to match as expected, and unknown backend names now safely return no bridge instead of selecting the wrong one.
  • Tests
    • Added coverage for backend-name-based bridge selection and fallback behavior.

An external `.backend_package` leaves `cfg.backend` at its `.raylib` enum
default (the tag is meaningless for a named package). `getBridgeForBackend`
keyed off that enum, so an out-of-tree bgfx game pulled the RAYLIB imgui bridge
(rlImGui) — dragging in an old, Zig-0.16-incompatible raylib-zig and failing the
build. Same class of bug as the preview-readback gate (#386 Phase 6b).

Select the bridge by `cfg.backendName()` over the same named `Bridges` fields:
an external "bgfx" resolves to `bridges.bgfx`, and built-ins are byte-identical
(their name IS the enum tag). A name with no declared bridge (null backend, or a
third-party backend the GUI plugin doesn't bridge) returns null → the caller's
existing "no bridge for backend X" diagnostic.

Surfaced by validating Flying Platform (bgfx + imgui + zig_ecs + plugins)
against the extracted out-of-tree labelle-bgfx package: before this, FP staged
the rlImGui bridge and failed to compile; after, it stages bgfx_imgui_bridge and
the full desktop game builds (BUILD_RC=0, 37 MB binary linking labelle-bgfx).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the enum-based backend bridge selection with a name-based selection (getBridgeForBackendName) to correctly resolve external backends, and adds a corresponding regression test. The reviewer suggests improving getBridgeForBackendName by using Zig's compile-time reflection (std.meta.fields) to dynamically iterate over the fields of the Bridges struct instead of hardcoding string comparisons.

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.

Comment thread src/gui_resolve.zig
Comment on lines +232 to 239
fn getBridgeForBackendName(bridges: Bridges, name: []const u8) ?BridgeDef {
if (std.mem.eql(u8, name, "raylib")) return bridges.raylib;
if (std.mem.eql(u8, name, "sokol")) return bridges.sokol;
if (std.mem.eql(u8, name, "sdl")) return bridges.sdl;
if (std.mem.eql(u8, name, "bgfx")) return bridges.bgfx;
if (std.mem.eql(u8, name, "wgpu")) return bridges.wgpu;
return null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of manually hardcoding string comparisons for each backend, we can use Zig's compile-time reflection (std.meta.fields) to iterate over the fields of the Bridges struct. This ensures that if any new backends are added to the Bridges struct in the future, this function will automatically support them without requiring manual updates.

fn getBridgeForBackendName(bridges: Bridges, name: []const u8) ?BridgeDef {
    inline for (std.meta.fields(Bridges)) |field| {
        if (std.mem.eql(u8, name, field.name)) {
            return @field(bridges, field.name);
        }
    }
    return null;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — switched to an inline for over @typeInfo(Bridges).@"struct".fields matching field name == backend name. Same behavior, and a new bridge field now needs no change here. Thanks.

…ini)

Replace the hardcoded per-backend string comparisons with an inline-for over the
Bridges struct fields — same behavior, but adding a bridge field no longer needs
a matching line here. (gemini review on #414.)
@coderabbitai

coderabbitai Bot commented Jun 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 60da46ef-ae9c-4c65-a07a-5394d982daad

📥 Commits

Reviewing files that changed from the base of the PR and between 509c8d1 and 6d427d1.

📒 Files selected for processing (1)
  • src/gui_resolve.zig

📝 Walkthrough

Walkthrough

In src/gui_resolve.zig, getBridgeForBackend (which switched on the config.Backend enum) is replaced by getBridgeForBackendName, which uses compile-time reflection over Bridges struct fields to match a backend name string. The call site in resolveGuiPlugin is updated to pass cfg.backendName(), and new tests cover external, built-in, and unknown backend cases.

Bridge name-based selection

Layer / File(s) Summary
getBridgeForBackendName implementation and call site
src/gui_resolve.zig
Removes getBridgeForBackend (enum switch) and adds getBridgeForBackendName that iterates Bridges struct fields at compile time to match the provided name string, returning null on no match. Updates resolveGuiPlugin to call getBridgeForBackendName(bridges, cfg.backendName()).
Tests for name-based selection
src/gui_resolve.zig
Adds a test suite validating bridge selection for external backends by name, built-in backends, and unknown names returning null.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐇 A name beats an enum, I say with delight,
Reflect on the fields — the match comes out right!
External or built-in, the bridge finds its way,
Unknown names return null, and that's okay.
Hop hop, refactor, a cleaner today! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: GUI bridge selection now uses backend name instead of the enum.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/386-external-backend-gui-bridge

Comment @coderabbitai help to get the list of available commands.

@apotema
apotema merged commit d6be2ad into main Jun 29, 2026
6 checks passed
@apotema
apotema deleted the fix/386-external-backend-gui-bridge branch June 29, 2026 20:57
apotema added a commit that referenced this pull request Jun 30, 2026
… (#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant