Back to Raylib Rs

Safe abstractions for GuiGetIcons / GuiLoadIcons + PR #296 — complete

docs/superpowers/notes/ws-gui-icons-safe-abstractions-complete.md

6.0.08.0 KB
Original Source

Safe abstractions for GuiGetIcons / GuiLoadIcons + PR #296 — complete

Status: DONE on branch 6.0-rc (pushed to fork). Seventh and final pre-WS9 workstream in the owner-locked queue. Spec: docs/superpowers/specs/2026-05-30-gui-icons-safe-abstractions-design.md. Plan: docs/superpowers/plans/2026-05-30-gui-icons-safe-abstractions.md.

What shipped

StatisticBeforeAfter
unsafe fn in RaylibGuiIcons2 (_raw accessors)0
Safe icon-buffer accessors02 (gui_get_icons, gui_get_icons_mut)
Safe .rgi load methods04 (file + memory × no-names + with-names)
Safe .rgs from-memory load01 (gui_load_style_from_memory)
New error enums02 (LoadIconsError, LoadStyleFromMemoryError)
Tier-1 unit tests2 pure-unit (check_i32_len_boundary, validate_rgi_header_accepts_well_formed) + 2 LoadStyleFromMemoryError boundary
Tier-2 with_headless tests8 (4 header-validation + 2 file-variant rejection + 1 icons_buffer_round_trip + 1 with_names_sub_256)
Tier-2 integration tests1 (icon_buffer_mutations_are_drawn)
Doctests passing146145 (−1 from AsF32 dedup; no rgui regression)
nextest full features7678 (+2 LoadStyleFromMemoryError)
nextest SR (no raygui)8890 (+2 LoadStyleFromMemoryError)
nextest SR+raygui100102 (+2: render_gui unchanged; integration_rgui_icons +1)
CI workflows green on fork5/5 (see CI inventory below)5/5

Decisions executed

#DecisionOutcome
D1Typed grid &[[u32; 8]; 256] + &mut
D2aSplit load API, no bool
D2bWrap GuiLoadIconsFromMemory
D3aRe-vendor raygui (chosen path: hand-patch fallback)✅ — the upstream master snapshot at the PR #549 merge commit (4fbd425) brought signature changes on GuiTabBar / GuiListViewEx that would have required Rust-side changes outside this workstream's scope; per scope-discovery-fix-gap-spike-rest, fell back to the 3-line hand-patch. Marked with TODO(raygui-sync) markers at all three sites + at the new GuiLoadIconsFromMemory extern decl that was also missing from the raygui header.
D3btry_from::<i32> + LengthOverflow
D4Remove _raw entirely
D5Defer SR doctest leg✅ (still deferred)
D6Bundle four minor cleanups✅ (all four landed — Music typo, ALBEDO comment, RSliceGlyphInfo doc, AsF32 dedup; mod.rs skipped as already adequate)
D7Pre-validate icons files in Rust
D8Allocator unification via RAYGUI_MALLOC = RL_MALLOC✅ in binding/rgui_wrapper.c (with a build.rs comment pointing to it)

Commits shipped

