std: Minor changes to the fs module

* Add a size_hint parameter to the read{toEnd,File}AllocOptions fns
* Rename readAllAlloc{,Options} to readToEndAlloc{,Options} as they
  don't rewind the file before reading
* Fix missing rewind in test case
This commit is contained in:
LemonBoy 2020-09-04 09:28:43 +02:00
parent 5f31d54064
commit 90743881cf
5 changed files with 31 additions and 13 deletions

View File

@ -1437,24 +1437,29 @@ pub const Dir = struct {
/// On success, caller owns returned buffer.
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 {
return self.readFileAllocOptions(allocator, file_path, max_bytes, @alignOf(u8), null);
return self.readFileAllocOptions(allocator, file_path, max_bytes, null, @alignOf(u8), null);
}
/// On success, caller owns returned buffer.
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
/// If `size_hint` is specified the initial buffer size is calculated using
/// that value, otherwise the effective file size is used instead.
/// Allows specifying alignment and a sentinel value.
pub fn readFileAllocOptions(
self: Dir,
allocator: *mem.Allocator,
file_path: []const u8,
max_bytes: usize,
size_hint: ?usize,
comptime alignment: u29,
comptime optional_sentinel: ?u8,
) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) {
var file = try self.openFile(file_path, .{});
defer file.close();
return file.readAllAllocOptions(allocator, max_bytes, alignment, optional_sentinel);
const stat_size = size_hint orelse try file.getEndPos();
return file.readToEndAllocOptions(allocator, max_bytes, stat_size, alignment, optional_sentinel);
}
pub const DeleteTreeError = error{

View File

@ -363,25 +363,29 @@ pub const File = struct {
try os.futimens(self.handle, &times);
}
/// Reads all the bytes from the current position to the end of the file.
/// On success, caller owns returned buffer.
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
pub fn readAllAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 {
return self.readAllAllocOptions(allocator, max_bytes, @alignOf(u8), null);
pub fn readToEndAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 {
return self.readToEndAllocOptions(allocator, max_bytes, null, @alignOf(u8), null);
}
/// Reads all the bytes from the current position to the end of the file.
/// On success, caller owns returned buffer.
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
/// If `size_hint` is specified the initial buffer size is calculated using
/// that value, otherwise an arbitrary value is used instead.
/// Allows specifying alignment and a sentinel value.
pub fn readAllAllocOptions(
pub fn readToEndAllocOptions(
self: File,
allocator: *mem.Allocator,
max_bytes: usize,
size_hint: ?usize,
comptime alignment: u29,
comptime optional_sentinel: ?u8,
) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) {
const stat_size = try self.getEndPos();
const size = math.cast(usize, stat_size) catch math.maxInt(usize);
if (size > max_bytes) return error.FileTooBig;
// If no size hint is provided fall back to the size=0 code path
const size = size_hint orelse 0;
// The file size returned by stat is used as hint to set the buffer
// size. If the reported size is zero, as it happens on Linux for files

View File

@ -188,7 +188,7 @@ test "readAllAlloc" {
var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });
defer file.close();
const buf1 = try file.readAllAlloc(testing.allocator, 1024);
const buf1 = try file.readToEndAlloc(testing.allocator, 1024);
defer testing.allocator.free(buf1);
testing.expect(buf1.len == 0);
@ -197,20 +197,21 @@ test "readAllAlloc" {
try file.seekTo(0);
// max_bytes > file_size
const buf2 = try file.readAllAlloc(testing.allocator, 1024);
const buf2 = try file.readToEndAlloc(testing.allocator, 1024);
defer testing.allocator.free(buf2);
testing.expectEqual(write_buf.len, buf2.len);
testing.expect(std.mem.eql(u8, write_buf, buf2));
try file.seekTo(0);
// max_bytes == file_size
const buf3 = try file.readAllAlloc(testing.allocator, write_buf.len);
const buf3 = try file.readToEndAlloc(testing.allocator, write_buf.len);
defer testing.allocator.free(buf3);
testing.expectEqual(write_buf.len, buf3.len);
testing.expect(std.mem.eql(u8, write_buf, buf3));
try file.seekTo(0);
// max_bytes < file_size
testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, write_buf.len - 1));
testing.expectError(error.FileTooBig, file.readToEndAlloc(testing.allocator, write_buf.len - 1));
}
test "directory operations on files" {

View File

@ -595,6 +595,7 @@ pub const Scope = struct {
module.gpa,
self.sub_file_path,
std.math.maxInt(u32),
null,
1,
0,
);
@ -697,6 +698,7 @@ pub const Scope = struct {
module.gpa,
self.sub_file_path,
std.math.maxInt(u32),
null,
1,
0,
);

View File

@ -806,7 +806,13 @@ fn fmtPathFile(
if (stat.kind == .Directory)
return error.IsDir;
const source_code = source_file.readAllAlloc(fmt.gpa, max_src_size) catch |err| switch (err) {
const source_code = source_file.readToEndAllocOptions(
fmt.gpa,
max_src_size,
stat.size,
@alignOf(u8),
null,
) catch |err| switch (err) {
error.ConnectionResetByPeer => unreachable,
error.ConnectionTimedOut => unreachable,
error.NotOpenForReading => unreachable,