One cool thing which you can do with std.Io is to create versions of it with have some functions disabled. For example, let’s say you have parts of your code which you don’t want to have file system access. Here is NoFileIo.zig:
const std = @import("std");
const NoFileIo = @This();
vtable: std.Io.VTable,
userdata: ?*anyopaque,
pub fn init(base_io: std.Io) NoFileIo {
var self = NoFileIo{
.vtable = base_io.vtable.*,
.userdata = base_io.userdata,
};
const failing = std.Io.failing.vtable;
// Set all file and directory operations to fail.
self.vtable.dirCreateDir = failing.dirCreateDir;
self.vtable.dirCreateDirPath = failing.dirCreateDirPath;
self.vtable.dirCreateDirPathOpen = failing.dirCreateDirPathOpen;
self.vtable.dirOpenDir = failing.dirOpenDir;
self.vtable.dirStat = failing.dirStat;
self.vtable.dirStatFile = failing.dirStatFile;
self.vtable.dirAccess = failing.dirAccess;
self.vtable.dirCreateFile = failing.dirCreateFile;
self.vtable.dirCreateFileAtomic = failing.dirCreateFileAtomic;
self.vtable.dirOpenFile = failing.dirOpenFile;
self.vtable.dirClose = failing.dirClose;
self.vtable.dirRead = failing.dirRead;
self.vtable.dirRealPath = failing.dirRealPath;
self.vtable.dirRealPathFile = failing.dirRealPathFile;
self.vtable.dirDeleteFile = failing.dirDeleteFile;
self.vtable.dirDeleteDir = failing.dirDeleteDir;
self.vtable.dirRename = failing.dirRename;
self.vtable.dirRenamePreserve = failing.dirRenamePreserve;
self.vtable.dirSymLink = failing.dirSymLink;
self.vtable.dirReadLink = failing.dirReadLink;
self.vtable.dirSetOwner = failing.dirSetOwner;
self.vtable.dirSetFileOwner = failing.dirSetFileOwner;
self.vtable.dirSetPermissions = failing.dirSetPermissions;
self.vtable.dirSetFilePermissions = failing.dirSetFilePermissions;
self.vtable.dirSetTimestamps = failing.dirSetTimestamps;
self.vtable.dirHardLink = failing.dirHardLink;
self.vtable.fileStat = failing.fileStat;
self.vtable.fileLength = failing.fileLength;
self.vtable.fileClose = failing.fileClose;
self.vtable.fileWritePositional = failing.fileWritePositional;
self.vtable.fileWriteFileStreaming = failing.fileWriteFileStreaming;
self.vtable.fileWriteFilePositional = failing.fileWriteFilePositional;
self.vtable.fileReadPositional = failing.fileReadPositional;
self.vtable.fileSeekBy = failing.fileSeekBy;
self.vtable.fileSeekTo = failing.fileSeekTo;
self.vtable.fileSync = failing.fileSync;
self.vtable.fileIsTty = failing.fileIsTty;
self.vtable.fileEnableAnsiEscapeCodes = failing.fileEnableAnsiEscapeCodes;
self.vtable.fileSupportsAnsiEscapeCodes = failing.fileSupportsAnsiEscapeCodes;
self.vtable.fileSetLength = failing.fileSetLength;
self.vtable.fileSetOwner = failing.fileSetOwner;
self.vtable.fileSetPermissions = failing.fileSetPermissions;
self.vtable.fileSetTimestamps = failing.fileSetTimestamps;
self.vtable.fileLock = failing.fileLock;
self.vtable.fileTryLock = failing.fileTryLock;
self.vtable.fileUnlock = failing.fileUnlock;
self.vtable.fileDowngradeLock = failing.fileDowngradeLock;
self.vtable.fileRealPath = failing.fileRealPath;
self.vtable.fileHardLink = failing.fileHardLink;
self.vtable.fileMemoryMapCreate = failing.fileMemoryMapCreate;
self.vtable.fileMemoryMapDestroy = failing.fileMemoryMapDestroy;
self.vtable.fileMemoryMapSetLength = failing.fileMemoryMapSetLength;
self.vtable.fileMemoryMapRead = failing.fileMemoryMapRead;
self.vtable.fileMemoryMapWrite = failing.fileMemoryMapWrite;
self.vtable.processExecutableOpen = failing.processExecutableOpen;
self.vtable.processExecutablePath = failing.processExecutablePath;
self.vtable.progressParentFile = failing.progressParentFile;
self.vtable.netWriteFile = failing.netWriteFile;
return self;
}
pub fn io(self: *NoFileIo) std.Io {
return .{
.userdata = self.userdata,
.vtable = &self.vtable,
};
}
test "NoFileIo errors when accessing files" {
var no_file_io = NoFileIo.init(std.testing.io);
const nf_io = no_file_io.io();
try std.testing.expectError(error.FileNotFound, std.Io.Dir.openDir(.cwd(), nf_io, "nonexistent", .{}));
}
test "NoFileIo can still do randomness" {
var no_file_io = NoFileIo.init(std.testing.io);
const nf_io = no_file_io.io();
var buf: [4]u8 = undefined;
nf_io.random(&buf);
}
If course one can get around this by just using a new std.Io.Theaded instance instead of the one that was passed down. I think it would be nice if one could disallow using certain parts of the standard library in build.zig on a per-module basis. (also C imports, inline assembly…)
What do you folks think of this?