diff --git a/app/Recents.zig b/app/Recents.zig index 07133b1cf..4b38e6b12 100644 --- a/app/Recents.zig +++ b/app/Recents.zig @@ -49,15 +49,10 @@ pub fn load(allocator: std.mem.Allocator, path: []const u8) !Recents { if (core.fs.readZ(allocator, dvui.io, path) catch null) |data| { defer allocator.free(data); - if ((zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Disk, .{ .gpa = allocator, .arena = zig017_arena.allocator(), .source = data, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Disk, allocator, zig017_v) else |zig017_e| zig017_e; - }) catch null) |disk| { - defer zig017ZonFree(allocator, disk); - + var disk_arena: std.heap.ArenaAllocator = .init(allocator); + defer disk_arena.deinit(); + var disk_diag: std.zon.parse.Diagnostics = undefined; + if (std.zon.parse.fromSlice(Disk, .{ .gpa = allocator, .arena = disk_arena.allocator(), .source = data, .diagnostics = &disk_diag, .ignore_unknown_fields = true }) catch null) |disk| { for (disk.folders) |folder| { // A folder on a mount (`gdrive://…`) is not the disk's to check: it exists // whenever its plugin is signed in, which is decided at open time. @@ -172,64 +167,3 @@ pub fn deinit(recents: *Recents, allocator: std.mem.Allocator) void { recents.commands.deinit(allocator); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/app/settings/Settings.zig b/app/settings/Settings.zig index c4c7ffae3..5ede92e37 100644 --- a/app/settings/Settings.zig +++ b/app/settings/Settings.zig @@ -175,47 +175,36 @@ pub fn load(allocator: std.mem.Allocator, path: []const u8, plugins_dir: ?[]cons const data = core.fs.readZ(allocator, dvui.io, path) catch return default(allocator); defer allocator.free(data); - const parsed = parseOnly(allocator, data) catch |err| { + var arena: std.heap.ArenaAllocator = .init(allocator); + defer arena.deinit(); + const parsed = parseOnly(allocator, arena.allocator(), data) catch |err| { dvui.log.warn("Could not parse settings.zon ({s}); using defaults.", .{@errorName(err)}); return default(allocator); }; - defer freeParsed(allocator, parsed); - var result = parsed; // Own `theme` for the process lifetime (freed in `deinit`); every other field is scalar. result.theme = try allocator.dupe(u8, parsed.theme); return result; } -/// Frees a `parseOnly`/`load` result. Not `std.zon.parse.free` directly: since R12 the file only -/// records non-default fields, so a missing `theme` is filled by `std.zon.parse` with *this -/// struct's declared default* — a comptime string literal, not an allocation — and handing that -/// pointer to the allocator would be an invalid free. Zeroing it first makes the whole-struct -/// free a no-op for that field (`Allocator.free` returns early on an empty slice) while still -/// covering any other allocated field. -pub fn freeParsed(allocator: std.mem.Allocator, parsed: Settings) void { - var value = parsed; - if (value.theme.ptr == default_theme.ptr) value.theme = ""; - zig017ZonFree(allocator, value); -} - /// Parses `data` (already-read `settings.zon` bytes) into a `Settings` value, ignoring unknown /// fields (forward-compat + `.plugins` is handled separately — see `load`'s doc comment above). /// Unlike `load`, this returns the raw parse error on failure instead of falling back to /// defaults — defaulting is only correct when there's no existing live state to fall back *to* /// (startup); `Editor.reconcileExternalSettingsChange` (external hand-edit reconciliation, R11) /// has existing state and must not let a transient torn-write read reset every fizzy field and -/// every plugin's settings. Caller frees the result with `freeParsed` (not `Settings.deinit`, -/// which owns the live value's long-lived `theme`). -pub fn parseOnly(allocator: std.mem.Allocator, data: [:0]const u8) !Settings { +/// every plugin's settings. The result's strings live in `arena` (`allocator` is the parse's +/// scratch); `load` copies out the one it keeps. +pub fn parseOnly(allocator: std.mem.Allocator, arena: std.mem.Allocator, data: [:0]const u8) !Settings { @setEvalBranchQuota(10_000); - var parsed = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Settings, .{ .gpa = allocator, .arena = zig017_arena.allocator(), .source = data, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Settings, allocator, zig017_v) else |zig017_e| zig017_e; + var diag: std.zon.parse.Diagnostics = undefined; + var parsed = try std.zon.parse.fromSlice(Settings, .{ + .gpa = allocator, + .arena = arena, + .source = data, + .diagnostics = &diag, + .ignore_unknown_fields = true, }); SettingsMigration.windowGlass(allocator, data, &parsed); return parsed; @@ -238,7 +227,7 @@ fn fieldEqual(comptime FT: type, a: FT, b: FT) bool { /// halves of `settings.zon` record just what the user actually changed. An untouched fizzy /// serializes to `.{}`; a field hand-written back at its default drops out on the next write. /// Reading back is unaffected: `load`/`parseOnly` fill every missing field from these same -/// defaults (see `freeParsed` for the one ownership wrinkle that creates). +/// defaults (they are the declared defaults themselves: `load` copies `theme` before keeping it). /// /// This is *not* the whole `settings.zon` file — plugin settings are a separate /// `.plugins = .{ . = .{...}, ... }` field spliced on afterward by @@ -269,64 +258,3 @@ pub fn serialize(settings: *const Settings, allocator: std.mem.Allocator) ![]u8 pub fn deinit(settings: *Settings, allocator: std.mem.Allocator) void { allocator.free(settings.theme); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/app/settings/SettingsMigration.zig b/app/settings/SettingsMigration.zig index 4592718a3..ae99eaa8f 100644 --- a/app/settings/SettingsMigration.zig +++ b/app/settings/SettingsMigration.zig @@ -75,17 +75,13 @@ pub fn migrateToPerPluginEnabled(allocator: std.mem.Allocator, settings_zon_path defer allocator.free(data); @setEvalBranchQuota(10_000); - const legacy = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(LegacyDisk, .{ .gpa = allocator, .arena = zig017_arena.allocator(), .source = data, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(LegacyDisk, allocator, zig017_v) else |zig017_e| zig017_e; - }) catch |err| { + var legacy_arena: std.heap.ArenaAllocator = .init(allocator); + defer legacy_arena.deinit(); + var legacy_diag: std.zon.parse.Diagnostics = undefined; + const legacy = std.zon.parse.fromSlice(LegacyDisk, .{ .gpa = allocator, .arena = legacy_arena.allocator(), .source = data, .diagnostics = &legacy_diag, .ignore_unknown_fields = true }) catch |err| { dvui.log.warn("settings: could not parse settings.zon for R12 enabled migration ({s}); skipping", .{@errorName(err)}); return; }; - defer zig017ZonFree(allocator, legacy); const blocks = SettingsPluginsZon.listPluginBlocks(allocator, data) catch return; defer SettingsPluginsZon.freeEntries(allocator, blocks); @@ -161,11 +157,12 @@ pub fn migrateToPerPluginEnabled(allocator: std.mem.Allocator, settings_zon_path // Regenerate fizzy's own fields from a Settings parse (unknown fields — including the legacy // `disabled_plugins` list — are ignored), so the rewritten file drops that list for free. - const parsed = Settings.parseOnly(allocator, data) catch |err| { + var parsed_arena: std.heap.ArenaAllocator = .init(allocator); + defer parsed_arena.deinit(); + const parsed = Settings.parseOnly(allocator, parsed_arena.allocator(), data) catch |err| { dvui.log.warn("settings: could not re-serialize fizzy's own fields for R12 migration ({s}); skipping", .{@errorName(err)}); return; }; - defer Settings.freeParsed(allocator, parsed); const fizzy_text = Settings.serialize(&parsed, allocator) catch |err| { dvui.log.warn("settings: could not serialize fizzy's own fields for R12 migration ({s}); skipping", .{@errorName(err)}); @@ -258,14 +255,10 @@ const LegacyGlass = struct { /// dialogs' blur goes with them, as the roughness that followed it does. pub fn windowGlass(allocator: std.mem.Allocator, data: [:0]const u8, settings: *Settings) void { @setEvalBranchQuota(10_000); - const legacy = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(LegacyGlass, .{ .gpa = allocator, .arena = zig017_arena.allocator(), .source = data, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(LegacyGlass, allocator, zig017_v) else |zig017_e| zig017_e; - }) catch return; - defer zig017ZonFree(allocator, legacy); + var legacy_arena: std.heap.ArenaAllocator = .init(allocator); + defer legacy_arena.deinit(); + var legacy_diag: std.zon.parse.Diagnostics = undefined; + const legacy = std.zon.parse.fromSlice(LegacyGlass, .{ .gpa = allocator, .arena = legacy_arena.allocator(), .source = data, .diagnostics = &legacy_diag, .ignore_unknown_fields = true }) catch return; if (legacy.dialog_opacity == null and legacy.dialog_blur == null and legacy.dialog_lift == null and legacy.dialog_detail == null and legacy.dialog_refraction == null) return; const opaque_window = comptime builtin.target.cpu.arch == .wasm32 or (builtin.target.os.tag != .macos and builtin.target.os.tag != .windows); @@ -274,64 +267,3 @@ pub fn windowGlass(allocator: std.mem.Allocator, data: [:0]const u8, settings: * settings.window_opacity_light = std.math.clamp(o, 0, 1); }; } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/app/store/PluginLoader.zig b/app/store/PluginLoader.zig index fab9e8e04..6f1f12e23 100644 --- a/app/store/PluginLoader.zig +++ b/app/store/PluginLoader.zig @@ -532,8 +532,9 @@ pub fn probeName(allocator: std.mem.Allocator, path: []const u8) ?[]u8 { if (lib.lookup(dylib_api.GetManifestZonFn, dylib_api.symbol_manifest_zon)) |get_zon| { const zon = std.mem.span(get_zon()); if (zon.len > 0) { - if (sdk.Manifest.parse(allocator, zon)) |parsed| { - defer sdk.Manifest.free(allocator, parsed); + var arena: std.heap.ArenaAllocator = .init(allocator); + defer arena.deinit(); + if (sdk.Manifest.parse(allocator, arena.allocator(), zon)) |parsed| { if (parsed.name.len > 0) return allocator.dupe(u8, parsed.name) catch null; } else |_| {} } @@ -570,8 +571,9 @@ pub fn probeManifestInfo(allocator: std.mem.Allocator, path: []const u8) ?Probed const get_zon = lib.lookup(dylib_api.GetManifestZonFn, dylib_api.symbol_manifest_zon) orelse return null; const zon = std.mem.span(get_zon()); if (zon.len == 0) return null; - const parsed = sdk.Manifest.parse(allocator, zon) catch return null; - defer sdk.Manifest.free(allocator, parsed); + var arena: std.heap.ArenaAllocator = .init(allocator); + defer arena.deinit(); + const parsed = sdk.Manifest.parse(allocator, arena.allocator(), zon) catch return null; var out: ProbedManifest = .{}; errdefer freeProbedManifest(allocator, out); @@ -614,10 +616,10 @@ pub fn probeVersionInfo(path: []const u8) ?PluginVersionInfo { if (lib.lookup(dylib_api.GetManifestZonFn, dylib_api.symbol_manifest_zon)) |get_zon| { const zon = std.mem.span(get_zon()); if (zon.len > 0) { - // Stack/arena-free parse: use page allocator for a short-lived Manifest. - const gpa = std.heap.page_allocator; - if (sdk.Manifest.parse(gpa, zon)) |parsed| { - defer sdk.Manifest.free(gpa, parsed); + // A short-lived Manifest, in an arena over the page allocator. + var arena: std.heap.ArenaAllocator = .init(std.heap.page_allocator); + defer arena.deinit(); + if (sdk.Manifest.parse(std.heap.page_allocator, arena.allocator(), zon)) |parsed| { if (std.SemanticVersion.parse(parsed.version)) |sv| { plugin_version = .{ .major = @intCast(sv.major), .minor = @intCast(sv.minor), .patch = @intCast(sv.patch) }; } else |_| {} diff --git a/backend/src/Health.zig b/backend/src/Health.zig index 9b9c806cd..eeed51b86 100644 --- a/backend/src/Health.zig +++ b/backend/src/Health.zig @@ -314,14 +314,10 @@ test "a snapshot round-trips through ZON" { try std.zon.stringify.serialize(s, .{}, &out.writer); const text = try std.testing.allocator.dupeSentinel(u8, out.written(), 0); defer std.testing.allocator.free(text); - const back = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(std.testing.allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Snapshot, .{ .gpa = std.testing.allocator, .arena = zig017_arena.allocator(), .source = text, .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Snapshot, std.testing.allocator, zig017_v) else |zig017_e| zig017_e; - }); - defer zig017ZonFree(std.testing.allocator, back); + var back_arena: std.heap.ArenaAllocator = .init(std.testing.allocator); + defer back_arena.deinit(); + var back_diag: std.zon.parse.Diagnostics = undefined; + const back = try std.zon.parse.fromSlice(Snapshot, .{ .gpa = std.testing.allocator, .arena = back_arena.allocator(), .source = text, .diagnostics = &back_diag }); try std.testing.expectEqual(s.presents, back.presents); try std.testing.expectEqual(s.os_windows, back.os_windows); try std.testing.expectEqual(s.ns_windows, back.ns_windows); @@ -330,64 +326,3 @@ test "a snapshot round-trips through ZON" { try std.testing.expectEqual(s.last_frame, back.last_frame); try std.testing.expectEqualStrings(s.first_sdl_error, back.first_sdl_error); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/backend/src/SDLBackend.zig b/backend/src/SDLBackend.zig index a5f5bdd3c..6e8beb16c 100644 --- a/backend/src/SDLBackend.zig +++ b/backend/src/SDLBackend.zig @@ -700,13 +700,10 @@ pub const WindowGeometry = struct { if (data.len >= nul_buf.len) return null; @memcpy(nul_buf[0..data.len], data); nul_buf[data.len] = 0; - const saved = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(std.heap.page_allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Saved, .{ .gpa = std.heap.page_allocator, .arena = zig017_arena.allocator(), .source = nul_buf[0..data.len :0], .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Saved, std.heap.page_allocator, zig017_v) else |zig017_e| zig017_e; - }) catch return null; + var arena: std.heap.ArenaAllocator = .init(std.heap.page_allocator); + defer arena.deinit(); + var diag: std.zon.parse.Diagnostics = undefined; + const saved = std.zon.parse.fromSliceNoAlloc(Saved, .{ .gpa = std.heap.page_allocator, .arena = arena.allocator(), .source = nul_buf[0..data.len :0], .diagnostics = &diag, .ignore_unknown_fields = true }) catch return null; return fromSaved(saved); } @@ -3759,40 +3756,3 @@ const live_resize_trace = struct { (dvui.Rect.Physical{ .x = 200, .y = r.h - 6, .w = r.w - 400, .h = 6 }).fill(.all(0), .{ .color = .{ .color = yellow } }); } }; - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/backend/src/platform/geometry.zig b/backend/src/platform/geometry.zig index f8fb06aa7..e40da2221 100644 --- a/backend/src/platform/geometry.zig +++ b/backend/src/platform/geometry.zig @@ -75,13 +75,10 @@ fn fileLoad(_: ?*anyopaque) ?Geometry { defer gpa.free(data); const z = gpa.dupeSentinel(u8, data, 0) catch return null; defer gpa.free(z); - const g = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Geometry, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = z, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Geometry, gpa, zig017_v) else |zig017_e| zig017_e; - }) catch return null; + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var diag: std.zon.parse.Diagnostics = undefined; + const g = std.zon.parse.fromSliceNoAlloc(Geometry, .{ .gpa = gpa, .arena = arena.allocator(), .source = z, .diagnostics = &diag, .ignore_unknown_fields = true }) catch return null; return if (g.valid()) g else null; } @@ -265,40 +262,3 @@ fn trackLinux() void { if (w < 1 or h < 1) return; linux_normal = .{ .x = @floatFromInt(x), .y = @floatFromInt(y), .w = @floatFromInt(w), .h = @floatFromInt(h) }; } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/core/profile.zig b/core/profile.zig index 8e414551d..60f9d28a7 100644 --- a/core/profile.zig +++ b/core/profile.zig @@ -867,13 +867,8 @@ test "a report says what each owner and scope cost, as ZON that reads back" { }; var arena: std.heap.ArenaAllocator = .init(std.testing.allocator); defer arena.deinit(); - const r = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(arena.allocator()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Report, .{ .gpa = arena.allocator(), .arena = zig017_arena.allocator(), .source = try arena.allocator().dupeSentinel(u8, text, 0), .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Report, arena.allocator(), zig017_v) else |zig017_e| zig017_e; - }); + var diag: std.zon.parse.Diagnostics = undefined; + const r = try std.zon.parse.fromSlice(Report, .{ .gpa = std.testing.allocator, .arena = arena.allocator(), .source = try arena.allocator().dupeSentinel(u8, text, 0), .diagnostics = &diag }); // The plugin's own time is what it spent; fizzy's own is what was left once that is taken out. try std.testing.expectEqualStrings("text", r.owners[0].owner); try std.testing.expect(r.owners[0].self_ms >= 1.5); @@ -957,40 +952,3 @@ test "a frame's GPU counts land in its own slot and the window's average, not be p.frameEnd(); try std.testing.expectEqual(@as(f64, 2), p.stats.gpu.?.targets); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/plugins/shared/build/helpers.zig b/plugins/shared/build/helpers.zig index ba1d37c3a..5beda65ff 100644 --- a/plugins/shared/build/helpers.zig +++ b/plugins/shared/build/helpers.zig @@ -66,13 +66,9 @@ pub fn readManifestAt(b: *std.Build, zon_rel_path: []const u8) IdentityManifest version: []const u8, min_sdk_version: []const u8 = "", }; - const parsed = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(b.allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Target, .{ .gpa = b.allocator, .arena = zig017_arena.allocator(), .source = src, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Target, b.allocator, zig017_v) else |zig017_e| zig017_e; - }) catch |e| + // The build's allocator is freed only when the build ends: the manifest is read into it. + var diag: std.zon.parse.Diagnostics = undefined; + const parsed = std.zon.parse.fromSlice(Target, .{ .gpa = b.allocator, .arena = b.allocator, .source = src, .diagnostics = &diag, .ignore_unknown_fields = true }) catch |e| std.debug.panic("fizzy: failed to parse {s}: {}", .{ zon_rel_path, e }); _ = std.SemanticVersion.parse(parsed.version) catch std.debug.panic("fizzy: {s} .version \"{s}\" is not valid semver", .{ zon_rel_path, parsed.version }); @@ -280,40 +276,3 @@ pub fn installDylib(b: *std.Build, lib: *std.Build.Step.Compile, name: []const u }); b.getInstallStep().dependOn(&install_step.step); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/plugins/workbench/src/workbench_layout.zig b/plugins/workbench/src/workbench_layout.zig index 1e64ba59e..5648edffa 100644 --- a/plugins/workbench/src/workbench_layout.zig +++ b/plugins/workbench/src/workbench_layout.zig @@ -176,17 +176,13 @@ fn loadPanes(wb: *Workbench) void { defer wb.allocator.free(data); const bytes = wb.allocator.dupeSentinel(u8, data, 0) catch return; defer wb.allocator.free(bytes); - const snap = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(wb.allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Panes.Snapshot, .{ .gpa = wb.allocator, .arena = zig017_arena.allocator(), .source = bytes, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Panes.Snapshot, wb.allocator, zig017_v) else |zig017_e| zig017_e; - }) catch |err| { + var snap_arena: std.heap.ArenaAllocator = .init(wb.allocator); + defer snap_arena.deinit(); + var snap_diag: std.zon.parse.Diagnostics = undefined; + const snap = std.zon.parse.fromSlice(Panes.Snapshot, .{ .gpa = wb.allocator, .arena = snap_arena.allocator(), .source = bytes, .diagnostics = &snap_diag, .ignore_unknown_fields = true }) catch |err| { dvui.log.warn("workbench: ignoring {s}: {s}", .{ path, @errorName(err) }); return; }; - defer zig017ZonFree(wb.allocator, snap); var loaded = Panes.fromSnapshot(wb.allocator, snap) catch return; loaded.animated = true; @@ -236,64 +232,3 @@ fn panesPath(wb: *Workbench) ?[]u8 { std.Io.Dir.cwd().createDirPath(dvui.io, dir) catch return null; return std.fs.path.join(wb.allocator, &.{ dir, panes_file }) catch null; } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/scripts/zig-0.17/rewrite.sh b/scripts/zig-0.17/rewrite.sh index 5bbe76ff6..357f2c3fe 100755 --- a/scripts/zig-0.17/rewrite.sh +++ b/scripts/zig-0.17/rewrite.sh @@ -4,8 +4,7 @@ # rewritten too, and delete it in the PR that merges the branch. Idempotent. # # Hand migrations are not here. What is here either `zig fmt` does, or is a rename with one -# right answer. `zon_standin.pl` is the exception: a stand-in for the zon arena migration, -# marked ZIG017 wherever it writes, until that PR replaces it. +# right answer. set -euo pipefail cd "$(jj root 2>/dev/null || git rev-parse --show-toplevel)" here=scripts/zig-0.17 @@ -36,8 +35,8 @@ perl -0pi -e 's/\.dupeZ(\((?:[^()]++|(?1))*\))/my $a=$1; $a =~ s{\)\z}{, 0)}; ". python3 $here/fields.py $files >/dev/null python3 $here/unused.py $here $files >/dev/null -# Stand-in until the zon arena PR: 0.17's std.zon.parse, results in the old allocator. -perl $here/zon_standin.pl $files >/dev/null +# Not std.zon.parse: each call is ported by hand to its owner's arena. A 0.16 call that a merge +# from main brings fails to compile, which is the reminder. # Last: zig fmt's own upgrades (@intFromEnum -> @backingInt, ...). jj file list | grep -E "\.(zig|zon)$" | xargs "${zig[@]}" fmt >/dev/null # everything, spikes too diff --git a/scripts/zig-0.17/zon_standin.pl b/scripts/zig-0.17/zon_standin.pl deleted file mode 100644 index 880f80db5..000000000 --- a/scripts/zig-0.17/zon_standin.pl +++ /dev/null @@ -1,90 +0,0 @@ -# ZIG017 stand-in: 0.16 std.zon.parse calls on 0.17's API, results in the given allocator. Replaced by the zon arena PR. -use strict; use warnings; -local $/; -our $NEED_DUPE = 0; -my $DUPE = <<'ZIGDUPE'; - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -ZIGDUPE -my $FREE = <<'ZIGFREE'; -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} -ZIGFREE -for my $f (@ARGV) { - open my $fh, '<', $f or die; my $s = <$fh>; close $fh; my $o = $s; - $NEED_DUPE = 0; - $s =~ s{std\.zon\.parse\.(fromSliceAlloc|fromSlice)(\((?:[^()]++|(?2))*\))}{conv($2)}ge; - $s =~ s{std\.zon\.parse\.free\(}{zig017ZonFree(}g; - $s .= $DUPE if $NEED_DUPE && $s !~ /fn zig017ZonDupe\(/; - $s .= $FREE if $s =~ /zig017ZonFree\(/ && $s !~ /fn zig017ZonFree\(/; - if ($s ne $o) { open my $w, '>', $f or die; print $w $s; close $w; print "$f\n"; } -} -sub split_args { my ($a)=@_; $a =~ s/^\(//; $a =~ s/\)$//; my @p; my $d=0; my $cur=''; - for my $c (split //, $a) { if ($c eq ',' && $d==0) { push @p, $cur; $cur=''; next } $d++ if $c =~ /[\(\[\{]/; $d-- if $c =~ /[\)\]\}]/; $cur.=$c } push @p, $cur if $cur =~ /\S/; - s/^\s+|\s+$//g for @p; return @p } -sub conv { my ($a)=@_; my @p=split_args($a); return "std.zon.parse.fromSlice$a" unless @p==5; - my ($t,$al,$src,$diag,$opts)=@p; my $iuf = $opts =~ /ignore_unknown_fields\s*=\s*(\w+)/ ? ", .ignore_unknown_fields = $1" : ""; - if ($diag ne 'null') { - return "(zig017_zon: { break :zig017_zon std.zon.parse.fromSlice($t, .{ .gpa = $al, .arena = $al, .source = $src, .diagnostics = $diag$iuf }); })"; - } - $NEED_DUPE = 1; - return "(zig017_zon: { var zig017_zd: std.zon.parse.Diagnostics = undefined; var zig017_arena: std.heap.ArenaAllocator = .init($al); defer zig017_arena.deinit(); " - . "const zig017_r = std.zon.parse.fromSlice($t, .{ .gpa = $al, .arena = zig017_arena.allocator(), .source = $src, .diagnostics = &zig017_zd$iuf }); " - . "break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe($t, $al, zig017_v) else |zig017_e| zig017_e; })" } diff --git a/sdk/plugin_sdk.zig b/sdk/plugin_sdk.zig index 6802c6d10..6025a3d2e 100644 --- a/sdk/plugin_sdk.zig +++ b/sdk/plugin_sdk.zig @@ -111,13 +111,9 @@ fn readManifestAt(b: *std.Build, rel_path: []const u8) IdentityManifest { version: []const u8, min_sdk_version: []const u8 = "", }; - const parsed = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(b.allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Target, .{ .gpa = b.allocator, .arena = zig017_arena.allocator(), .source = src, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Target, b.allocator, zig017_v) else |zig017_e| zig017_e; - }) catch |e| + // The build's allocator is freed only when the build ends: the manifest is read into it. + var diag: std.zon.parse.Diagnostics = undefined; + const parsed = std.zon.parse.fromSlice(Target, .{ .gpa = b.allocator, .arena = b.allocator, .source = src, .diagnostics = &diag, .ignore_unknown_fields = true }) catch |e| std.debug.panic("fizzy: failed to parse {s}: {}", .{ rel_path, e }); _ = std.SemanticVersion.parse(parsed.version) catch std.debug.panic("fizzy: {s} .version \"{s}\" is not valid semver (expected e.g. 1.2.3)", .{ rel_path, parsed.version }); @@ -625,43 +621,6 @@ pub fn installBuiltinPlugin( }); } -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} - /// Declare to Zig 0.17's configure cache that the build read whether `rel` exists: the file itself /// when it does, and otherwise the nearest directory that exists, since the maker cannot load a /// configuration that depends on a path inside a missing directory ("configuration failed: diff --git a/sdk/replay/Snapshot.zig b/sdk/replay/Snapshot.zig index 9c7eb9b58..3dea87645 100644 --- a/sdk/replay/Snapshot.zig +++ b/sdk/replay/Snapshot.zig @@ -382,13 +382,8 @@ test "a snapshot names what a person acts on, and what a tape aims at" { // It reads back as what it says: two buttons by name, the tagged one by its tag, the mark. var arena: std.heap.ArenaAllocator = .init(std.testing.allocator); defer arena.deinit(); - const nodes = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(arena.allocator()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice([]const Node, .{ .gpa = arena.allocator(), .arena = zig017_arena.allocator(), .source = try arena.allocator().dupeSentinel(u8, text, 0), .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe([]const Node, arena.allocator(), zig017_v) else |zig017_e| zig017_e; - }); + var diag: std.zon.parse.Diagnostics = undefined; + const nodes = try std.zon.parse.fromSlice([]const Node, .{ .gpa = std.testing.allocator, .arena = arena.allocator(), .source = try arena.allocator().dupeSentinel(u8, text, 0), .diagnostics = &diag }); var buttons: usize = 0; var save = false; var close = false; @@ -472,13 +467,8 @@ test "a snapshot has the dialogs dvui shows after its capture, and says which wi var arena: std.heap.ArenaAllocator = .init(std.testing.allocator); defer arena.deinit(); - const nodes = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(arena.allocator()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice([]const Node, .{ .gpa = arena.allocator(), .arena = zig017_arena.allocator(), .source = try arena.allocator().dupeSentinel(u8, text, 0), .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe([]const Node, arena.allocator(), zig017_v) else |zig017_e| zig017_e; - }); + var diag: std.zon.parse.Diagnostics = undefined; + const nodes = try std.zon.parse.fromSlice([]const Node, .{ .gpa = std.testing.allocator, .arena = arena.allocator(), .source = try arena.allocator().dupeSentinel(u8, text, 0), .diagnostics = &diag }); // The windows first, each a node. try std.testing.expect(nodes.len > 3); for (nodes[0..3], [_][]const u8{ "app.window:main", "app.window:band", "app.window:dialog" }) |node, tag| { @@ -510,40 +500,3 @@ test "a snapshot has the dialogs dvui shows after its capture, and says which wi // Taken, nothing more is captured: a dialog drawn in a frame nobody asked for is free. try std.testing.expect(!taking()); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/sdk/src/Command.zig b/sdk/src/Command.zig index 1da84a7a0..f911790d4 100644 --- a/sdk/src/Command.zig +++ b/sdk/src/Command.zig @@ -198,9 +198,7 @@ pub fn Params(comptime T: type) type { const text = std.mem.trim(u8, call.args, " \t\r\n"); const source = try call.arena.dupeSentinel(u8, if (text.len == 0) ".{}" else text, 0); var diag: std.zon.parse.Diagnostics = undefined; - return (zig017_zon: { - break :zig017_zon std.zon.parse.fromSlice(Args, .{ .gpa = call.arena, .arena = call.arena, .source = source, .diagnostics = &diag }); - }) catch |err| switch (err) { + return std.zon.parse.fromSlice(Args, .{ .gpa = call.arena, .arena = call.arena, .source = source, .diagnostics = &diag }) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ParseZon => { call.bad_args = true; diff --git a/sdk/src/Manifest.zig b/sdk/src/Manifest.zig index 7cf87ae29..ee31afbce 100644 --- a/sdk/src/Manifest.zig +++ b/sdk/src/Manifest.zig @@ -52,7 +52,7 @@ author_url: []const u8 = "", /// `dupeZ`/`readFileAllocOptions` with a sentinel) into a `Manifest`. Validates `version` (and /// `min_sdk_version`, when non-empty) are well-formed semver post-parse — zon itself has no /// semver type, so this is the manifest's own integrity check on top of the structural parse. -/// Free the result with `free`. +/// The result, its strings included, lives in `arena`; `gpa` is the parse's scratch. /// /// **Unknown fields are ignored on purpose**, which is what makes this format forward-compatible: /// `Manifest` is explicitly a growing set of optional fields (R16 added `description`, R17 added @@ -63,15 +63,15 @@ author_url: []const u8 = "", /// (`probeName`/`probeDescription`/`probeTags`/`probeVersionInfo`) would silently lose data it /// could otherwise still read. The tradeoff accepted here is that a misspelled field name is /// ignored rather than diagnosed; the visible symptom is a store listing missing that value. -pub fn parse(gpa: std.mem.Allocator, source: [:0]const u8) !Manifest { - const m = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Manifest, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = source, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Manifest, gpa, zig017_v) else |zig017_e| zig017_e; +pub fn parse(gpa: std.mem.Allocator, arena: std.mem.Allocator, source: [:0]const u8) !Manifest { + var diag: std.zon.parse.Diagnostics = undefined; + const m = try std.zon.parse.fromSlice(Manifest, .{ + .gpa = gpa, + .arena = arena, + .source = source, + .diagnostics = &diag, + .ignore_unknown_fields = true, }); - errdefer free(gpa, m); _ = std.SemanticVersion.parse(m.version) catch return error.InvalidVersion; if (m.min_sdk_version.len > 0) { _ = std.SemanticVersion.parse(m.min_sdk_version) catch return error.InvalidMinSdkVersion; @@ -79,11 +79,6 @@ pub fn parse(gpa: std.mem.Allocator, source: [:0]const u8) !Manifest { return m; } -/// Free a `Manifest` returned by `parse`. -pub fn free(gpa: std.mem.Allocator, m: Manifest) void { - zig017ZonFree(gpa, m); -} - test "Manifest parse round-trips identity" { const gpa = std.testing.allocator; const source: [:0]const u8 = @@ -95,8 +90,11 @@ test "Manifest parse round-trips identity" { \\} ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + + defer arena.deinit(); + + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqualStrings("example", m.id); try std.testing.expectEqualStrings("Example", m.name); @@ -113,8 +111,9 @@ test "parse defaults min_sdk_version when omitted" { \\ .version = "0.1.0", \\} ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqualStrings("", m.min_sdk_version); } @@ -128,8 +127,9 @@ test "parse defaults tags to empty when omitted" { \\ .version = "0.1.0", \\} ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqual(@as(usize, 0), m.tags.len); } @@ -144,8 +144,9 @@ test "parse round-trips tags" { \\ .tags = .{ "editor", "pixel-art" }, \\} ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqual(@as(usize, 2), m.tags.len); try std.testing.expectEqualStrings("editor", m.tags[0]); @@ -163,8 +164,9 @@ test "parse round-trips author and author_url" { \\ .author_url = "https://example.test/~somebody", \\} ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqualStrings("somebody", m.author); try std.testing.expectEqualStrings("https://example.test/~somebody", m.author_url); @@ -175,8 +177,9 @@ test "parse defaults author and author_url to empty" { const source: [:0]const u8 = \\.{ .id = "example", .name = "Example", .version = "0.1.0" } ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqualStrings("", m.author); try std.testing.expectEqualStrings("", m.author_url); @@ -195,8 +198,9 @@ test "parse ignores fields a newer SDK added" { \\ .another = .{ "a", "b" }, \\} ; - const m = try parse(gpa, source); - defer free(gpa, m); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const m = try parse(gpa, arena.allocator(), source); try std.testing.expectEqualStrings("example", m.id); try std.testing.expectEqualStrings("0.1.0", m.version); @@ -211,66 +215,7 @@ test "parse rejects a non-semver version" { \\ .version = "not-a-version", \\} ; - try std.testing.expectError(error.InvalidVersion, parse(gpa, source)); -} - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + try std.testing.expectError(error.InvalidVersion, parse(gpa, arena.allocator(), source)); } diff --git a/sdk/src/events.zig b/sdk/src/events.zig index 1b66e4aaa..3bd1e270e 100644 --- a/sdk/src/events.zig +++ b/sdk/src/events.zig @@ -53,13 +53,8 @@ pub fn matches(pattern: []const u8, name: []const u8) bool { pub fn parse(comptime T: type, arena: std.mem.Allocator, event: Event) !T { const text = std.mem.trim(u8, event.payload, " \t\r\n"); const source = try arena.dupeSentinel(u8, if (text.len == 0) ".{}" else text, 0); - return (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(arena); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(T, .{ .gpa = arena, .arena = zig017_arena.allocator(), .source = source, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(T, arena, zig017_v) else |zig017_e| zig017_e; - }); + var diag: std.zon.parse.Diagnostics = undefined; + return std.zon.parse.fromSlice(T, .{ .gpa = arena, .arena = arena, .source = source, .diagnostics = &diag, .ignore_unknown_fields = true }); } // ---- what fizzy announces ---- @@ -145,40 +140,3 @@ test "a subscription takes its name, its prefix, or everything" { try std.testing.expect(!matches("fizzy.document.*", "fizzy.folder.opened")); try std.testing.expect(matches("*", "chat.turn_ended")); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/sdk/src/settings.zig b/sdk/src/settings.zig index 9e345b693..4a4b4f77e 100644 --- a/sdk/src/settings.zig +++ b/sdk/src/settings.zig @@ -464,16 +464,32 @@ pub fn Schema(comptime T: type) type { }; defer gpa.free(blob_z); - const parsed = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Payloads, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = blob_z, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Payloads, gpa, zig017_v) else |zig017_e| zig017_e; + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var diag: std.zon.parse.Diagnostics = undefined; + var parsed = std.zon.parse.fromSlice(Payloads, .{ + .gpa = gpa, + .arena = arena.allocator(), + .source = blob_z, + .diagnostics = &diag, + .ignore_unknown_fields = true, }) catch |err| { dvui.log.warn("sdk.settings: failed to parse settings: {s}", .{@errorName(err)}); return; }; + // The parse's strings are in `arena`. One that is not the declared default is copied + // out, so it is this schema's to free (`freeOwned`); a default stays the default. + inline for (struct_fields) |f| { + if (comptime typeTagFor(f.type.Payload) == .string) { + const parsed_str = @field(parsed, f.name); + if (parsed_str.ptr != @field(default_payloads, f.name).ptr) { + @field(parsed, f.name) = gpa.dupe(u8, parsed_str) catch |err| { + dvui.log.warn("sdk.settings: out of memory keeping settings: {s}", .{@errorName(err)}); + return; + }; + } + } + } freeOwned(gpa, out.*); fromPayloads(out, parsed); } @@ -641,16 +657,14 @@ pub fn Schema(comptime T: type) type { const P = f.type.Payload; const text_z = gpa.dupeSentinel(u8, text, 0) catch return false; defer gpa.free(text_z); - const parsed = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(P, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = text_z, .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(P, gpa, zig017_v) else |zig017_e| zig017_e; - }) catch return false; - // Strings follow the same ownership rule as `setString`; other payloads are - // plain values the parse allocated nothing for. + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var diag: std.zon.parse.Diagnostics = undefined; + var parsed = std.zon.parse.fromSlice(P, .{ .gpa = gpa, .arena = arena.allocator(), .source = text_z, .diagnostics = &diag }) catch return false; + // Strings follow the same ownership rule as `setString`: copied out of the + // parse's arena, the schema's to free. Other payloads are plain values. if (comptime typeTagFor(P) == .string) { + parsed = gpa.dupe(u8, parsed) catch return false; if (fieldIsOwned(f.name, v.*)) gpa.free(@field(v.*, f.name).v); } payloadPtr(v, f.name).* = parsed; @@ -1010,40 +1024,3 @@ test "a type with no dedicated control is still a legal setting, edited as zon t // `.other` payloads take part in diff-vs-default like anything else. try testing.expect(try S.diffSerialize(testing.allocator, .{}) == null); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/sdk/tape/Tape.zig b/sdk/tape/Tape.zig index be9ce34ed..360251170 100644 --- a/sdk/tape/Tape.zig +++ b/sdk/tape/Tape.zig @@ -449,13 +449,8 @@ pub fn load(gpa: std.mem.Allocator, bytes: []const u8, check: Check) !Owned { pub fn parse(gpa: std.mem.Allocator, source: [:0]const u8, check: Check) !Owned { var arena: std.heap.ArenaAllocator = .init(gpa); errdefer arena.deinit(); - const tape = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(arena.allocator()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Tape, .{ .gpa = arena.allocator(), .arena = zig017_arena.allocator(), .source = source, .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Tape, arena.allocator(), zig017_v) else |zig017_e| zig017_e; - }); + var diag: std.zon.parse.Diagnostics = undefined; + const tape = try std.zon.parse.fromSlice(Tape, .{ .gpa = gpa, .arena = arena.allocator(), .source = source, .diagnostics = &diag }); try tape.validate(check); return .{ .arena = arena, .tape = tape }; } @@ -677,40 +672,3 @@ test "a hand-written tape parses with every default left out" { try testing.expect(owned.tape.ops[2].do.wait.until == .idle); try testing.expectEqual(@as(u32, 10_000), owned.tape.ops[2].do.wait.timeout); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/src/backend/backend_native.zig b/src/backend/backend_native.zig index 21d4c74bb..612eedfc2 100644 --- a/src/backend/backend_native.zig +++ b/src/backend/backend_native.zig @@ -158,8 +158,9 @@ var layout_store_dir: []const u8 = ""; fn layoutStoreLoad(_: ?*anyopaque) ?platform.geometry.Geometry { const gpa = std.heap.page_allocator; - const f = loadWindowFile(gpa, layout_store_dir); - defer zig017ZonFree(gpa, f); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const f = loadWindowFile(gpa, arena.allocator(), layout_store_dir); if (f.w < 1 or f.h < 1) return null; return .{ .x = f.x, .y = f.y, .w = f.w, .h = f.h, .state = if (f.maximized) .maximized else .normal }; } @@ -167,8 +168,9 @@ fn layoutStoreLoad(_: ?*anyopaque) ?platform.geometry.Geometry { fn layoutStoreSave(_: ?*anyopaque, g: platform.geometry.Geometry) void { // Read-modify-write: the regions and tree on disk stay as they are. const gpa = std.heap.page_allocator; - var f = loadWindowFile(gpa, layout_store_dir); - defer zig017ZonFree(gpa, f); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var f = loadWindowFile(gpa, arena.allocator(), layout_store_dir); f.x = g.x; f.y = g.y; f.w = g.w; @@ -396,27 +398,3 @@ pub fn setDynamicNativeMenuShortcut(index: usize, key: ?[]const u8, modifier_mas pub fn setSdlAppMetadata(name: [*:0]const u8, version: [*:0]const u8, identifier: [*:0]const u8) void { _ = sdl3.SDL_SetAppMetadata(name, version, identifier); } -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/src/backend/layout_file.zig b/src/backend/layout_file.zig index 3254f0c57..3192238ae 100644 --- a/src/backend/layout_file.zig +++ b/src/backend/layout_file.zig @@ -97,9 +97,8 @@ fn windowFilePath(buf: []u8, dir: []const u8, name: []const u8) ?[:0]const u8 { /// Reads every field of `window.zon`, falling back to `SavedFrame`'s own defaults for whatever /// is missing or unparseable (never null — simplifies every caller, which only cares about the /// subset of fields it owns). -/// Reads `window.zon` into `gpa`-owned memory. Free with `zig017ZonFree(gpa, frame)` — the -/// region list holds allocated names now, so the old return-by-value-and-forget will not do. -pub fn loadWindowFile(gpa: std.mem.Allocator, dir: []const u8) SavedFrame { +/// Reads `window.zon` into `arena` (the region list holds allocated names); `gpa` is scratch. +pub fn loadWindowFile(gpa: std.mem.Allocator, arena: std.mem.Allocator, dir: []const u8) SavedFrame { var path_buf: [1024]u8 = undefined; const path = windowFilePath(&path_buf, dir, layout_file) orelse return .{}; const data = readCapped(gpa, path) catch blk: { @@ -111,14 +110,13 @@ pub fn loadWindowFile(gpa: std.mem.Allocator, dir: []const u8) SavedFrame { defer gpa.free(data); const data_z = gpa.dupeSentinel(u8, data, 0) catch return .{}; defer gpa.free(data_z); - // `fromSliceAlloc`, not `fromSlice`: the region list holds allocated names, and `fromSlice` - // asserts at comptime that the result contains no pointers. - return (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(SavedFrame, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = data_z, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(SavedFrame, gpa, zig017_v) else |zig017_e| zig017_e; + var diag: std.zon.parse.Diagnostics = undefined; + return std.zon.parse.fromSlice(SavedFrame, .{ + .gpa = gpa, + .arena = arena, + .source = data_z, + .diagnostics = &diag, + .ignore_unknown_fields = true, }) catch .{}; } @@ -140,8 +138,9 @@ pub fn writeWindowFile(dir: []const u8, f: SavedFrame) void { /// Read-modify-write: keeps whatever frame geometry is on disk, replaces the region list. pub fn saveRegions(dir: []const u8, regions: []const SavedRegion) void { const gpa = std.heap.page_allocator; - var f = loadWindowFile(gpa, dir); - defer zig017ZonFree(gpa, f); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var f = loadWindowFile(gpa, arena.allocator(), dir); const keep = f.regions; f.regions = regions; writeWindowFile(dir, f); @@ -153,8 +152,9 @@ pub fn saveRegions(dir: []const u8, regions: []const SavedRegion) void { /// this, so an existing tree on disk is left alone. pub fn saveTree(dir: []const u8, tree: ?core.widgets.DockLayout.Snapshot) void { const gpa = std.heap.page_allocator; - var f = loadWindowFile(gpa, dir); - defer zig017ZonFree(gpa, f); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var f = loadWindowFile(gpa, arena.allocator(), dir); const keep = f.tree; f.tree = tree; writeWindowFile(dir, f); @@ -164,8 +164,9 @@ pub fn saveTree(dir: []const u8, tree: ?core.widgets.DockLayout.Snapshot) void { /// The saved seed-tree, rebuilt as a live `DockLayout`, or null when the file has none. /// Caller owns the result (`DockLayout.deinit`). pub fn loadTree(gpa: std.mem.Allocator, dir: []const u8) ?core.widgets.DockLayout { - const f = loadWindowFile(gpa, dir); - defer zig017ZonFree(gpa, f); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const f = loadWindowFile(gpa, arena.allocator(), dir); const snap = f.tree orelse return null; var dock = core.widgets.DockLayout.fromSnapshot(gpa, snap) catch return null; dock.animated = true; @@ -175,8 +176,9 @@ pub fn loadTree(gpa: std.mem.Allocator, dir: []const u8) ?core.widgets.DockLayou /// Every region `layout.zon` remembers, in `gpa`-owned memory. Call once at startup; free with /// `freeRegions`. pub fn loadRegions(gpa: std.mem.Allocator, dir: []const u8) []SavedRegion { - const f = loadWindowFile(gpa, dir); - defer zig017ZonFree(gpa, f); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const f = loadWindowFile(gpa, arena.allocator(), dir); const out = gpa.alloc(SavedRegion, f.regions.len) catch return &.{}; var n: usize = 0; for (f.regions) |r| { @@ -234,64 +236,3 @@ pub fn freeRegions(gpa: std.mem.Allocator, regions: []SavedRegion) void { } gpa.free(regions); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -} diff --git a/src/editor/Editor.zig b/src/editor/Editor.zig index 9d53529e1..350fe287c 100644 --- a/src/editor/Editor.zig +++ b/src/editor/Editor.zig @@ -871,7 +871,7 @@ pub fn builtinManifest(editor: *Editor, id: []const u8) ?sdk.Manifest { if (std.mem.eql(u8, m.plugin_id, id)) { const frame_gpa = editor.app.arena.allocator(); const zon = frame_gpa.dupeSentinel(u8, m.plugin_options.manifest_zon, 0) catch return null; - return sdk.Manifest.parse(frame_gpa, zon) catch return null; + return sdk.Manifest.parse(frame_gpa, frame_gpa, zon) catch return null; } } return null; @@ -3457,11 +3457,12 @@ pub fn reconcileExternalSettingsChange(editor: *Editor) void { // plugin's settings. Left unreconciled until another external change retriggers a read // (rare in practice: the watcher's debounce already gives a normal atomic save time to // settle before this runs at all). - const parsed = Settings.parseOnly(gpa, data) catch |err| { + var parsed_arena: std.heap.ArenaAllocator = .init(gpa); + defer parsed_arena.deinit(); + const parsed = Settings.parseOnly(gpa, parsed_arena.allocator(), data) catch |err| { dvui.log.warn("settings watcher: could not parse external settings.zon change ({s}); skipping this reconciliation", .{@errorName(err)}); return; }; - defer Settings.freeParsed(gpa, parsed); // Fizzy fields, one at a time rather than `editor.app.settings = parsed` wholesale: `theme` is // runtime-owned (see its doc comment on `Settings`) and must not be clobbered by the raw diff --git a/src/editor/KeptDocuments.zig b/src/editor/KeptDocuments.zig index b4b4c7bc8..2c3196b96 100644 --- a/src/editor/KeptDocuments.zig +++ b/src/editor/KeptDocuments.zig @@ -359,13 +359,8 @@ pub fn loadSession(gpa: std.mem.Allocator, dir: []const u8) ?KeptDocuments { defer gpa.free(text); var arena: std.heap.ArenaAllocator = .init(gpa); defer arena.deinit(); - const saved = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(arena.allocator()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Saved, .{ .gpa = arena.allocator(), .arena = zig017_arena.allocator(), .source = text, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Saved, arena.allocator(), zig017_v) else |zig017_e| zig017_e; - }) catch |err| { + var diag: std.zon.parse.Diagnostics = undefined; + const saved = std.zon.parse.fromSlice(Saved, .{ .gpa = gpa, .arena = arena.allocator(), .source = text, .diagnostics = &diag, .ignore_unknown_fields = true }) catch |err| { dvui.log.warn("restart: the last session could not be read ({t}); documents open from disk", .{err}); return null; }; @@ -495,40 +490,3 @@ fn recover(editor: *Editor, path: []const u8, unsaved: []const u8) void { dvui.log.warn("reload: the unsaved contents of {s} are in {s}", .{ path, out }); dvui.toast(@src(), .{ .message = std.fmt.allocPrint(editor.app.arena.allocator(), "Unsaved changes to {s} were kept in {s}", .{ std.fs.path.basename(path), out }) catch "Unsaved changes were kept in fizzy's recovered folder." }); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/src/editor/verdict.zig b/src/editor/verdict.zig index 0e690246a..b1b697574 100644 --- a/src/editor/verdict.zig +++ b/src/editor/verdict.zig @@ -190,13 +190,10 @@ fn readExpect(gpa: std.mem.Allocator, file: []const u8) !Expect { defer gpa.free(bytes); const source = try gpa.dupeSentinel(u8, bytes, 0); defer gpa.free(source); - return (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Expect, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = source, .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Expect, gpa, zig017_v) else |zig017_e| zig017_e; - }); + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var diag: std.zon.parse.Diagnostics = undefined; + return std.zon.parse.fromSliceNoAlloc(Expect, .{ .gpa = gpa, .arena = arena.allocator(), .source = source, .diagnostics = &diag }); } /// Once a displayed frame, after the app's: watch the tape start and end. True: the tape has @@ -366,40 +363,3 @@ fn over(limit: ?u32, value: u32) bool { const max = limit orelse return false; return value > max; } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} diff --git a/tests/integration.zig b/tests/integration.zig index 16872511f..d428ebe69 100644 --- a/tests/integration.zig +++ b/tests/integration.zig @@ -5162,13 +5162,10 @@ test "verdict: the soak tape is a demo, and its expectations read" { // It ends on a wait, so what closed last has time to close before the windows are counted. try std.testing.expect(owned.tape.ops[owned.tape.ops.len - 1].do == .wait); - const expect = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(std.testing.allocator); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(fizzy.verdict.Expect, .{ .gpa = std.testing.allocator, .arena = zig017_arena.allocator(), .source = @embedFile("soak_expect"), .diagnostics = &zig017_zd }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(fizzy.verdict.Expect, std.testing.allocator, zig017_v) else |zig017_e| zig017_e; - }); + var expect_arena: std.heap.ArenaAllocator = .init(std.testing.allocator); + defer expect_arena.deinit(); + var expect_diag: std.zon.parse.Diagnostics = undefined; + const expect = try std.zon.parse.fromSliceNoAlloc(fizzy.verdict.Expect, .{ .gpa = std.testing.allocator, .arena = expect_arena.allocator(), .source = @embedFile("soak_expect"), .diagnostics = &expect_diag }); try std.testing.expect(!expect.allow_leaks); try std.testing.expectEqual(@as(u32, 0), expect.max_sdl_errors); try std.testing.expectEqual(@as(?u32, null), expect.os_windows); @@ -5338,14 +5335,10 @@ test "float: the saved layout brings it back, and Reset Layout takes it away" { gpa.free(regions); const text = try gpa.dupeSentinel(u8, out.written(), 0); defer gpa.free(text); - const saved = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice([]fizzy.backend.SavedRegion, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = text, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe([]fizzy.backend.SavedRegion, gpa, zig017_v) else |zig017_e| zig017_e; - }); - defer zig017ZonFree(gpa, saved); + var saved_arena: std.heap.ArenaAllocator = .init(gpa); + defer saved_arena.deinit(); + var saved_diag: std.zon.parse.Diagnostics = undefined; + const saved = try std.zon.parse.fromSlice([]fizzy.backend.SavedRegion, .{ .gpa = gpa, .arena = saved_arena.allocator(), .source = text, .diagnostics = &saved_diag, .ignore_unknown_fields = true }); editor.app.layout.resetLayout(gpa); try dvui.testing.settle(ManyPanelFrame.frame); @@ -6672,25 +6665,17 @@ const HeardEvents = struct { defer gpa.free(src); // A batch of disk changes is heard by its first path, everything else by its `.path`. const path = if (std.mem.eql(u8, e.name, "fizzy.files.changed")) files: { - const changed = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(sdk.events.FilesChanged, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = src, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(sdk.events.FilesChanged, gpa, zig017_v) else |zig017_e| zig017_e; - }) catch return; - defer zig017ZonFree(gpa, changed); + var changed_arena: std.heap.ArenaAllocator = .init(gpa); + defer changed_arena.deinit(); + var changed_diag: std.zon.parse.Diagnostics = undefined; + const changed = std.zon.parse.fromSlice(sdk.events.FilesChanged, .{ .gpa = gpa, .arena = changed_arena.allocator(), .source = src, .diagnostics = &changed_diag, .ignore_unknown_fields = true }) catch return; if (changed.events.len == 0) return; break :files gpa.dupe(u8, changed.events[0].path) catch return; } else plain: { - const payload = (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(gpa); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(sdk.events.Path, .{ .gpa = gpa, .arena = zig017_arena.allocator(), .source = src, .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(sdk.events.Path, gpa, zig017_v) else |zig017_e| zig017_e; - }) catch return; - defer zig017ZonFree(gpa, payload); + var payload_arena: std.heap.ArenaAllocator = .init(gpa); + defer payload_arena.deinit(); + var payload_diag: std.zon.parse.Diagnostics = undefined; + const payload = std.zon.parse.fromSlice(sdk.events.Path, .{ .gpa = gpa, .arena = payload_arena.allocator(), .source = src, .diagnostics = &payload_diag, .ignore_unknown_fields = true }) catch return; break :plain gpa.dupe(u8, payload.path) catch return; }; self.events.append(gpa, .{ .name = gpa.dupe(u8, e.name) catch return, .path = path }) catch gpa.free(path); @@ -6993,13 +6978,8 @@ test "headless: the whole editor comes up, opens a file, plays the tour and goes .ok => |r| r orelse return error.TestUnexpectedResult, else => return error.TestUnexpectedResult, }; - return (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(h.arena()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Read, .{ .gpa = h.arena(), .arena = zig017_arena.allocator(), .source = try h.arena().dupeSentinel(u8, zon, 0), .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Read, h.arena(), zig017_v) else |zig017_e| zig017_e; - }); + var diag: std.zon.parse.Diagnostics = undefined; + return std.zon.parse.fromSlice(Read, .{ .gpa = h.arena(), .arena = h.arena(), .source = try h.arena().dupeSentinel(u8, zon, 0), .diagnostics = &diag, .ignore_unknown_fields = true }); } }.read; @@ -7037,13 +7017,8 @@ test "headless: the whole editor comes up, opens a file, plays the tour and goes try std.testing.expectEqualStrings(notes, front.owner.documentPath(front)); const Caret = struct { caret: struct { line: u32, column: u32 } }; const out = host.callCommand("text.read", notes_args, host.arena()).ok.?; - const at = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(host.arena()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Caret, .{ .gpa = host.arena(), .arena = zig017_arena.allocator(), .source = try host.arena().dupeSentinel(u8, out, 0), .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Caret, host.arena(), zig017_v) else |zig017_e| zig017_e; - }); + var at_diag: std.zon.parse.Diagnostics = undefined; + const at = try std.zon.parse.fromSlice(Caret, .{ .gpa = host.arena(), .arena = host.arena(), .source = try host.arena().dupeSentinel(u8, out, 0), .diagnostics = &at_diag, .ignore_unknown_fields = true }); try std.testing.expectEqual(@as(u32, 3), at.caret.line); try std.testing.expectEqual(@as(u32, 4), at.caret.column); } @@ -7271,13 +7246,8 @@ test "headless: the whole editor comes up, opens a file, plays the tour and goes // has passed on screen, which a few test frames are not. profile: struct { frame: struct { fps: f64 } }, }; - const stats = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(host.arena()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Stats, .{ .gpa = host.arena(), .arena = zig017_arena.allocator(), .source = try host.arena().dupeSentinel(u8, zon, 0), .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Stats, host.arena(), zig017_v) else |zig017_e| zig017_e; - }); + var stats_diag: std.zon.parse.Diagnostics = undefined; + const stats = try std.zon.parse.fromSlice(Stats, .{ .gpa = host.arena(), .arena = host.arena(), .source = try host.arena().dupeSentinel(u8, zon, 0), .diagnostics = &stats_diag, .ignore_unknown_fields = true }); try std.testing.expect(for (stats.plugins) |pl| { if (std.mem.eql(u8, pl.id, "devtools")) break pl.link == .bundled; } else false); @@ -7297,13 +7267,8 @@ test "headless: the whole editor comes up, opens a file, plays the tour and goes else => return error.TestUnexpectedResult, }; const Written = struct { path: []const u8, frames: u64 }; - const written = try (zig017_zon: { - var zig017_zd: std.zon.parse.Diagnostics = undefined; - var zig017_arena: std.heap.ArenaAllocator = .init(host.arena()); - defer zig017_arena.deinit(); - const zig017_r = std.zon.parse.fromSlice(Written, .{ .gpa = host.arena(), .arena = zig017_arena.allocator(), .source = try host.arena().dupeSentinel(u8, zon, 0), .diagnostics = &zig017_zd, .ignore_unknown_fields = true }); - break :zig017_zon if (zig017_r) |zig017_v| zig017ZonDupe(Written, host.arena(), zig017_v) else |zig017_e| zig017_e; - }); + var written_diag: std.zon.parse.Diagnostics = undefined; + const written = try std.zon.parse.fromSlice(Written, .{ .gpa = host.arena(), .arena = host.arena(), .source = try host.arena().dupeSentinel(u8, zon, 0), .diagnostics = &written_diag, .ignore_unknown_fields = true }); try std.testing.expect(written.frames > 0); const input_path = try std.fs.path.join(host.arena(), &.{ written.path, "input.bin" }); const bytes = try std.Io.Dir.cwd().readFileAlloc(dvui.io, input_path, host.arena(), .unlimited); @@ -7923,64 +7888,3 @@ test "a live tape drags a floating window by its header" { std.debug.print("float x {d:.1} (from 300) after {d} frames\n", .{ live_float.x, frames }); try std.testing.expectApproxEqAbs(@as(f32, 150), live_float.x, 2); } - -// ZIG017 stand-in: a deep copy of a zon result out of the parse's arena into the caller's -// allocator, where the code before 0.17 expects to free it. Goes with the zon arena PR. -fn zig017ZonDupe(comptime T: type, gpa: std.mem.Allocator, value: T) error{OutOfMemory}!T { - switch (@typeInfo(T)) { - .pointer => |p| switch (p.size) { - .one => { - const out = try gpa.create(p.child); - out.* = try zig017ZonDupe(p.child, gpa, value.*); - return out; - }, - .slice => { - const out = if (comptime p.sentinel()) |s| try gpa.allocSentinel(p.child, value.len, s) else try gpa.alloc(p.child, value.len); - for (out, value) |*o, v| o.* = try zig017ZonDupe(p.child, gpa, v); - return out; - }, - else => comptime unreachable, - }, - .array => |a| { - var out: T = undefined; - for (&out, value) |*o, v| o.* = try zig017ZonDupe(a.child, gpa, v); - return out; - }, - .@"struct" => |s| { - var out: T = value; - inline for (s.field_names, s.field_types, s.field_attrs) |n, FT, attrs| { - if (!attrs.@"comptime") @field(out, n) = try zig017ZonDupe(FT, gpa, @field(value, n)); - } - return out; - }, - .@"union" => |u| if (u.tag_type == null) return value else switch (value) { - inline else => |payload, tag| return @unionInit(T, @tagName(tag), try zig017ZonDupe(@TypeOf(payload), gpa, payload)), - }, - .optional => |o| return if (value) |v| try zig017ZonDupe(o.child, gpa, v) else null, - else => return value, - } -} -// ZIG017 stand-in: 0.16's `std.zon.parse.free`, which 0.17 removed (results now come from an -// arena the caller owns). Goes with the zon arena PR. -fn zig017ZonFree(gpa: std.mem.Allocator, value: anytype) void { - switch (@typeInfo(@TypeOf(value))) { - .pointer => |p| switch (p.size) { - .one => { - zig017ZonFree(gpa, value.*); - gpa.destroy(value); - }, - .slice => { - for (value) |item| zig017ZonFree(gpa, item); - gpa.free(value); - }, - else => comptime unreachable, - }, - .array => for (value) |item| zig017ZonFree(gpa, item), - .@"struct" => |s| inline for (s.field_names) |n| zig017ZonFree(gpa, @field(value, n)), - .@"union" => |u| if (u.tag_type != null) switch (value) { - inline else => |payload| zig017ZonFree(gpa, payload), - }, - .optional => if (value) |some| zig017ZonFree(gpa, some), - else => {}, - } -}