diff --git a/flake.nix b/flake.nix index 2aeca70..5e96027 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ flake-utils.lib.eachSystem systems ( system: let pkgs = nixpkgs.legacyPackages.${system}; - zig = zig-overlay.packages.${system}."0.15.2"; + zig = zig-overlay.packages.${system}."0.16.0"; in rec { formatter = nixpkgs.legacyPackages.${system}.nixpkgs-fmt; packages.default = packages.sonic-pdb-parser; diff --git a/src/fasta-lib.zig b/src/fasta-lib.zig index 651892b..d47ef40 100644 --- a/src/fasta-lib.zig +++ b/src/fasta-lib.zig @@ -67,9 +67,9 @@ fn handleRecord(writer: anytype, record: Record, prevChainID: *u8) !void { } pub fn pdbToFasta(allocator: std.mem.Allocator, lines: []const u8) ![]const u8 { - var builder: std.ArrayList(u8) = .empty; - errdefer builder.deinit(allocator); - const writer = builder.writer(allocator); + var builder = std.Io.Writer.Allocating.init(allocator); + errdefer builder.deinit(); + const writer = &builder.writer; var prevChainID: u8 = 0; var recordNumber: u32 = 0; var input = std.mem.tokenizeScalar(u8, lines, '\n'); @@ -78,27 +78,27 @@ pub fn pdbToFasta(allocator: std.mem.Allocator, lines: []const u8) ![]const u8 { if (line.len < 6) continue; const tag_int = std.mem.readInt(u48, line[0..6], .little); if (tag_int == end) break; - const tag = std.meta.intToEnum(records.RecordType, tag_int) catch continue; + const tag = records.recordTypeFromInt(tag_int) orelse continue; var record = try Record.parse(line, tag, recordNumber, allocator); defer record.free(allocator); if (record == .endmdl) break; recordNumber = record.serial(); try handleRecord(writer, record, &prevChainID); } - return try builder.toOwnedSlice(allocator); + return try builder.toOwnedSlice(); } // Handles the conversion of a list of records to a fasta file pub fn recordsToFasta(allocator: std.mem.Allocator, input: std.ArrayList(Record)) ![]const u8 { - var builder: std.ArrayList(u8) = .empty; - errdefer builder.deinit(allocator); - const writer = builder.writer(allocator); + var builder = std.Io.Writer.Allocating.init(allocator); + errdefer builder.deinit(); + const writer = &builder.writer; var prevChainID: u8 = 0; for (input.items) |record| { if (record == .endmdl) break; try handleRecord(writer, record, &prevChainID); } - return try builder.toOwnedSlice(allocator); + return try builder.toOwnedSlice(); } // test "recordsToFasta" { diff --git a/src/fasta.zig b/src/fasta.zig index 9642946..c23f599 100644 --- a/src/fasta.zig +++ b/src/fasta.zig @@ -8,7 +8,7 @@ const Args = struct { fileName: []const u8 = "", output: ?[]const u8 = null, - pub fn parseArgs(argsList: [][:0]u8) !Args { + pub fn parseArgs(argsList: []const [:0]const u8) !Args { var args = Args{}; for (argsList, 0..) |arg, idx| { if (strings.equals(arg, "-f")) { @@ -19,41 +19,43 @@ const Args = struct { } if (strings.equals(arg, "-h")) { std.debug.print("Usage: pdb2fasta -f -o \n", .{}); - std.posix.exit(0); + std.process.exit(0); } } if (strings.equals(args.fileName, "")) { std.debug.print("No file specified, please provide a file\n", .{}); - std.posix.exit(1); + std.process.exit(1); } return args; } }; -pub fn main() !void { - const allocator = std.heap.page_allocator; - const args = try std.process.argsAlloc(allocator); - defer std.process.argsFree(allocator, args); +pub fn main(init: std.process.Init) !void { + const gpa = init.gpa; + // const allocator = std.heap.page_allocator; + const args = try init.minimal.args.toSlice(init.arena.allocator()); + // const args = try std.process.argsAlloc(allocator); + // defer std.process.argsFree(allocator, args); const parsedArgs = try Args.parseArgs(args); - const file = try std.fs.cwd().openFile(parsedArgs.fileName, .{}); - defer file.close(); + const file = try std.Io.Dir.cwd().openFile(init.io, parsedArgs.fileName, .{}); + defer file.close(init.io); var read_buffer: [4096]u8 = undefined; - var file_reader = file.reader(&read_buffer); - const atoms = try file_reader.interface.allocRemaining(allocator, .unlimited); - defer allocator.free(atoms); + var file_reader = file.reader(init.io, &read_buffer); + const atoms = try file_reader.interface.allocRemaining(gpa, .unlimited); + defer gpa.free(atoms); - const converted = try fasta.pdbToFasta(allocator, atoms); - defer allocator.free(converted); + const converted = try fasta.pdbToFasta(gpa, atoms); + defer gpa.free(converted); var stdout_buffer: [4096]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer); + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &stdout_buffer); try stdout_writer.interface.writeAll(converted); try stdout_writer.interface.flush(); if (parsedArgs.output != null) { - const fastaPath = try std.fs.cwd().createFile(parsedArgs.output.?, .{}); - defer fastaPath.close(); + const fastaPath = try std.Io.Dir.cwd().createFile(init.io, parsedArgs.output.?, .{}); + defer fastaPath.close(init.io); var write_buffer: [4096]u8 = undefined; - var fasta_writer = fastaPath.writerStreaming(&write_buffer); + var fasta_writer = fastaPath.writerStreaming(init.io, &write_buffer); try fasta_writer.interface.writeAll(converted); try fasta_writer.interface.flush(); } diff --git a/src/main.zig b/src/main.zig index 555093a..5f6c7c1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -22,7 +22,7 @@ const Args = struct { output: string = "times.csv", json: bool = false, - pub fn parseArgs(argsList: [][:0]u8) !Args { + pub fn parseArgs(argsList: []const [:0]const u8) !Args { var args = Args{}; for (argsList, 0..) |arg, idx| { if (strings.equals(arg, "-r")) { @@ -37,59 +37,65 @@ const Args = struct { if (strings.equals(arg, "--json")) args.json = true; if (strings.equals(arg, "-h")) { std.debug.print("Usage: exe -r -f -o \n", .{}); - std.posix.exit(0); + std.process.exit(0); } } if (strings.equals(args.fileName, "")) { std.debug.print("No file specified, please provide a file\n", .{}); - std.posix.exit(1); + std.process.exit(1); } return args; } }; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - const args = try std.process.argsAlloc(allocator); - defer std.process.argsFree(allocator, args); +pub fn main(init: std.process.Init) !void { + // var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = init.gpa; + // defer _ = gpa.deinit(); + // const allocator = gpa.allocator(); + // const args = try std.process.argsAlloc(allocator); + // defer std.process.argsFree(allocator, args); + var args_arena = std.heap.ArenaAllocator.init(allocator); + defer args_arena.deinit(); + const args = try init.minimal.args.toSlice(args_arena.allocator()); const parsedArgs = try Args.parseArgs(args); var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const arenaAllocator = arena.allocator(); - const file = try fs.cwd().openFile(parsedArgs.fileName, .{}); - defer file.close(); + const file = try std.Io.Dir.cwd().openFile(init.io, parsedArgs.fileName, .{}); + defer file.close(init.io); if (parsedArgs.runs == 1) { var read_buffer: [4096]u8 = undefined; - var file_reader = file.reader(&read_buffer); + var file_reader = file.reader(init.io, &read_buffer); var pdb = try PDB.init(arenaAllocator); defer pdb.deinit(); try pdb.read(&file_reader.interface); var stdout_buffer: [4096]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer); + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &stdout_buffer); if (parsedArgs.json) { try pdb.writeJson(&stdout_writer.interface); try stdout_writer.interface.writeByte('\n'); + try stdout_writer.flush(); } else { - try stdout_writer.interface.print("{f}\n", .{pdb}); + try stdout_writer.interface.print("{f}", .{pdb}); + try stdout_writer.flush(); } try stdout_writer.interface.flush(); return; } - var timer = try std.time.Timer.start(); + var timer_start = std.Io.Clock.awake.now(init.io); var times = try std.ArrayList(u64).initCapacity(allocator, @intCast(parsedArgs.runs)); defer times.deinit(allocator); var sum: u64 = 0; - const csv = try fs.cwd().createFile(parsedArgs.output, .{}); - defer csv.close(); - try RunRecord.writeCSVHeader(csv); + const csv = try std.Io.Dir.cwd().createFile(init.io, parsedArgs.output, .{}); + defer csv.close(init.io); + try RunRecord.writeCSVHeader(init.io, csv); // var arena = std.heap.ArenaAllocator.init(allocator); // defer arena.deinit(); @@ -98,17 +104,17 @@ pub fn main() !void { for (0..parsedArgs.runs) |i| { defer { _ = arena.reset(.retain_capacity); - file.seekTo(0) catch @panic("file error"); + init.io.vtable.fileSeekTo(init.io.userdata, file, 0) catch @panic("file error"); } - timer.reset(); + timer_start = std.Io.Clock.awake.now(init.io); var read_buffer: [4096]u8 = undefined; - var file_reader = file.reader(&read_buffer); + var file_reader = file.reader(init.io, &read_buffer); var pdb = try PDB.init(arenaAllocator); try pdb.read(&file_reader.interface); - const elapsed = timer.read(); + const elapsed: u64 = @intCast(timer_start.untilNow(init.io, .awake).toNanoseconds()); try times.append(allocator, elapsed); var runRecord: RunRecord = RunRecord{ .run = i + 1, .time = elapsed, .file = parsedArgs.fileName }; - try runRecord.writeCSVLine(csv); + try runRecord.writeCSVLine(init.io, csv); sum += elapsed; std.debug.print("Run {} Complete\n", .{i}); } diff --git a/src/records.zig b/src/records.zig index da2aebd..77d2b64 100644 --- a/src/records.zig +++ b/src/records.zig @@ -68,14 +68,11 @@ pub const PDB = struct { var recordNumber: u32 = 0; const end = std.mem.readInt(u48, "END ", .little); while (true) { - const line = reader.takeDelimiterExclusive('\n') catch |err| switch (err) { - error.EndOfStream => break, - else => |e| return e, - }; + const line = (try reader.takeDelimiter('\n')) orelse break; if (line.len < 6) continue; const tag_int = std.mem.readInt(u48, line[0..6], .little); if (tag_int == end) break; - const tag = std.meta.intToEnum(RecordType, tag_int) catch continue; + const tag = recordTypeFromInt(tag_int) orelse continue; if (tag == .endmdl) { continue; } @@ -108,10 +105,7 @@ pub fn PDBReader(reader: anytype, allocator: std.mem.Allocator) !std.ArrayList(R // Some of the CHARMM files are longer const end = std.mem.readInt(u48, "END ", .little); while (true) { - const line = reader.takeDelimiterExclusive('\n') catch |err| switch (err) { - error.EndOfStream => break, - else => |e| return e, - }; + const line = (try reader.takeDelimiter('\n')) orelse break; if (line.len < 6) continue; const tag_int = std.mem.readInt(u48, line[0..6], .little); if (tag_int == end) break; @@ -138,29 +132,39 @@ pub const RunRecord = struct { file: string, // there is no need to allocate here. you can print directly to the file. - pub fn writeCSVLine(self: *RunRecord, file: std.fs.File) !void { + pub fn writeCSVLine(self: *RunRecord, io: std.Io, file: std.Io.File) !void { var buffer: [1024]u8 = undefined; - var file_writer = file.writerStreaming(&buffer); + var file_writer = file.writerStreaming(io, &buffer); try file_writer.interface.print("{d},{d},{s}\n", .{ self.run, self.time, self.file }); try file_writer.interface.flush(); } - pub fn writeCSVHeader(file: std.fs.File) !void { + pub fn writeCSVHeader(io: std.Io, file: std.Io.File) !void { // const fields = @typeInfo(RunRecord).Struct.fields; const fields = @typeInfo(RunRecord).@"struct".fields; const len = fields.len; + var buffer: [1024]u8 = undefined; + var file_writer = file.writerStreaming(io, &buffer); inline for (fields, 0..) |field, idx| { std.debug.print("{s}\n", .{field.name}); - _ = try file.write(field.name); + try file_writer.interface.writeAll(field.name); if (idx == len - 1) { break; } - _ = try file.write(","); + try file_writer.interface.writeByte(','); } - _ = try file.write("\n"); + try file_writer.interface.writeByte('\n'); + try file_writer.interface.flush(); } }; +pub fn recordTypeFromInt(value: u48) ?RecordType { + inline for (std.meta.tags(RecordType)) |tag| { + if (@intFromEnum(tag) == value) return tag; + } + return null; +} + // zig fmt: off /// An enum derived of possible records in a PDB file pub const RecordType = enum(u48) {