zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit a70e0061579a4365da0092554470ffeadb4594a4 (tree)
parent 5a7dc4b0fae62c8b7ec798043c93e4d90704a638
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Wed, 14 Jan 2026 15:11:37 -0800

std: add unit test for memory mapping

Diffstat:
Mlib/std/Io/File.zig | 4++++
Mlib/std/Io/File/MemoryMap.zig | 9+++++++++
Mlib/std/Io/Threaded.zig | 3+--
Mlib/std/Io/test.zig | 41+++++++++++++++++++++++++++++++++++++++++
4 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig @@ -784,6 +784,10 @@ pub fn hardLink( return io.vtable.fileHardLink(io.userdata, file, new_dir, new_sub_path, options); } +pub fn createMemoryMap(file: File, io: Io, options: MemoryMap.CreateOptions) MemoryMap.CreateError!MemoryMap { + return .create(io, file, options); +} + test { _ = Reader; _ = Writer; diff --git a/lib/std/Io/File/MemoryMap.zig b/lib/std/Io/File/MemoryMap.zig @@ -36,7 +36,14 @@ pub const CreateError = error{ } || Allocator.Error || File.ReadPositionalError; pub const CreateOptions = struct { + /// When this has read set to false, bytes that are not modified before a + /// sync may have the original file contents, or may be set to zero. protection: std.process.MemoryProtection = .{ .read = true, .write = true }, + /// If set to `true`, allows bytes observed before calling `read` to be + /// undefined, and bytes unwritten before calling `write` to write + /// undefined memory to the file. + undefined_contents: bool = false, + /// Prefault the pages. populate: bool = true, /// Byte index of file to start from. offset: u64 = 0, @@ -46,6 +53,8 @@ pub const CreateOptions = struct { len: ?usize = null, }; +/// To release the resources associated with the returned `MemoryMap`, call +/// `destroy`. pub fn create(io: Io, file: File, options: CreateOptions) CreateError!MemoryMap { return io.vtable.fileMemoryMapCreate(io.userdata, file, options); } diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig @@ -16150,8 +16150,7 @@ fn fileMemoryMapCreate( }; errdefer gpa.rawFree(memory, alignment, @returnAddress()); - // If the mapping does not have read permissions, no need to populate the contents. - if (options.protection.read) try mmSyncRead(file, memory, offset); + if (!options.undefined_contents) try mmSyncRead(file, memory, offset); return .{ .file = file, diff --git a/lib/std/Io/test.zig b/lib/std/Io/test.zig @@ -592,3 +592,44 @@ test "randomSecure" { // that two sets of 50 bytes were equal. try expect(!mem.eql(u8, &buf_a, &buf_b)); } + +test "memory mapping" { + const io = testing.io; + + var tmp = tmpDir(.{}); + defer tmp.cleanup(); + + try tmp.dir.writeFile(io, .{ + .sub_path = "blah.txt", + .data = "this is my data123", + }); + + { + var file = try tmp.dir.openFile(io, "blah.txt", .{}); + defer file.close(io); + + var mm = try file.createMemoryMap(io, .{}); + defer mm.destroy(io); + + try expectEqualStrings("this is my data123", mm.memory); + mm.memory[5] = '9'; + mm.memory[8] = '9'; + + try mm.write(io); + } + + var buffer: [100]u8 = undefined; + const updated_contents = try tmp.dir.readFile(io, "blah.txt", &buffer); + try expectEqualStrings("this9is9my data123", updated_contents); + + var file = try tmp.dir.openFile(io, "blah.txt", .{}); + defer file.close(io); + + var mm = try file.createMemoryMap(io, .{ + .protection = .{ .read = true }, + .offset = 2, + }); + defer mm.destroy(io); + + try expectEqualStrings("is9is9my data123", mm.memory); +}