authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2025-08-24 22:19:10 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2025-08-24 22:19:10 -07:00
log5c892a2a4906837df00bb943faabec17714a406b
tree58e303a48f2b47566c95aa362ad7ddf48a79e3a0
parent59ffaf7611ec0b535d172f8faacb5a769667bb02

add Dir.readFileAlloc


2 files changed, 44 insertions(+), 0 deletions(-)

Dir.zig+7
...@@ -33,3 +33,10 @@ pub const OpenDirFlags = packed struct {...@@ -33,3 +33,10 @@ pub const OpenDirFlags = packed struct {
33pub fn to_std(self: Dir) std.fs.Dir {33pub fn to_std(self: Dir) std.fs.Dir {
34 return .{ .fd = @intFromEnum(self.fd) };34 return .{ .fd = @intFromEnum(self.fd) };
35}35}
36
37pub fn readFileAlloc(self: Dir, allocator: std.mem.Allocator, file_path: [:0]const u8, max_bytes: usize) ![:0]u8 {
38 var file = try self.openFile(file_path, .{});
39 defer file.close();
40 const stat_size = std.math.cast(usize, try file.getEndPos()) orelse return error.FileTooBig;
41 return file.readToEndAlloc(allocator, max_bytes, stat_size);
42}
File.zig+37
...@@ -52,6 +52,43 @@ pub fn stat(self: File) !Stat {...@@ -52,6 +52,43 @@ pub fn stat(self: File) !Stat {
52 };52 };
53}53}
5454
55pub fn getEndPos(self: File) !u64 {
56 return (try self.stat()).size;
57}
58
59pub fn readToEndAlloc(self: File, allocator: std.mem.Allocator, max_bytes: usize, size_hint: ?usize) ![:0]u8 {
60 var array_list = try std.ArrayList(u8).initCapacity(allocator, @min(size_hint orelse 1023, max_bytes) + 1);
61 defer array_list.deinit();
62 self.readAllArrayList(&array_list, max_bytes) catch |err| switch (err) {
63 error.StreamTooLong => return error.FileTooBig,
64 else => |e| return e,
65 };
66 return try array_list.toOwnedSliceSentinel(0);
67}
68
69pub fn readAllArrayList(self: File, array_list: *std.ArrayList(u8), max_append_size: usize) anyerror!void {
70 try array_list.ensureTotalCapacity(@min(max_append_size, 4096));
71 const original_len = array_list.items.len;
72 var start_index: usize = original_len;
73 while (true) {
74 array_list.expandToCapacity();
75 const dest_slice = array_list.items[start_index..];
76 const bytes_read = try self.readAll(dest_slice);
77 start_index += bytes_read;
78
79 if (start_index - original_len > max_append_size) {
80 array_list.shrinkAndFree(original_len + max_append_size);
81 return error.StreamTooLong;
82 }
83 if (bytes_read != dest_slice.len) {
84 array_list.shrinkAndFree(start_index);
85 return;
86 }
87 // This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
88 try array_list.ensureTotalCapacity(start_index + 1);
89 }
90}
91
55pub const Stat = struct {92pub const Stat = struct {
56 inode: INode,93 inode: INode,
57 size: u64,94 size: u64,