From edf34754c6c96935904696752ba115712cfecd27 Mon Sep 17 00:00:00 2001 From: anshalshukla Date: Fri, 24 Apr 2026 22:30:39 +0530 Subject: [PATCH 1/2] upgrade to zig 0.16.0 --- build.zig.zon | 2 +- src/codegen/gen.zig | 11 ++++++----- src/codegen/gen/enum.zig | 8 ++++---- src/codegen/gen/fields/bytes.zig | 6 +++++- src/codegen/gen/import.zig | 6 +++--- src/codegen/gen/output.zig | 13 ++++++------- src/parser/entries/buffer.zig | 14 ++++++-------- src/parser/fs/paths.zig | 19 +++++++++++-------- src/parser/parser.zig | 8 ++++---- step.zig | 4 +++- 10 files changed, 49 insertions(+), 42 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 4fbed1e..4e7f144 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,7 +2,7 @@ .name = .gremlin, .version = "0.1.0", .fingerprint = 0x52f178c9d53d6b13, - .minimum_zig_version = "0.15.2", + .minimum_zig_version = "0.16.0", .paths = .{""}, } diff --git a/src/codegen/gen.zig b/src/codegen/gen.zig index 88a24da..8e9e517 100644 --- a/src/codegen/gen.zig +++ b/src/codegen/gen.zig @@ -63,7 +63,7 @@ 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); + try std.fs.path.relativePosix(allocator, "/", proto_root, file_path); defer allocator.free(rel_to_proto); // Generate output path @@ -99,11 +99,12 @@ fn createFile( /// OutOfMemory if allocation fails pub fn generateProtobuf( allocator: std.mem.Allocator, + io: std.Io, proto_root: []const u8, target_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(allocator, io, proto_root, ignore_masks); defer parsed.deinit(); // Create ZigFile instances @@ -129,7 +130,7 @@ pub fn generateProtobuf( try resolveReferences(&files); // Generate code for each file - try generateCode(allocator, &files); + try generateCode(allocator, io, &files); } /// Resolves cross-file references between all generated files. @@ -153,10 +154,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(allocator: std.mem.Allocator, io: std.Io, 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..669b4a2 100644 --- a/src/codegen/gen/enum.zig +++ b/src/codegen/gen/enum.zig @@ -114,9 +114,9 @@ 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); + var aw = try std.Io.Writer.Allocating.initCapacity(allocator, 1024); + errdefer aw.deinit(); + const writer = &aw.writer; try writer.print("pub const {s} = enum(i32) {{\n", .{self.const_name}); @@ -126,7 +126,7 @@ pub const ZigEnum = struct { } try writer.writeAll("};\n"); - return buffer.toOwnedSlice(allocator); + return aw.toOwnedSlice(); } /// 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..0a2b6e9 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 => { + const hex = try std.fmt.allocPrint(allocator, "\\x{X:0>2}", .{c}); + defer allocator.free(hex); + try result.appendSlice(allocator, hex); + }, } } try result.appendSlice(allocator, "\""); diff --git a/src/codegen/gen/import.zig b/src/codegen/gen/import.zig index d751ca8..290b0ea 100644 --- a/src/codegen/gen/import.zig +++ b/src/codegen/gen/import.zig @@ -132,7 +132,7 @@ pub fn importResolve( const imported_file_rel_path_from_proto_root = if (well_known_types.isWellKnownImport(import_path_in_proto_file)) try allocator.dupe(u8, import_path_in_proto_file) else - try std.fs.path.relativePosix(allocator, proto_root, import_path_in_proto_file); + try std.fs.path.relativePosix(allocator, "/", proto_root, import_path_in_proto_file); defer allocator.free(imported_file_rel_path_from_proto_root); // Generate output path for the imported file @@ -154,7 +154,7 @@ pub fn importResolve( } else { // Different directory - compute path relative to the importing file's output location // First, get the output path for the current file (the one doing the importing) - const current_file_rel_to_proto_root = try std.fs.path.relativePosix(allocator, proto_root, proto_file_path); + const current_file_rel_to_proto_root = try std.fs.path.relativePosix(allocator, "/", proto_root, proto_file_path); defer allocator.free(current_file_rel_to_proto_root); const current_file_out_path = try paths.outputPath(allocator, current_file_rel_to_proto_root, target_root); @@ -164,7 +164,7 @@ pub fn importResolve( const current_out_dir = std.fs.path.dirname(current_file_out_path) orelse "."; // Compute relative path from current file's directory to imported file - const rel_import_path = try std.fs.path.relativePosix(allocator, current_out_dir, out_path); + const rel_import_path = try std.fs.path.relativePosix(allocator, "/", current_out_dir, out_path); defer allocator.free(rel_import_path); return try ZigImport.init(allocator, src, name, rel_import_path); diff --git a/src/codegen/gen/output.zig b/src/codegen/gen/output.zig index 9a5bc6a..5ce6af2 100644 --- a/src/codegen/gen/output.zig +++ b/src/codegen/gen/output.zig @@ -91,17 +91,16 @@ 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, .{ + var 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); @@ -130,11 +129,11 @@ pub const FileOutput = struct { // Write content up to the last non-newline character if (trimmed_len > 0) { - try file.writeAll(processed.items[0..trimmed_len]); + try file.writeStreamingAll(io,processed.items[0..trimmed_len]); } // Always add exactly one newline at the end - try file.writeAll("\n"); + try file.writeStreamingAll(io,"\n"); // 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..0458dc0 100644 --- a/src/parser/entries/buffer.zig +++ b/src/parser/entries/buffer.zig @@ -36,11 +36,8 @@ 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(allocator: std.mem.Allocator, io: std.Io, path: []const u8) !ParserBuffer { + const buf = try std.Io.Dir.cwd().readFileAlloc(io, path, allocator, .unlimited); return ParserBuffer{ .buf = buf, .allocator = allocator }; } @@ -253,10 +250,11 @@ 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); + var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined; + const n = try std.Io.Dir.cwd().realPathFile(std.testing.io, "test_data/google/proto3.proto", &path_buffer); + const path = path_buffer[0..n]; - var buf = try ParserBuffer.initFile(std.testing.allocator, path); + var buf = try ParserBuffer.initFile(std.testing.allocator, std.testing.io, 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..f3a9714 100644 --- a/src/parser/fs/paths.zig +++ b/src/parser/fs/paths.zig @@ -52,9 +52,9 @@ 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(allocator: std.mem.Allocator, io: std.Io, basePath: []const u8, ignore_masks: ?[]const []const u8) !std.ArrayList([]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(); @@ -67,11 +67,13 @@ 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_z = try dir.realPathFileAlloc(io, entry.path, allocator); + defer allocator.free(path_z); + const path = try allocator.dupe(u8, path_z); try paths.append(allocator, path); } } @@ -176,10 +178,11 @@ pub fn findRoot( } test "walk" { - var path_buffer: [std.fs.max_path_bytes]u8 = undefined; - const path = try std.fs.realpath(".", &path_buffer); + var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined; + const n = try std.Io.Dir.cwd().realPathFile(std.testing.io, ".", &path_buffer); + const path = path_buffer[0..n]; - var entries = try findProtoFiles(std.testing.allocator, path, null); + var entries = try findProtoFiles(std.testing.allocator, std.testing.io, path, null); defer { for (entries.items) |entry| { std.testing.allocator.free(entry); diff --git a/src/parser/parser.zig b/src/parser/parser.zig index 586c897..6c46970 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(allocator: std.mem.Allocator, io: std.Io, base_path: []const u8, ignore_masks: ?[]const []const u8) !ParseResult { + var proto_files = try paths.findProtoFiles(allocator, io, 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(allocator, io, file_path); errdefer buffer.deinit(); var result = ProtoFile.parse(allocator, &buffer); diff --git a/step.zig b/step.zig index fa38586..bbbeef9 100644 --- a/step.zig +++ b/step.zig @@ -57,11 +57,13 @@ fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void { const proto_path = try ps.proto_sources.getPath3(b, step).toString(b.allocator); const target_path = try ps.gen_output.getPath3(b, step).toString(b.allocator); - const proto_path_resolved = try std.Build.Cache.Directory.cwd().handle.realpathAlloc(b.allocator, proto_path); + const io = b.graph.io; + const proto_path_resolved = try std.Io.Dir.cwd().realPathFileAlloc(io, proto_path, b.allocator); defer b.allocator.free(proto_path_resolved); generateProtobuf( b.allocator, + io, proto_path_resolved, target_path, ps.ignore_masks, From eabc190c74d269b7a6baaa26614155807627f9b1 Mon Sep 17 00:00:00 2001 From: anshalshukla Date: Mon, 27 Apr 2026 14:50:00 +0530 Subject: [PATCH 2/2] zig fmt --- integration-test/benchmark.zig | 136 ++++++++++++++++----------------- src/codegen/gen/output.zig | 4 +- src/gremlin/types.zig | 7 +- src/parser/entries/service.zig | 2 +- 4 files changed, 75 insertions(+), 74 deletions(-) diff --git a/integration-test/benchmark.zig b/integration-test/benchmark.zig index 88c97c7..ae583b4 100644 --- a/integration-test/benchmark.zig +++ b/integration-test/benchmark.zig @@ -128,48 +128,48 @@ fn updateGoldenMessage(msg: *unittest.TestAllTypes, repeated_storage: []?unittes fn createDeepNested() benchmark.DeepNested { const items_level1 = [_]?benchmark.Level1{ benchmark.Level1{ - .id = 11, - .title = "item1_top_level", - .score = 2.34, - .nested = benchmark.Level2{ - .id = 110, - .description = "nested_in_top_item1", - .payload = "some payload data", - .nested = benchmark.Level3{ - .id = 1100, - .name = "deeply_nested_top_item1", + .id = 11, + .title = "item1_top_level", + .score = 2.34, + .nested = benchmark.Level2{ + .id = 110, + .description = "nested_in_top_item1", + .payload = "some payload data", + .nested = benchmark.Level3{ + .id = 1100, + .name = "deeply_nested_top_item1", + }, }, }, - }, benchmark.Level1{ - .id = 12, - .title = "item2_top_level", - .score = 3.45, - .nested = benchmark.Level2{ - .id = 120, - .description = "nested_in_top_item2", - .payload = "more payload data here", - }, + .id = 12, + .title = "item2_top_level", + .score = 3.45, + .nested = benchmark.Level2{ + .id = 120, + .description = "nested_in_top_item2", + .payload = "more payload data here", + }, }, benchmark.Level1{ - .id = 13, - .title = "item3_top_level", - .score = 4.56, + .id = 13, + .title = "item3_top_level", + .score = 4.56, }, benchmark.Level1{ - .id = 14, - .title = "item4_top_level", - .score = 5.67, - .nested = benchmark.Level2{ - .id = 140, - .description = "nested_in_top_item4", - .payload = "final payload data", - }, + .id = 14, + .title = "item4_top_level", + .score = 5.67, + .nested = benchmark.Level2{ + .id = 140, + .description = "nested_in_top_item4", + .payload = "final payload data", + }, }, benchmark.Level1{ - .id = 15, - .title = "item5_top_level", - .score = 6.78, + .id = 15, + .title = "item5_top_level", + .score = 6.78, }, }; @@ -193,23 +193,23 @@ fn createDeepNested() benchmark.DeepNested { const items_level3 = [_]?benchmark.Level3{ benchmark.Level3{ - .id = 31, - .name = "item1_nested", - .nested = benchmark.Level4{ - .value = 310, - .data = "nested_item1_data", - .numbers = &[_]i32{ 1, 2, 3, 4, 5 }, - }, + .id = 31, + .name = "item1_nested", + .nested = benchmark.Level4{ + .value = 310, + .data = "nested_item1_data", + .numbers = &[_]i32{ 1, 2, 3, 4, 5 }, + }, .items = &sub_items1, }, benchmark.Level3{ - .id = 32, - .name = "item2_nested", - .nested = benchmark.Level4{ - .value = 320, - .data = "nested_item2_data", - .numbers = &[_]i32{ 6, 7, 8, 9, 10 }, - }, + .id = 32, + .name = "item2_nested", + .nested = benchmark.Level4{ + .value = 320, + .data = "nested_item2_data", + .numbers = &[_]i32{ 6, 7, 8, 9, 10 }, + }, .items = &sub_items2, }, benchmark.Level3{ @@ -234,32 +234,32 @@ fn createDeepNested() benchmark.DeepNested { const items_level2 = [_]?benchmark.Level2{ benchmark.Level2{ - .id = 21, - .description = "item1_level2_with_payload", - .payload = "payload for item 1", - .nested = benchmark.Level3{ - .id = 210, - .name = "nested_in_item1", - .nested = benchmark.Level4{ - .value = 2100, - .data = "deep_nested", - .numbers = &[_]i32{ 100, 200, 300 }, + .id = 21, + .description = "item1_level2_with_payload", + .payload = "payload for item 1", + .nested = benchmark.Level3{ + .id = 210, + .name = "nested_in_item1", + .nested = benchmark.Level4{ + .value = 2100, + .data = "deep_nested", + .numbers = &[_]i32{ 100, 200, 300 }, + }, }, }, - }, benchmark.Level2{ - .id = 22, - .description = "item2_level2_with_payload", - .payload = "payload for item 2 with more data", - .nested = benchmark.Level3{ - .id = 220, - .name = "nested_in_item2", - }, + .id = 22, + .description = "item2_level2_with_payload", + .payload = "payload for item 2 with more data", + .nested = benchmark.Level3{ + .id = 220, + .name = "nested_in_item2", + }, }, benchmark.Level2{ - .id = 23, - .description = "item3_level2_with_payload", - .payload = "payload for item 3", + .id = 23, + .description = "item3_level2_with_payload", + .payload = "payload for item 3", }, benchmark.Level2{ .id = 24, diff --git a/src/codegen/gen/output.zig b/src/codegen/gen/output.zig index 5ce6af2..8441ffa 100644 --- a/src/codegen/gen/output.zig +++ b/src/codegen/gen/output.zig @@ -129,11 +129,11 @@ pub const FileOutput = struct { // Write content up to the last non-newline character if (trimmed_len > 0) { - try file.writeStreamingAll(io,processed.items[0..trimmed_len]); + try file.writeStreamingAll(io, processed.items[0..trimmed_len]); } // Always add exactly one newline at the end - try file.writeStreamingAll(io,"\n"); + try file.writeStreamingAll(io, "\n"); // Free the content buffer self.content.deinit(self.allocator); diff --git a/src/gremlin/types.zig b/src/gremlin/types.zig index 1acfd9b..82cf449 100644 --- a/src/gremlin/types.zig +++ b/src/gremlin/types.zig @@ -57,8 +57,9 @@ pub const SizedBool = Sized(bool); pub const SizedBytes = Sized([]const u8); /// Protocol buffer encoding/decoding errors -pub const Error = error{ InvalidVarInt, // Invalid variable integer encoding +pub const Error = error{ + InvalidVarInt, // Invalid variable integer encoding InvalidTag, // Invalid field tag InvalidData, // Data doesn't match expected format - OutOfMemory // Memory allocation failed - }; + OutOfMemory, // Memory allocation failed +}; diff --git a/src/parser/entries/service.zig b/src/parser/entries/service.zig index 78af9f1..2fc4b42 100644 --- a/src/parser/entries/service.zig +++ b/src/parser/entries/service.zig @@ -85,7 +85,7 @@ test "service parsing" { // Test case 3: Service with nested braces { - var buf = ParserBuffer{ .buf = + var buf = ParserBuffer{ .buf = \\service Test { \\ rpc Method1 (Request) { option deprecated = true; } \\ rpc Method2 (Request) returns (Response) { option idempotency_level = "NO_SIDE_EFFECTS"; }