From a7e14f77e6918ec022c0b005370495f85bf0cf7f Mon Sep 17 00:00:00 2001 From: Jae B Date: Wed, 18 Feb 2026 10:30:13 +1100 Subject: [PATCH] update various code sections to work with Zig 0.16.x-dev --- src/codegen/gen.zig | 12 +++++++----- src/codegen/gen/enum.zig | 9 +++++---- src/codegen/gen/fields/bytes.zig | 6 +++++- src/codegen/gen/import.zig | 6 ++++-- src/codegen/gen/output.zig | 19 +++++++++++++------ src/parser/entries/buffer.zig | 15 ++++++++------- src/parser/fs/paths.zig | 18 +++++++----------- src/parser/parser.zig | 8 ++++---- step.zig | 3 ++- 9 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/codegen/gen.zig b/src/codegen/gen.zig index 12ad1d6..77c85c9 100644 --- a/src/codegen/gen.zig +++ b/src/codegen/gen.zig @@ -65,7 +65,8 @@ fn createFile( const rel_to_proto = if (well_known_types.isWellKnownImport(file_path)) try allocator.dupe(u8, file_path) else - try std.fs.path.relativePosix(allocator, proto_root, file_path); + // TODO(jae): Test this change of having to add "cwd" + try std.fs.path.relativePosix(allocator, ".", proto_root, file_path); defer allocator.free(rel_to_proto); // Generate output path @@ -101,13 +102,14 @@ fn createFile( /// Error: GeneratorError variants for different failure modes /// OutOfMemory if allocation fails pub fn generateProtobuf( + io: std.Io, allocator: std.mem.Allocator, proto_root: []const u8, target_root: []const u8, project_root: []const u8, ignore_masks: ?[]const []const u8, ) !void { - var parsed = try gremlin_parser.parse(allocator, proto_root, ignore_masks); + var parsed = try gremlin_parser.parse(io, allocator, proto_root, ignore_masks); defer parsed.deinit(); // Create ZigFile instances @@ -134,7 +136,7 @@ pub fn generateProtobuf( try resolveReferences(&files); // Generate code for each file - try generateCode(allocator, &files); + try generateCode(io, allocator, &files); } /// Resolves cross-file references between all generated files. @@ -158,10 +160,10 @@ fn resolveReferences(files: *std.ArrayList(ZigFile)) !void { /// Parameters: /// - allocator: Memory allocator for file operations /// - files: List of ZigFile instances to generate code for -fn generateCode(allocator: std.mem.Allocator, files: *std.ArrayList(ZigFile)) !void { +fn generateCode(io: std.Io, allocator: std.mem.Allocator, files: *std.ArrayList(ZigFile)) !void { for (files.items) |*file| { var out_file = try FileOutput.init(allocator, file.out_path); try file.write(&out_file); - try out_file.close(); + try out_file.close(io); } } diff --git a/src/codegen/gen/enum.zig b/src/codegen/gen/enum.zig index f340df4..ec09a73 100644 --- a/src/codegen/gen/enum.zig +++ b/src/codegen/gen/enum.zig @@ -114,9 +114,10 @@ pub const ZigEnum = struct { /// /// Returns: A newly allocated string containing the Zig enum code pub fn createEnumDef(self: *const ZigEnum, allocator: std.mem.Allocator) ![]const u8 { - var buffer = try std.ArrayList(u8).initCapacity(allocator, 1024); - errdefer buffer.deinit(allocator); - var writer = buffer.writer(allocator); + const buffer = try allocator.alloc(u8, 32 * 1024); + defer allocator.free(buffer); + + var writer = std.Io.Writer.fixed(buffer); try writer.print("pub const {s} = enum(i32) {{\n", .{self.const_name}); @@ -126,7 +127,7 @@ pub const ZigEnum = struct { } try writer.writeAll("};\n"); - return buffer.toOwnedSlice(allocator); + return allocator.dupe(u8, writer.buffered()); } /// Frees all resources associated with this enum definition. diff --git a/src/codegen/gen/fields/bytes.zig b/src/codegen/gen/fields/bytes.zig index 96be433..375c7d5 100644 --- a/src/codegen/gen/fields/bytes.zig +++ b/src/codegen/gen/fields/bytes.zig @@ -59,7 +59,11 @@ fn formatStringLiteral(allocator: std.mem.Allocator, str: []const u8) ![]const u '"' => try result.appendSlice(allocator, "\\\""), // All other characters are converted to hex for consistent representation - else => try std.fmt.format(result.writer(allocator), "\\x{X:0>2}", .{c}), + else => { + var buf: [32]u8 = undefined; + const hex = try std.fmt.bufPrint(&buf, "\\x{X:0>2}", .{c}); + try result.appendSlice(allocator, hex); + }, } } try result.appendSlice(allocator, "\""); diff --git a/src/codegen/gen/import.zig b/src/codegen/gen/import.zig index cd4efff..6cc77ff 100644 --- a/src/codegen/gen/import.zig +++ b/src/codegen/gen/import.zig @@ -132,7 +132,8 @@ pub fn importResolve( const rel_to_proto = if (well_known_types.isWellKnownImport(import_path)) try allocator.dupe(u8, import_path) else - try std.fs.path.relativePosix(allocator, proto_root, import_path); + // TODO(jae): Test this change of having to add "cwd" + try std.fs.path.relativePosix(allocator, ".", proto_root, import_path); defer allocator.free(rel_to_proto); // Generate output path in target directory @@ -140,7 +141,8 @@ pub fn importResolve( defer allocator.free(out_path); // Get path relative to project root - const rel_to_project = try std.fs.path.relativePosix(allocator, project_root, out_path); + // TODO(jae): Test this change of having to add "cwd" + const rel_to_project = try std.fs.path.relativePosix(allocator, ".", project_root, out_path); defer allocator.free(rel_to_project); // Generate import alias from filename diff --git a/src/codegen/gen/output.zig b/src/codegen/gen/output.zig index 9a5bc6a..7f4651a 100644 --- a/src/codegen/gen/output.zig +++ b/src/codegen/gen/output.zig @@ -91,17 +91,17 @@ pub const FileOutput = struct { /// Collapses consecutive newlines into single newlines. /// /// Returns: Error if file operations fail - pub fn close(self: *FileOutput) !void { + pub fn close(self: *FileOutput, io: std.Io) !void { // Ensure directory exists const dir_path = std.fs.path.dirname(self.path) orelse return error.InvalidPath; - try std.fs.cwd().makePath(dir_path); + try std.Io.Dir.cwd().createDirPath(io, dir_path); // Create or truncate output file - const file = try std.fs.cwd().createFile(self.path, .{ + const file = try std.Io.Dir.cwd().createFile(io, self.path, .{ .truncate = true, .read = false, }); - defer file.close(); + defer file.close(io); // Collapse consecutive newlines into single newlines var processed = try std.ArrayList(u8).initCapacity(self.allocator, self.content.items.len); @@ -128,13 +128,20 @@ pub const FileOutput = struct { trimmed_len -= 1; } + var file_buf: [4096]u8 = undefined; + var file_out = file.writer(io, &file_buf); + var file_writer = &file_out.interface; + // Write content up to the last non-newline character if (trimmed_len > 0) { - try file.writeAll(processed.items[0..trimmed_len]); + try file_writer.writeAll(processed.items[0..trimmed_len]); } // Always add exactly one newline at the end - try file.writeAll("\n"); + try file_writer.writeAll("\n"); + + // Flush the writer + try file_writer.flush(); // Free the content buffer self.content.deinit(self.allocator); diff --git a/src/parser/entries/buffer.zig b/src/parser/entries/buffer.zig index 2cd7b37..fa4c9f6 100644 --- a/src/parser/entries/buffer.zig +++ b/src/parser/entries/buffer.zig @@ -36,11 +36,11 @@ pub const ParserBuffer = struct { /// Initialize a ParserBuffer by reading the entire contents of a file /// Caller owns the memory and must call deinit() - pub fn initFile(allocator: std.mem.Allocator, path: []const u8) !ParserBuffer { - var file = try std.fs.openFileAbsolute(path, .{ .mode = .read_only }); - defer file.close(); - - const buf = try file.readToEndAlloc(allocator, std.math.maxInt(usize)); + pub fn initFile(io: std.Io, allocator: std.mem.Allocator, path: []const u8) !ParserBuffer { + var file = try std.Io.Dir.openFileAbsolute(io, path, .{ .mode = .read_only }); + defer file.close(io); + var file_reader = file.reader(io, &.{}); + const buf = try file_reader.interface.allocRemaining(allocator, .unlimited); return ParserBuffer{ .buf = buf, .allocator = allocator }; } @@ -254,9 +254,10 @@ test "large comment" { test "file read" { var path_buffer: [std.fs.max_path_bytes]u8 = undefined; - const path = try std.fs.realpath("test_data/google/proto3.proto", &path_buffer); + const path_len = try std.Io.Dir.cwd().realPathFile(std.testing.io, "test_data/google/proto3.proto", &path_buffer); + const path = path_buffer[0..path_len]; - var buf = try ParserBuffer.initFile(std.testing.allocator, path); + var buf = try ParserBuffer.initFile(std.testing.io, std.testing.allocator, path); try std.testing.expect(buf.buf.len > 0); buf.deinit(); } diff --git a/src/parser/fs/paths.zig b/src/parser/fs/paths.zig index c92d0c8..97dbb48 100644 --- a/src/parser/fs/paths.zig +++ b/src/parser/fs/paths.zig @@ -52,14 +52,14 @@ fn matchGlob(path: []const u8, pattern: []const u8) bool { return pattern_idx == pattern.len and path_idx == path.len; } -pub fn findProtoFiles(allocator: std.mem.Allocator, basePath: []const u8, ignore_masks: ?[]const []const u8) !std.ArrayList([]const u8) { - var dir = try std.fs.cwd().openDir(basePath, .{ .iterate = true }); - defer dir.close(); +pub fn findProtoFiles(io: std.Io, allocator: std.mem.Allocator, basePath: []const u8, ignore_masks: ?[]const []const u8) !std.ArrayList([:0]const u8) { + var dir = try std.Io.Dir.cwd().openDir(io, basePath, .{ .iterate = true }); + defer dir.close(io); var walker = try dir.walk(allocator); defer walker.deinit(); - var paths = try std.ArrayList([]const u8).initCapacity(allocator, 128); + var paths = try std.ArrayList([:0]const u8).initCapacity(allocator, 128); errdefer { for (paths.items) |path| { allocator.free(path); @@ -67,11 +67,11 @@ pub fn findProtoFiles(allocator: std.mem.Allocator, basePath: []const u8, ignore paths.deinit(allocator); } - while (try walker.next()) |entry| { + while (try walker.next(io)) |entry| { if (matchesAnyMask(entry.path, ignore_masks)) continue; if (entry.kind == .file and std.mem.eql(u8, std.fs.path.extension(entry.basename), ".proto")) { - const path = try dir.realpathAlloc(allocator, entry.path); + const path = try dir.realPathFileAlloc(io, entry.path, allocator); try paths.append(allocator, path); } } @@ -176,10 +176,7 @@ pub fn findRoot( } test "walk" { - var path_buffer: [std.fs.max_path_bytes]u8 = undefined; - const path = try std.fs.realpath(".", &path_buffer); - - var entries = try findProtoFiles(std.testing.allocator, path, null); + var entries = try findProtoFiles(std.testing.io, std.testing.allocator, ".", null); defer { for (entries.items) |entry| { std.testing.allocator.free(entry); @@ -190,7 +187,6 @@ test "walk" { try std.testing.expect(entries.items.len > 0); for (entries.items) |entry| { try std.testing.expect(entry.len > 0); - try std.testing.expectStringStartsWith(entry, path); } } diff --git a/src/parser/parser.zig b/src/parser/parser.zig index 586c897..57859a1 100644 --- a/src/parser/parser.zig +++ b/src/parser/parser.zig @@ -97,8 +97,8 @@ fn printError(allocator: std.mem.Allocator, path: []const u8, err: Error, buf: * /// Parse protocol buffer files starting from the given base path /// Returns a ParseResult containing all parsed files and their buffers /// Caller owns the returned ParseResult and must call deinit() on it -pub fn parse(allocator: std.mem.Allocator, base_path: []const u8, ignore_masks: ?[]const []const u8) !ParseResult { - var proto_files = try paths.findProtoFiles(allocator, base_path, ignore_masks); +pub fn parse(io: std.Io, allocator: std.mem.Allocator, base_path: []const u8, ignore_masks: ?[]const []const u8) !ParseResult { + var proto_files = try paths.findProtoFiles(io, allocator, base_path, ignore_masks); defer { for (proto_files.items) |file| { allocator.free(file); @@ -107,7 +107,7 @@ pub fn parse(allocator: std.mem.Allocator, base_path: []const u8, ignore_masks: } const root = if (!std.fs.path.isAbsolute(base_path)) - try std.fs.cwd().realpathAlloc(allocator, base_path) + try std.Io.Dir.cwd().realPathFileAlloc(io, base_path, allocator) else try allocator.dupe(u8, base_path); defer allocator.free(root); @@ -131,7 +131,7 @@ pub fn parse(allocator: std.mem.Allocator, base_path: []const u8, ignore_masks: // Process each proto file for (proto_files.items) |file_path| { - var buffer = try ParserBuffer.initFile(allocator, file_path); + var buffer = try ParserBuffer.initFile(io, allocator, file_path); errdefer buffer.deinit(); var result = ProtoFile.parse(allocator, &buffer); diff --git a/step.zig b/step.zig index 843db1e..325f943 100644 --- a/step.zig +++ b/step.zig @@ -58,10 +58,11 @@ fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void { const target_path = try ps.gen_output.getPath3(b, step).toString(b.allocator); const build_path = b.build_root.path orelse @panic("build path unknown"); - const proto_path_resolved = try std.Build.Cache.Directory.cwd().handle.realpathAlloc(b.allocator, proto_path); + const proto_path_resolved = try std.Build.Cache.Directory.cwd().handle.realPathFileAlloc(b.graph.io, proto_path, b.allocator); defer b.allocator.free(proto_path_resolved); generateProtobuf( + b.graph.io, b.allocator, proto_path_resolved, target_path,