SHASubject
df37cf7docs(ws-gui-icons): spec for safe-abstractions + PR #296 fold-in
7b6535adocs(ws-gui-icons): plan for safe-abstractions + PR #296 fold-in
722c42ebuild(raylib-sys): hand-patch raygui.h to expose GuiLoadStyleFromMemory
ad6ee0dfix(raylib-sys): add public forward decl for GuiLoadIconsFromMemory; broaden TODO markers
d35a2d8build(raylib-sys): unify raygui allocator with raylib's RL_MALLOC/CALLOC/FREE
e538f32docs(build): point gen_rgui() at the source-file allocator defines
87a0833feat(error): add LoadIconsError and LoadStyleFromMemoryError
c833439fix(error): tighten LoadIconsError::FileNotFound docstring; add Io From-impl test
cc09beefeat(rgui)!: safe gui_get_icons / gui_get_icons_mut; remove _raw
3d571fffix(rgui): icons test slot + tighten SAFETY comment + bitmap doc
a56cddafeat(rgui): gui_load_icons_from_memory + _with_names
db77b82fix(rgui): copy_and_free_names must use icon_count, not RAYGUI_ICON_MAX_ICONS
b637362feat(rgui): gui_load_icons + _with_names (file variants)
1aa9866fix(rgui): file-variant load fixups (read_to_end, no panic, error docs)
e9b3650feat(rgui): gui_load_style_from_memory (PR #296)
4b5e0c3test(rgui): Tier-2 integration test proving icon buffer is live
f75f41edocs(changelog): add 6.0.0 entries for rgui safe icons + style-from-memory
ce04407chore(rustdoc): four R2-minor cleanups deferred from rustdoc-rewrite
e7f6747docs(changelog): restore samples/ migration prose to its bullet
27a7b63fix(rgui): gate GuiGetIcons/GuiLoadIcons calls on feature = "raygui"

Lessons learned

  • The reviewer-caught iconCount vs 256 OOB bug in copy_and_free_names was a Critical UB that the spec's pseudo-code propagated. Updated the spec inline (commit db77b82) so the from-file variant inherited the corrected pattern. The pattern: always pass the raygui-reported iconCount from the validated header, never the static constant.
  • path.exists() swallows PermissionDeniedfs::metadata with explicit ErrorKind::NotFound discrimination is the right pattern for distinguishing "file absent" from "I/O error". Discovered during D7 implementation; corrected in 1aa9866.
  • Read::read can short-return on a valid filetake(N).read_to_end is the safer header-read primitive that guarantees all N bytes are collected if available. Plain read is permitted to return fewer even when more data exists.
  • CString::new(...).expect(...) panics on NUL bytes in paths — map to a typed LoadIconsError::Io instead. Discovered and fixed in 1aa9866.
  • The raygui feature gate on trait methods — new icons trait methods call GuiGetIcons, GuiLoadIconsFromMemory, and GuiLoadIcons, which are only compiled when the raygui feature enables rgui_wrapper.c. Without the gate, the SR (software_renderer, no raygui) build produced 3 linker errors. Fixed by gating all 6 new methods + helper fns with #[cfg(feature = "raygui")] (commit 27a7b63). This is the correct pattern for any future raygui-specific trait methods.

Tracked-deferred (carries forward to WS9 + post-release)

  • SR doctest leg re-enable (test.yml lines 99-110).
  • ease.rs::back_in_out + expo_in_out interior math bugs.
  • PR #277 wrapper-soundness refactor.
  • get_gamepad_button_pressed transmute UB.
  • structoptclap, paste rewrite/swap.
  • macOS / Windows UBSAN coverage.
  • bevy-raylib crate (owner's post-release intent).
  • gui_load_style silent-failure pre-validation (D7 narrow scope only covered the icons path).
  • GuiLoadIconsFromMemory upstream multi-call leak — raygui reassigns guiIconsPtr to a fresh malloc without freeing the previous one. Documented in the wrapper rustdoc; not fixable from the Rust side.
  • Next raygui re-vendor cleanup: when the next raygui sync happens, the hand-patch markers at binding/raygui.h lines 747, 762, 1537, 4983 should be cleaned up — and GuiTabBar / GuiListViewEx will need Rust-side updates for the const char**char** signature changes that come with upstream master.
  • integration_rgui_icons not yet in test.yml — the CI's software-render job doesn't yet run integration_rgui_icons. Add it alongside the existing raygui render test leg in a future CI pass.

CI inventory

All 5 workflows green on fork (Dacode45/ms-raylib-rs, branch 6.0-rc, commit 99065cc).

WorkflowRun IDDurationStatus
book2673357243252s✅ success
sanitizers267335724411m34s✅ success
check267335724361m32s✅ success
web267335724332m36s✅ success
test267335724382m54s✅ success

Next workstream

WS9 — showcase finale. Port all of raylib's official C examples to Rust (showcase/originalshowcase/src/example), build on desktop + wasm where applicable, assemble + deploy the GitHub Pages gallery + book.

pixel-pointers ✅ → hashes ✅ → mixed-audio ✅ → raylib-test ✅ → UBSAN ✅ → rustdoc rewrite ✅ → safe-abstractions for GuiGetIcons/GuiLoadIcons + PR #296 ✅ → **WS9 showcase ← NEXT** → GitHub Pages (finale) → final-release.