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(
784784 return io.vtable.fileHardLink(io.userdata, file, new_dir, new_sub_path, options);
785785}
786786
787pub fn createMemoryMap(file: File, io: Io, options: MemoryMap.CreateOptions) MemoryMap.CreateError!MemoryMap {
788 return .create(io, file, options);
789}
790
787791test {
788792 _ = Reader;
789793 _ = Writer;
lib/std/Io/File/MemoryMap.zig+9
......@@ -36,7 +36,14 @@ pub const CreateError = error{
3636} || Allocator.Error || File.ReadPositionalError;
3737
3838pub 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.
3941 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.
4047 populate: bool = true,
4148 /// Byte index of file to start from.
4249 offset: u64 = 0,
......@@ -46,6 +53,8 @@ pub const CreateOptions = struct {
4653 len: ?usize = null,
4754};
4855
56/// To release the resources associated with the returned `MemoryMap`, call
57/// `destroy`.
4958pub fn create(io: Io, file: File, options: CreateOptions) CreateError!MemoryMap {
5059 return io.vtable.fileMemoryMapCreate(io.userdata, file, options);
5160}
lib/std/Io/Threaded.zig+1-2
......@@ -16150,8 +16150,7 @@ fn fileMemoryMapCreate(
1615016150 };
1615116151 errdefer gpa.rawFree(memory, alignment, @returnAddress());
1615216152
16153 // If the mapping does not have read permissions, no need to populate the contents.
16154 if (options.protection.read) try mmSyncRead(file, memory, offset);
16153 if (!options.undefined_contents) try mmSyncRead(file, memory, offset);
1615516154
1615616155 return .{
1615716156 .file = file,
lib/std/Io/test.zig+41
......@@ -592,3 +592,44 @@ test "randomSecure" {
592592 // that two sets of 50 bytes were equal.
593593 try expect(!mem.eql(u8, &buf_a, &buf_b));
594594}
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}