Commit 4381241237

Igor Anić <igor.anic@gmail.com>
2023-11-27 17:17:28
tar: refactor Buffer
Move reader into Buffer and make it BufferedReader. This doesn't introduce any new functionality just grouping similar things.
1 parent ff8544d
Changed files (1)
lib
lib/std/tar.zig
@@ -136,51 +136,90 @@ pub const Header = struct {
     }
 };
 
-const Buffer = struct {
-    buffer: [512 * 8]u8 = undefined,
-    start: usize = 0,
-    end: usize = 0,
+fn BufferedReader(comptime ReaderType: type) type {
+    return struct {
+        unbuffered_reader: ReaderType,
+        buffer: [512 * 8]u8 = undefined,
+        start: usize = 0,
+        end: usize = 0,
 
-    pub fn readChunk(b: *Buffer, reader: anytype, count: usize) ![]const u8 {
-        b.ensureCapacity(1024);
+        const Self = @This();
 
-        const ask = @min(b.buffer.len - b.end, count -| (b.end - b.start));
-        b.end += try reader.readAtLeast(b.buffer[b.end..], ask);
+        pub fn readChunk(self: *Self, count: usize) ![]const u8 {
+            self.ensureCapacity(1024);
 
-        return b.buffer[b.start..b.end];
-    }
+            const ask = @min(self.buffer.len - self.end, count -| (self.end - self.start));
+            self.end += try self.unbuffered_reader.readAtLeast(self.buffer[self.end..], ask);
 
-    pub fn advance(b: *Buffer, count: usize) void {
-        b.start += count;
-        assert(b.start <= b.end);
-    }
+            return self.buffer[self.start..self.end];
+        }
 
-    pub fn skip(b: *Buffer, reader: anytype, count: usize) !void {
-        if (b.start + count > b.end) {
-            try reader.skipBytes(b.start + count - b.end, .{});
-            b.start = b.end;
-        } else {
-            b.advance(count);
+        pub fn advance(self: *Self, count: usize) void {
+            self.start += count;
+            assert(self.start <= self.end);
+        }
+
+        pub fn skip(self: *Self, count: usize) !void {
+            if (self.start + count > self.end) {
+                try self.unbuffered_reader.skipBytes(self.start + count - self.end, .{});
+                self.start = self.end;
+            } else {
+                self.advance(count);
+            }
         }
-    }
 
-    inline fn ensureCapacity(b: *Buffer, count: usize) void {
-        if (b.buffer.len - b.start < count) {
-            const dest_end = b.end - b.start;
-            @memcpy(b.buffer[0..dest_end], b.buffer[b.start..b.end]);
-            b.end = dest_end;
-            b.start = 0;
+        inline fn ensureCapacity(self: *Self, count: usize) void {
+            if (self.buffer.len - self.start < count) {
+                const dest_end = self.end - self.start;
+                @memcpy(self.buffer[0..dest_end], self.buffer[self.start..self.end]);
+                self.end = dest_end;
+                self.start = 0;
+            }
         }
-    }
-};
+
+        pub fn write(self: *Self, writer: anytype, size: usize) !void {
+            const rounded_file_size = std.mem.alignForward(usize, size, 512);
+            const chunk_size = rounded_file_size + 512;
+            const pad_len: usize = rounded_file_size - size;
+
+            var file_off: usize = 0;
+            while (true) {
+                const temp = try self.readChunk(chunk_size - file_off);
+                if (temp.len == 0) return error.UnexpectedEndOfStream;
+                const slice = temp[0..@min(size - file_off, temp.len)];
+                try writer.writeAll(slice);
+
+                file_off += slice.len;
+                self.advance(slice.len);
+                if (file_off >= size) {
+                    self.advance(pad_len);
+                    return;
+                }
+            }
+        }
+
+        pub fn copy(self: *Self, dst_buffer: []u8, size: usize) !void {
+            const rounded_file_size = std.mem.alignForward(usize, size, 512);
+            const chunk_size = rounded_file_size + 512;
+
+            var i: usize = 0;
+            while (i < size) {
+                const slice = try self.readChunk(chunk_size - i);
+                if (slice.len == 0) return error.UnexpectedEndOfStream;
+                const copy_size: usize = @min(size - i, slice.len);
+                @memcpy(dst_buffer[i .. i + copy_size], slice[0..copy_size]);
+                self.advance(copy_size);
+                i += copy_size;
+            }
+        }
+    };
+}
 
 fn Iterator(comptime ReaderType: type) type {
     return struct {
         file_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined,
         file_name_len: usize = 0,
-        buffer: Buffer = .{},
-        reader: ReaderType,
-        pad_len: usize = 0,
+        reader: BufferedReader(ReaderType),
         diagnostics: ?*Options.Diagnostics,
 
         const Self = @This();
@@ -193,50 +232,32 @@ fn Iterator(comptime ReaderType: type) type {
             iter: *Self,
 
             pub fn write(self: File, writer: anytype) !void {
-                const rounded_file_size = std.mem.alignForward(u64, self.size, 512);
-                var file_off: usize = 0;
-                while (true) {
-                    const temp = try self.iter.buffer.readChunk(self.iter.reader, @intCast(rounded_file_size + 512 - file_off));
-                    if (temp.len == 0) return error.UnexpectedEndOfStream;
-                    const slice = temp[0..@intCast(@min(self.size - file_off, temp.len))];
-                    try writer.writeAll(slice);
-
-                    file_off += slice.len;
-                    self.iter.buffer.advance(slice.len);
-                    if (file_off >= self.size) {
-                        return;
-                        //     self.iter.buffer.advance(pad_len);
-                        //     continue :header;
-                    }
-                }
+                try self.iter.reader.write(writer, self.size);
             }
 
-            pub fn skip(self: File) void {
-                _ = self;
-                unreachable;
+            pub fn skip(self: File) !void {
+                const rounded_file_size = std.mem.alignForward(usize, self.size, 512);
+                try self.iter.reader.skip(rounded_file_size);
             }
         };
 
         pub fn next(self: *Self) !?File {
-            self.buffer.advance(self.pad_len);
-            self.pad_len = 0;
             self.file_name_len = 0;
-
             while (true) {
-                const chunk = try self.buffer.readChunk(self.reader, 1024);
+                const chunk = try self.reader.readChunk(1024);
                 switch (chunk.len) {
                     0 => return null,
                     1...511 => return error.UnexpectedEndOfStream,
                     else => {},
                 }
-                self.buffer.advance(512);
+                self.reader.advance(512);
 
                 const header: Header = .{ .bytes = chunk[0..512] };
                 const file_size = try header.fileSize();
                 const file_type = header.fileType();
                 const link_name = header.linkName();
-                const rounded_file_size = std.mem.alignForward(u64, file_size, 512);
-                self.pad_len = @intCast(rounded_file_size - file_size);
+                const rounded_file_size: usize = std.mem.alignForward(usize, file_size, 512);
+
                 const file_name = if (self.file_name_len == 0)
                     try header.fullFileName(&self.file_name_buffer)
                 else
@@ -253,44 +274,33 @@ fn Iterator(comptime ReaderType: type) type {
                         };
                     },
                     .global_extended_header => {
-                        self.buffer.skip(self.reader, @intCast(rounded_file_size)) catch return error.TarHeadersTooBig;
+                        self.reader.skip(rounded_file_size) catch return error.TarHeadersTooBig;
                     },
                     .extended_header => {
-                        if (file_size == 0) {
-                            self.buffer.advance(@intCast(rounded_file_size));
-                            continue;
-                        }
+                        if (file_size == 0) continue;
 
-                        const chunk_size: usize = @intCast(rounded_file_size + 512);
+                        const chunk_size: usize = rounded_file_size + 512;
                         var data_off: usize = 0;
                         const file_name_override_len = while (data_off < file_size) {
-                            const slice = try self.buffer.readChunk(self.reader, chunk_size - data_off);
+                            const slice = try self.reader.readChunk(chunk_size - data_off);
                             if (slice.len == 0) return error.UnexpectedEndOfStream;
-                            const remaining_size: usize = @intCast(file_size - data_off);
+                            const remaining_size: usize = file_size - data_off;
                             const attr_info = try parsePaxAttribute(slice[0..@min(remaining_size, slice.len)], remaining_size);
 
                             if (std.mem.eql(u8, attr_info.key, "path")) {
                                 if (attr_info.value_len > self.file_name_buffer.len) return error.NameTooLong;
-                                self.buffer.advance(attr_info.value_off);
+                                self.reader.advance(attr_info.value_off);
                                 data_off += attr_info.value_off;
                                 break attr_info.value_len;
                             }
 
-                            try self.buffer.skip(self.reader, attr_info.size);
+                            try self.reader.skip(attr_info.size);
                             data_off += attr_info.size;
                         } else 0;
 
-                        var i: usize = 0;
-                        while (i < file_name_override_len) {
-                            const slice = try self.buffer.readChunk(self.reader, chunk_size - data_off - i);
-                            if (slice.len == 0) return error.UnexpectedEndOfStream;
-                            const copy_size: usize = @intCast(@min(file_name_override_len - i, slice.len));
-                            @memcpy(self.file_name_buffer[i .. i + copy_size], slice[0..copy_size]);
-                            self.buffer.advance(copy_size);
-                            i += copy_size;
-                        }
+                        try self.reader.copy(&self.file_name_buffer, file_name_override_len);
 
-                        try self.buffer.skip(self.reader, @intCast(rounded_file_size - data_off - file_name_override_len));
+                        try self.reader.skip(rounded_file_size - data_off - file_name_override_len);
                         self.file_name_len = file_name_override_len;
                         continue;
                     },
@@ -309,7 +319,11 @@ fn Iterator(comptime ReaderType: type) type {
 }
 
 pub fn iterator(reader: anytype, diagnostics: ?*Options.Diagnostics) Iterator(@TypeOf(reader)) {
-    return .{ .reader = reader, .diagnostics = diagnostics };
+    const ReaderType = @TypeOf(reader);
+    return .{
+        .reader = BufferedReader(ReaderType){ .unbuffered_reader = reader },
+        .diagnostics = diagnostics,
+    };
 }
 
 pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !void {
@@ -364,7 +378,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
                 if (file) |f| {
                     try iter_file.write(f);
                 } else {
-                    iter_file.skip();
+                    try iter_file.skip();
                 }
             },
             .symbolic_link => {