Skip to content

zig: zon results come from their owner's arena - #452

Merged
foxnne merged 1 commit into
zig/017-release-packagingfrom
zig/017-zon-arenas
Oct 16, 2026
Merged

foxnne merged 1 commit into
zig/017-release-packagingfrom
zig/017-zon-arenas

Conversation

@foxnne

@foxnne foxnne commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Part of fizzyedit/plans#5 (plans/ZIG_0_17_PLAN.md, step 2: std.zon.parse). Stacked on #448: based on zig/017-release-packaging, so this diff is only the zon work.

What changes

Zig 0.17's std.zon.parse.fromSlice takes a gpa for scratch and an arena that owns the result and any diagnostics, and there is no free. The scaffold (#437) bridged it with a stand-in: parse into a throwaway arena, deep-copy into the old allocator, plus a file-local copy of 0.16's free, in 20 files. This replaces every call with the arena that actually owns its result. The diff is −1,298/+200: the generated copy-and-free helpers go.

  • Parsed, used and freed in one scope (recents, the settings migrations, the workbench layout snapshot, the window-layout reads and saves, tests): a local arena that dies where the free used to run. Lifetimes are unchanged.
  • Parsing into an arena already (sdk.events.parse, Tape.parse, the restart session, Command.Call.parse, the replay and profile tests): that arena, passed as .arena.
  • Types that hold no pointers (the saved window geometry, SDL's saved window, the demo verdict's expectations): fromSliceNoAlloc. It checks at compile time that the type holds no pointers, and its result outlives the arena.
  • API changes, each with every caller updated:
    • Settings.parseOnly(allocator, arena, data). freeParsed is gone, and with it the workaround for freeing a default string literal; load still copies theme, the one string it keeps.
    • sdk.Manifest.parse(gpa, arena, source). Manifest.free is gone. All of PluginLoader's calls already parsed and freed in one scope.
    • layout_file.loadWindowFile(gpa, arena, dir).
  • Plugin settings (sdk.settings.Schema, applyZon and setting one field from ZON text) parse into a short-lived arena, then copy a non-default string out into the schema's allocator. freeOwned's rule still holds: a field is the schema's to free unless it is the declared default.
  • Build scripts reading a plugin's plugin.zig.zon read it into the build's allocator, which lives as long as the build.
  • scripts/zig-0.17/rewrite.sh no longer converts zon calls. A 0.16 call that a merge from main brings now fails to compile and gets ported by hand.

