authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-14 15:11:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-15 14:18:20-08:00
loga70e0061579a4365da0092554470ffeadb4594a4
tree654a312e9bea838429c0834e0db97cd97640b78f
parent5a7dc4b0fae62c8b7ec798043c93e4d90704a638

std: add unit test for memory mapping


4 files changed, 55 insertions(+), 2 deletions(-)

lib/std/Io/File.zig+4
...@@ -784,6 +784,10 @@ pub fn hardLink(...@@ -784,6 +784,10 @@ pub fn hardLink(
784 return io.vtable.fileHardLink(io.userdata, file, new_dir, new_sub_path, options);784 return io.vtable.fileHardLink(io.userdata, file, new_dir, new_sub_path, options);
785}785}
786786
787pub fn createMemoryMap(file: File, io: Io, options: MemoryMap.CreateOptions) MemoryMap.CreateError!MemoryMap {
788 return .create(io, file, options);
789}
790
787test {791test {
788 _ = Reader;792 _ = Reader;
789 _ = Writer;793 _ = Writer;
lib/std/Io/File/MemoryMap.zig+9
...@@ -36,7 +36,14 @@ pub const CreateError = error{...@@ -36,7 +36,14 @@ pub const CreateError = error{
36} || Allocator.Error || File.ReadPositionalError;36} || Allocator.Error || File.ReadPositionalError;
3737
38pub const CreateOptions = struct {38pub const CreateOptions = struct {
39 /// When this has read set to false, bytes that are not modified before a
40 /// sync may have the original file contents, or may be set to zero.
39 protection: std.process.MemoryProtection = .{ .read = true, .write = true },41 protection: std.process.MemoryProtection = .{ .read = true, .write = true },
42 /// If set to `true`, allows bytes observed before calling `read` to be
43 /// undefined, and bytes unwritten before calling `write` to write
44 /// undefined memory to the file.
45 undefined_contents: bool = false,
46 /// Prefault the pages.
40 populate: bool = true,47 populate: bool = true,
41 /// Byte index of file to start from.48 /// Byte index of file to start from.
42 offset: u64 = 0,49 offset: u64 = 0,
...@@ -46,6 +53,8 @@ pub const CreateOptions = struct {...@@ -46,6 +53,8 @@ pub const CreateOptions = struct {
46 len: ?usize = null,53 len: ?usize = null,
47};54};
4855
56/// To release the resources associated with the returned `MemoryMap`, call
57/// `destroy`.
49pub fn create(io: Io, file: File, options: CreateOptions) CreateError!MemoryMap {58pub fn create(io: Io, file: File, options: CreateOptions) CreateError!MemoryMap {
50 return io.vtable.fileMemoryMapCreate(io.userdata, file, options);59 return io.vtable.fileMemoryMapCreate(io.userdata, file, options);
51}60}
lib/std/Io/Threaded.zig+1-2
...@@ -16150,8 +16150,7 @@ fn fileMemoryMapCreate(...@@ -16150,8 +16150,7 @@ fn fileMemoryMapCreate(
16150 };16150 };
16151 errdefer gpa.rawFree(memory, alignment, @returnAddress());16151 errdefer gpa.rawFree(memory, alignment, @returnAddress());
1615216152
16153 // If the mapping does not have read permissions, no need to populate the contents.16153 if (!options.undefined_contents) try mmSyncRead(file, memory, offset);
16154 if (options.protection.read) try mmSyncRead(file, memory, offset);
1615516154
16156 return .{16155 return .{
16157 .file = file,16156 .file = file,
lib/std/Io/test.zig+41
...@@ -592,3 +592,44 @@ test "randomSecure" {...@@ -592,3 +592,44 @@ test "randomSecure" {
592 // that two sets of 50 bytes were equal.592 // that two sets of 50 bytes were equal.
593 try expect(!mem.eql(u8, &buf_a, &buf_b));593 try expect(!mem.eql(u8, &buf_a, &buf_b));
594}594}
595
596test "memory mapping" {
597 const io = testing.io;
598
599 var tmp = tmpDir(.{});
600 defer tmp.cleanup();
601
602 try tmp.dir.writeFile(io, .{
603 .sub_path = "blah.txt",
604 .data = "this is my data123",
605 });
606
607 {
608 var file = try tmp.dir.openFile(io, "blah.txt", .{});
609 defer file.close(io);
610
611 var mm = try file.createMemoryMap(io, .{});
612 defer mm.destroy(io);
613
614 try expectEqualStrings("this is my data123", mm.memory);
615 mm.memory[5] = '9';
616 mm.memory[8] = '9';
617
618 try mm.write(io);
619 }
620
621 var buffer: [100]u8 = undefined;
622 const updated_contents = try tmp.dir.readFile(io, "blah.txt", &buffer);
623 try expectEqualStrings("this9is9my data123", updated_contents);
624
625 var file = try tmp.dir.openFile(io, "blah.txt", .{});
626 defer file.close(io);
627
628 var mm = try file.createMemoryMap(io, .{
629 .protection = .{ .read = true },
630 .offset = 2,
631 });
632 defer mm.destroy(io);
633
634 try expectEqualStrings("is9is9my data123", mm.memory);
635}