chore: release v0.5.3 - #101
Closed
tycho wants to merge 29 commits into
Closed
Conversation
This is a work-in-progress implementation of a rust output. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Every generated tree records the command line that produced it, but the recorded --out-path is relative to whatever cwd the original invocation used, which is unknowable later — so replaying the recorded command only worked from that exact directory. `gloam regen [paths...]` replays each tree's recorded command with the current gloam, deriving the effective output path from the manifest's own location (<tree>/.gloam/manifest.json) and re-recording the original command line verbatim. Trees therefore regenerate correctly from any working directory, and regeneration never rewrites the recorded command. A path may be a tree root, a directory to search recursively (default: .), or a manifest file itself; bare `gloam lock` snapshots regenerate in place, unrelated files named manifest.json are skipped, and .git/target directories are never descended into. By default each replay is pinned to the tree's recorded provenance (--lock semantics), so a diff shows only the effect of gloam changes; --fresh re-resolves sources instead, advancing the tree. The suggested review filter now matches the current preamble stamps (C ` * @generated`, Rust `// @generated`) and additionally ignores the output BOM's 6-space "blob" lines, which track stamp churn byte-for-byte; that is safe because a provenance pin's blob never moves without its unfiltered sibling "commit" line moving too. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Discovery, path handling, and the locked-vs-fresh semantics now live in `gloam regen` itself, so the xtask just builds the working-copy gloam and runs it. The tree root defaults to the current directory, so a bare `cargo xtask regen` regenerates every tree in the repo — including examples/rust, which the old replay-with-tree-root-cwd scheme could not handle (its recorded --out-path was relative to the repo root, the C examples' to examples/c; no single cwd satisfied both). Signed-off-by: Steven Noonan <steven@uplinklabs.net>
After re-blessing the golden snapshots, replay each example tree's recorded command against the refreshed bundle (`gloam regen --fresh`; locked regen would refuse pins the new bundle no longer satisfies) and include examples/ in the PR. Regenerated files embed gloam's own version/commit, so a regen at a new HEAD always produces cosmetic churn; the regen is kept only when the diff is significant under the same filter `gloam regen` prints for human review (preamble stamps, the manifest's gloam meta block, and the output BOM's file hashes). A real change always registers: generated-file content shows its own diff, and a provenance pin advance moves the unfiltered 6-space "commit" line — so a no-op bundle refresh leaves the PR without example churn, while both spec-driven and generator-driven output changes are committed alongside the bundle they came from. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Locked regeneration with the current gloam: the only substantive change is the C preamble's stamp catching up from the 0.5.1-era "Generated by" wording to "@generated by"; everything else is version/commit stamp churn. The recorded command lines are preserved verbatim. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
README gains `rust` and `regen` entries in the command reference, a "Rust output (experimental)" section showing the generated crate's shape and load API, and a "Regenerating a tree with gloam regen" section under the provenance material. docs/manifest.md points at `gloam regen` as the automated form of the --lock replay it describes. CONTRIBUTING's pipeline sketch and module map pick up generator/rust/ and regen.rs, and CLAUDE.md's design philosophy no longer claims there is no active non-C backend. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Signed-off-by: Steven Noonan <steven@uplinklabs.net>
…eturns The registries express parameter/return types as fragments of C declarator syntax. gloam previously carried them as opaque text, and the Rust backend translated them by string-munging (counting '*'s, applying one const to every pointer level). Parse them instead into a TypeRef IR via the closed declarator grammar (const/struct qualifiers, multi-word scalar bases, per-level pointer constness, array dims, bitfield widths): - parse/ctype.rs: tokenizer + parser + grammar unit tests. Anything outside the grammar is a hard generation error naming the offending declarator, and a corpus test parses every command param/return across all bundled XMLs (>10k declarators), so a registry update introducing a new construct fails loudly at test time instead of flowing through as text a non-C backend would mistranslate. - resolve: Param.ty / Command.return_ty carry the typed view (serde-skipped; the C templates keep rendering raw text, so C output is byte-identical — all goldens unchanged). - generator/rust: print types from TypeRef with per-level pointer mutability. This corrects `const T **` parameters (glShaderSourceARB, the IBM *PointerListIBM family) from `*const *const T` to `*mut *const T`. ABI-identical; the rust golden configs do not select those extensions, so rust goldens are also unchanged, and the printer behavior is pinned by unit tests instead. Also drops the module doc's reference to the removed docs/rust-backend.md. Deliberately not marked as a generated-API break: the Rust backend is experimental and the affected signatures were semantically wrong. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Picks up the TypeRef-based Rust type printer: `const T **` parameters in examples/rust/gl-triangle (glShaderSourceARB, the IBM *PointerListIBM family) correct from `*const *const T` to `*mut *const T`. The C trees change only in generation stamps. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Keep the structured view of every <type> body alongside the assembled C text, instead of discarding it after synthesis: - struct/union: per-member records (raw C fragment, XML-declared name, TypeRef declarator, values= attribute for sType defaults), built in the same walk that synthesizes the C text, so the two views cannot drift - funcpointer: return + parameter signature, from the structured <proto>/<param> format and from old inline-text typedefs alike - typedefs: one arm per preprocessor branch (GLhandleARB's #ifdef __APPLE__ split, the synthesized macOS ptrdiff_t guard), plain typedefs as a single unconditional arm — detected by text shape since the GL-family registries carry no category attribute - Vulkan handles: dispatchable vs non-dispatchable Bodies outside the known shapes degrade to Opaque rather than erroring; a corpus test pins full structured coverage for every struct/union and funcpointer across all bundled XMLs, so a registry update that falls outside the grammar fails with a listing. Spot checks pin the cases hand-maintained type tables get wrong (GLhandleARB is void* on Apple, unsigned int elsewhere — the Rust backend's hardcoded table says u32 unconditionally; RT-3 fixes that by printing from these payloads). resolve::TypeDef carries the payload (serde-skipped): the C templates still render raw_c verbatim, so C output is byte-identical — all goldens unchanged, gloam-pregen regen audit clean (stamp-only churn). Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Replace the Rust backend's hand-maintained BASE_TYPES table with emission derived from the structured TypePayloads (RT-2): type aliases print from typedef arms, callbacks from funcpointer signatures, and forward-declared C structs synthesize deduplicated zero-sized opaque types. The only hand-written layer left is the ABI scalar map (khronos_*/fixed-width C spellings -> Rust), which encodes platform-ABI facts no XML records; an unknown scalar or preprocessor condition is now a hard generation error instead of a silently wrong hand-copied alias. Rust output changes (goldens re-blessed, diff reviewed): - GLhandleARB is now cfg-split: *mut c_void on target_vendor="apple", u32 elsewhere — matching gl.xml's #ifdef __APPLE__ arms. The old hardcoded u32 was wrong on Apple platforms. - The macOS ptrdiff_t guard arms collapse to a single isize alias (identical Rust mapping), as before. - Aliases follow registry order; GLDEBUGPROCARB/KHR are full signatures instead of aliases (identical types); GLclampx is now emitted (the hand table had silently omitted it). Generated crate verified to compile (cargo check, merged gl+gles2 config). C output untouched — all C goldens byte-identical. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Picks up the derived GL base types in examples/rust/gl-triangle: registry-ordered aliases, the GLhandleARB apple/other cfg split, full DEBUGPROC signatures, and grouped opaque struct types. The C trees change only in generation stamps. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
New generator/rust/vk_types.rs prints the resolved Vulkan type surface as Rust from the structured payloads and enum groups: - API constants from flat enums via a closed literal grammar ((~0U), (~0ULL), floats, extension NAME strings as &CStr) — unknown forms are hard errors - enum groups: non-bitmask groups become #[repr(transparent)] newtypes over i32 with free constants (unknown driver values are data, never Rust-enum UB); bitmask *FlagBits groups alias their *Flags carrier so constants combine with | and assign to fields exactly as in C. The bitmask distinction now flows from <enums type="bitmask"> through RawEnumGroup/EnumGroup (was parsed away; C-output-neutral, goldens unchanged) - handles: dispatchable = newtype over *mut c_void, non-dispatchable = newtype over u64 (the one shape that is ABI-correct on every target) - structs/unions: #[repr(C)] from member records; consecutive bitfield members merge into a u32 carrier field with shift/mask accessor methods (the acceleration-structure instance structs) - funcpointers as Option<unsafe extern "system" fn>, platform protects as #[cfg(feature)] guards, #define aliases as type aliases - a platform-handle table declares the ABI shape of every WSI type that C gets from platform headers (windows.h, Xlib, xcb, wayland, Metal, OpenHarmony, NvSci, ...); only referenced names are emitted Corpus test: every type in bundled vk.xml either emits or names a StdVideo* dependency (vk_video header types are a documented hard error until they get structured parsing). Spot checks pin handles, sType shapes, unions, bitfield packing math, and platform collection. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
The dependency-following pass collected prerequisite extension names into a HashSet and pushed them into the selection in its iteration order — random per process. Selection order determines extArray indices and (via consumer signatures) command ordering, so any build whose --extensions list pulls in dependencies (e.g. VK_KHR_acceleration_structure pulling VK_KHR_maintenance3 and VK_KHR_device_group) generated differently from run to run, violating the deterministic-output guarantee. Latent until now: no golden or pregen config selects a dependency-pulling extension list, which is also why all existing goldens are unchanged by the fix. Surfaced by the new rust_vk_ext golden flaking between bless and verify. IndexSet preserves discovery order. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Un-gate Spec::Vk in the Rust backend. generator/rust/vk_loader.rs emits a crate mirroring the C backend's phased Vulkan loading contract: - initialize(gipa): store vkGetInstanceProcAddr, load Global-scope commands (vkCreateInstance, vkEnumerateInstance*) - load_instance(instance, api_version, enabled_extensions): feature flags from the requested version, extension flags from the enabled list (XXH3 + binary search against the pre-baked table, identical to C detection), Global+Instance-scope loading - load_physical_device_extensions(...): pre-load Instance-scope queries of device extensions before a VkDevice exists (flags untouched) - load_device(device, physical_device, enabled_extensions): resolve vkGetDeviceProcAddr, cap features at the device apiVersion (variant-masked), reload all scopes so Device-scope commands get the direct-dispatch fast path Scope-aware loading consults a COMMAND_SCOPES table (the C backend's kCommandScopes equivalent); null results never clobber loaded slots, so phases are additive. Dispatch methods reuse the shared emit_method with a Vulkan type mapper (parameter arrays decay as in C); platform- protected commands and types carry #[cfg(feature = "VK_USE_PLATFORM_*")] guards with the features declared in the generated Cargo.toml. A prelude provides VK_MAKE_API_VERSION/VK_API_VERSION_* as const fns and the PFN_vkGet*ProcAddr types. New rust_vk_ext golden pins the full surface (including win32_surface for the cfg paths); the generated crate compile-checks clean with no features and with --all-features across a platform-rich extension set. Vulkan constant grammar extended for (~1U)/(~2U) forms; struct members named `type` sanitize to `type_`; StdVideo-referencing (video-codec) extensions are a documented hard error pointing at --extensions. GL output is untouched (all GL goldens byte-identical); --mx-global on Vulkan is rejected for now. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
examples/rust/vk-info: headless smoke test of the gloam_vk crate's phased loading contract. Bootstraps vkGetInstanceProcAddr via libloading, then initialize -> CreateInstance -> load_instance -> CreateDevice -> load_device, proving Device-scope dispatch by obtaining a queue through the vkGetDeviceProcAddr fast path. Prints instance and device versions, the loader's capped version, and feature/extension flags. Exit codes 0/1/77 match the C example conventions. Verified passing on an RTX 5090 (instance 1.4, device api 1.4): all version features detected, all five enabled extensions flagged, queue obtained. The checked-in gloam/ crate regenerates via cargo xtask regen examples (now 4 recorded trees). Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Stamp-only refresh across all four trees after the vk-info example landed; content is identical. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Un-gate EGL in the Rust backend. The generated gloam_egl crate mirrors the C backend's EGL contract: Egl::load_egl(display, loader) bootstraps eglQueryString, parses EGL_VERSION, gates feature loading on the parsed version, detects extensions from the client string (EGL_NO_DISPLAY) plus the display string for a real display — tokenized and matched via the same pre-baked XXH3 tables as C — then loads extension ranges and resolves aliases. Passing EGL_NO_DISPLAY is a supported phase-0 (EGL 1.5 client semantics), which is what ANGLE platform selection needs before any display exists. Supporting changes: - emit_base_types is spec-parameterized (newtype-skip list + platform table hook + command-signature sweep); EGL's native handle types and EGLint live in eglplatform.h, so they get per-target declarations mirroring its platform arms - rust_type maps raw C scalar spellings through the ABI table: a bare C `char` passed through verbatim names RUST's 4-byte char and silently breaks the ABI (eglQueryString returns `const char *`; EGL_MESA_image_dma_buf_export passes `int *`) - inline struct bodies in raw text (EGLClientPixmapHI) parse into member payloads and emit as #[repr(C)] structs - `#define PFN...PROC` naming shims and category-less `#include` carriers are skipped: dispatch methods replace PFN typedefs - EGL constants: EGL_CAST(T,V) forms emit as `V as T`; enum-shaped values as EGLenum (a plain u32 alias), 64-bit values as u64 - abi map additions: intptr_t/ssize_t/uintptr_t and the khronos nanosecond-timestamp types New rust_egl golden pins the full-extension surface (the production shape); the generated crate compile-checks clean. GL and Vulkan output are unchanged (all goldens byte-identical). Signed-off-by: Steven Noonan <steven@uplinklabs.net>
examples/rust/egl-info: headless smoke test of the gloam_egl crate, mirroring a real ANGLE application's startup. Phase-0 load_egl(EGL_NO_DISPLAY) detects the client extensions; with EGL_ANGLE_platform_angle present, each ANGLE render backend (D3D11, Vulkan, desktop OpenGL, OpenGL ES) is selected via eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, ...) with the EGL_PLATFORM_ANGLE_TYPE_* attributes, initialized, re-loaded against the live display (exercising display-extension detection), and reported. Plain EGL implementations (Mesa) fall back to the default display. libEGL comes from the EGL_LIBRARY env var or platform default names; ANGLE binaries are never committed. Verified against an ANGLE build on an RTX 5090: all four backends initialize and report EGL 1.5 (vendor Google Inc./NVIDIA), exit PASS. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Stamp-only refresh across all five trees after the egl-info example landed; content is identical. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Every feature set the Rust backend generates writes the same crate paths (Cargo.toml, src/lib.rs), so a request like --api gl:core,gles2,egl,vk resolved to several loaders and silently kept only the last one — the earlier specs' crates were generated and then overwritten, and the manifest recorded files that no longer matched the tree. Hard-error with the resolved spec list instead. A per-spec module layout (src/gl.rs, src/egl.rs, src/vk.rs under one crate, mirroring the C backend's per-spec .c/.h files) is the intended future shape. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
rust_backend_rejects_non_gl_specs used EGL as its unsupported-spec probe, which the Rust backend now accepts (along with Vulkan) — probe with WGL instead, which remains unsupported. Also cover the multi-spec refusal: several resolved loaders in one invocation must fail rather than clobber one crate's files. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
The Rust backend now generates one crate covering every resolved feature set, with one module file per spec — src/gl.rs, src/egl.rs, src/vk.rs — mirroring the C backend's per-spec .c/.h files in a shared tree. lib.rs carries the crate-level attributes (#![no_std]) and module declarations; Cargo.toml is emitted once, its crate name joining the spec stems (gloam_gl_egl_vk) and its features the union of every module's needs. This makes --api gl:core,gles2,egl,vk a single dependency whose modules can feed each other (EGL's GetProcAddress into the GL loader), exactly like the C tree. Single-spec crates keep their names (gloam_gl) and re-export the module at the root, so existing consumers compile unchanged — both examples rebuild and pass without source edits. Multi-spec crates do not re-export: loader types (each module's LoadError) collide. The golden harness snapshots every file under src/ individually, and the rust goldens re-blessed to the new layout (the module bodies are the previous lib.rs contents minus the crate-level attribute). The multi-spec refusal from the clobber fix is replaced by structure tests for both layouts. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
Picks up the per-spec module layout in the three Rust example crates (src/gl.rs / src/egl.rs / src/vk.rs plus a thin lib.rs re-exporting the module); example sources are unchanged. C trees change only in stamps. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
rusqlite 0.40 requires it, and 1.95 is a few months old, so it seems an okay version bump to accept. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 New release
gloam: 0.5.2 -> 0.5.3 (✓ API compatible changes)Changelog
This PR was generated with release-plz.