After this, 4 ZIG017 markers remain on the branch: the two per-pointer capture sites (dvui#1014), the examples' branch in check-examples.sh, and the @typeInfo field helper.

SDK impact

  • None
  • Core-only or additive: reaches plugins at the next SDK release. sdk.Manifest.parse takes an arena and sdk.Manifest.free is gone. That is SDK API, but not the plugin boundary: no fingerprint move (zig build test-sdk-version passes), and no store plugin calls either.
  • Fingerprint moved
  • SDK release

Verified

  • macOS (arm64, 0.17.0):
    • scripts/check-fmt.sh, zig build, zig build test (91/91 steps), zig build test-integration (77/77 steps, 523/523 tests, no leak reports), zig build check-web, zig build test-sdk-version, zig build check-tests-reached, zig build -Dvelopack=true.
    • scripts/check-examples.sh against the examples' zig-0.17 branches: all 8 builds pass.
    • The app, in a sandbox profile with an existing layout.zon and recents.zon: starts without a parse warning. With a settings.zon naming a non-default theme, the theme name survives the arena (fizzy's "did not match any known theme" warning names it), and the settings migration rewrites the file keeping theme and font_body_size.
  • Windows: CI.
  • Linux: CI.
  • Web: zig build check-web.

🤖 Generated with Claude Code

@foxnne
foxnne force-pushed the zig/017-zon-arenas branch from f18d1fe to d663e1d Compare October 16, 2026 14:28
Zig 0.17's std.zon.parse allocates results and diagnostics in an
arena the caller passes, and has no free. Every parse now names the
arena that owns its result: a local one where the old code parsed and
freed in one scope, the caller's where the result is kept.
Settings.parseOnly, Manifest.parse and layout_file.loadWindowFile take
that arena; plugin settings copy their non-default strings out of it.
The stand-in, its generated deep copy and free, and its rewrite-script
step are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@foxnne
foxnne force-pushed the zig/017-zon-arenas branch from d663e1d to 560e63d Compare October 16, 2026 15:12
@foxnne
foxnne marked this pull request as ready for review October 16, 2026 15:42
@foxnne
foxnne merged commit aaeb747 into zig/017-release-packaging Oct 16, 2026
12 of 22 checks passed
@foxnne
foxnne deleted the zig/017-zon-arenas branch October 16, 2026 15:42
@foxnne foxnne mentioned this pull request Oct 18, 2026
3 of 4 tasks
foxnne added a commit that referenced this pull request Oct 18, 2026
Part of fizzyedit/plans#5 (`plans/ZIG_0_17_PLAN.md`, step 2): fizzy, its
backend and its bundled plugins move to Zig 0.17. Every piece was
reviewed as its own PR into `zig/0.17`, and this PR lands that branch.
`main` is already merged in (through #555), so it carries no conflicts.

## What changes

**The move to 0.17** (`minimum_zig_version = "0.17.0"` everywhere), as
reviewed in:
- #437: the switch, scaffolded with marked stand-ins
- #438: the build's custom steps become helper programs
- #448: release packaging on 0.17, with Velopack 1.2.161 (+ #452's zon
arenas)
- #488: settings and command schemas read 0.17's `@typeInfo`, with a
test that the SDK fingerprint hashes the same facts as on 0.16
- #489: per-pointer capture through `captureMouseGet`
- #494: the Windows traps in `docs/PITFALLS.md`
- #496: `blitData` without an `extern struct` `@bitCast`
- #498: `fizzy.plugin.installBeside`, for a plugin's helper program
- #505: the 0.16 inflate workaround goes; the docs say 0.17
- #561: review fixes. A settings payload with pointers is a compile
error, and build reads go through `b.root`.
- #573: the plugin install helper compiles once, in Debug
- the catch-ups with `main` (#486, #503, #558, #574, and the last merge
here), each with `scripts/zig-0.17/rewrite.sh` re-run. That script is
deleted in the last commit.

Most of the diff is mechanical: `zig fmt`'s upgrades (`@backingInt`,
`std.lang`, …) and one-answer renames. The hand migrations are the build
(configure/make split, no custom steps), the zon arenas, `@typeInfo`,
translate-c for `@cImport`, and the `@bitCast` audit. A high-effort
review of the whole `main`…`zig/0.17` diff found five things; the three
correctness ones are fixed in #561, and one efficiency one in #573.

**Also on the branch, merged there by the maintainer:** the windowing
work.
- #480–#483: plain dvui apps on macOS
- #492, #501, #504, #510: OS windows for floating windows, full screen,
pointer routing
- #546: window materials

**Forks:** dvui-dev at its `zig-0.17` head `1b29a16`, which carries
fizzy-dev's patches on upstream's 0.17 `main`, including #540, #544 and
#563's dvui commits. Also assetpack, md4zig, sdl_zig and zig-objc on
their `zig-0.17` branches, and velopack-zig `3d553b7` (tagged
`fizzy-zig0.17`).

## Measured

macOS arm64, under load from other sessions, each step alternated
between the two. 0.16 is `main` #509; 0.17 is `zig/0.17` with #561.

| | Zig 0.16 | Zig 0.17 |
|---|---|---|
| App, cold Debug build | 94.4 s | 78.6 s |
| App, warm no-op rebuild | 0.7 s | 0.4 s |
| `test-integration` (compile + run) | 108.9 s | 90.4 s |
| App, ReleaseFast build | 142.8 s | 131.5 s |
| Image plugin, cold standalone build | 11.6 s | 14.0 s (with #573) |
| Startup, Debug (median of 5) | 565 ms | 466 ms |
| Startup, ReleaseFast (median of 5) | 175 ms | 177 ms |
| Text, ReleaseFast, µs/frame: idle / mid / scroll / typing | 305 / 424
/ 435 / 403 | 240 / 306 / 286 / 290 |
| Markdown, ReleaseFast, 4 docs, median of 5, µs/frame: idle top / mid /
scroll / resize | 1177 / 1735 / 2104 / 1319 | 1270 / 1699 / 1833 / 1192
|

The one slowdown is markdown idle at the top of a document, +8%. The
rest of the plugin build's gap is dvui's own translate-c on 0.17.

## The plan's gate

- **ZLS:** no 0.17 release yet (latest 0.16.0). zigtools/zls#3270 is on
ZLS's master. Completions across `fizzy_sdk` from a plugin are not
checked.
- **Minimum OS:** 0.17 needs Darwin 15+ (OS X 10.11); fizzy's macOS
minimum is 11.0, so no change. Windows 10+ and Linux 5.10+ are not
stated by fizzy.
- **Debug leak reports:** still print (`DebugAllocator`, deprecated,
unchanged). The move to `SafeAllocator` is a follow-up with its own
Debug frame-time check.
- **Velopack:** packaging proven by a test release on macOS (signed and
notarized), Windows and Linux. An update in place was not tested.
- **Every target builds:** in CI. Windows and Linux were not run by hand
on the VMs.

## SDK impact

- [x] Fingerprint moved (`0x5f9c818a6972efd4`, recorded in
`sdk/src/version.zig`); `sdk_version` untouched. `sdk: release 0.2.30`
follows this at once. Plugins need Zig 0.17 to build against it: there's
no overlap window.
- Plugin authors see `minimum_zig_version = "0.17.0"` and
`fizzy.plugin.installBeside`. A settings payload holding pointers other
than a string is now a compile error. `docs/PLUGINS.md` says 0.17.0.

## Right after this merges

1. fizzyedit/example-app#8 and fizzyedit/example-plugin#13 merge. Then a
one-line PR points `scripts/check-examples.sh` back at `main` (it pins
the examples' `zig-0.17` branches until then, so `main`'s CI is never
red).
2. `sdk: release 0.2.30`.
3. The store plugins' 0.17 PRs repin and release: fizzyedit/pixi#51,
zig#15, atlas#16, drive#13, ghostty#14, agent#23, chat#16.

## Verified

- [x] macOS (arm64, Zig 0.17.0), on this tree:
  - `scripts/check-fmt.sh`
  - `zig build`: 71/71
  - `zig build test`: 109/109 steps, 637/638 (1 skipped)
  - `zig build check-tests-reached`: 998 tests in 122 files
  - `zig build check-web`: 42/42
  - `zig build test-sdk-version`: 35/35
  - `zig build test-integration`: 78/78 steps, 608/608
- [x] All seven store plugins built against `zig/0.17`'s `sdk/` and
loaded together in a 0.17 fizzy (Debug, sandbox profile).
- [ ] Windows, Linux, the example repos: CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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