mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 03:24:46 +01:00
659 lines
34 KiB
Zig
659 lines
34 KiB
Zig
const Debug = @This();
|
|
|
|
impl: Io,
|
|
|
|
/// It is safe for this to be a `std.Thread.Mutex` because it does not guard any
|
|
/// `Io` operations, only data structure accesses. Using an `Io.Mutex` would be
|
|
/// undesirable as it may significantly change the scheduling behavior of the
|
|
/// application.
|
|
mutex: std.Thread.Mutex,
|
|
|
|
gpa: Allocator,
|
|
oom_count: u32,
|
|
open_files: std.AutoArrayHashMapUnmanaged(Io.File.Handle, StackTrace) = .empty,
|
|
open_dirs: std.AutoArrayHashMapUnmanaged(Io.Dir.Handle, StackTrace) = .empty,
|
|
|
|
const StackTrace = struct { index: usize, buf: [6]usize };
|
|
|
|
pub fn init(impl: Io, gpa: Allocator) Debug {
|
|
return .{
|
|
.impl = impl,
|
|
.mutex = .{},
|
|
.gpa = gpa,
|
|
.oom_count = 0,
|
|
.open_files = .empty,
|
|
.open_dirs = .empty,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(dbg: *Debug) void {
|
|
if (dbg.oom_count > 0) {
|
|
std.log.warn("ran out of memory to track {d} handles; some leaks may not be detected", .{dbg.oom_count});
|
|
}
|
|
for (dbg.open_files.keys(), dbg.open_files.values()) |handle, *st| {
|
|
std.log.err("file handle '{any}' leaked: {f}", .{
|
|
handle,
|
|
@as(std.debug.FormatStackTrace, .{
|
|
.stack_trace = .{ .instruction_addresses = &st.buf, .index = st.index },
|
|
.terminal_mode = std.log.terminalMode(),
|
|
}),
|
|
});
|
|
}
|
|
for (dbg.open_dirs.keys(), dbg.open_dirs.values()) |handle, *st| {
|
|
std.log.err("dir handle '{any}' leaked: {f}", .{
|
|
handle,
|
|
@as(std.debug.FormatStackTrace, .{
|
|
.stack_trace = .{ .instruction_addresses = &st.buf, .index = st.index },
|
|
.terminal_mode = std.log.terminalMode(),
|
|
}),
|
|
});
|
|
}
|
|
dbg.open_files.deinit(dbg.gpa);
|
|
dbg.open_dirs.deinit(dbg.gpa);
|
|
}
|
|
|
|
pub fn io(dbg: *Debug) Io {
|
|
return .{
|
|
.userdata = dbg,
|
|
.vtable = &.{
|
|
.async = &async,
|
|
.concurrent = &concurrent,
|
|
.await = &await,
|
|
.cancel = &cancel,
|
|
.select = &select,
|
|
|
|
.groupAsync = &groupAsync,
|
|
.groupConcurrent = &groupConcurrent,
|
|
.groupAwait = &groupAwait,
|
|
.groupCancel = &groupCancel,
|
|
|
|
.recancel = &recancel,
|
|
.swapCancelProtection = &swapCancelProtection,
|
|
.checkCancel = &checkCancel,
|
|
|
|
.futexWait = &futexWait,
|
|
.futexWaitUncancelable = &futexWaitUncancelable,
|
|
.futexWake = &futexWake,
|
|
|
|
.dirCreateDir = &dirCreateDir,
|
|
.dirCreateDirPath = &dirCreateDirPath,
|
|
.dirCreateDirPathOpen = &dirCreateDirPathOpen,
|
|
.dirOpenDir = &dirOpenDir,
|
|
.dirStat = &dirStat,
|
|
.dirStatFile = &dirStatFile,
|
|
.dirAccess = &dirAccess,
|
|
.dirCreateFile = &dirCreateFile,
|
|
.dirCreateFileAtomic = &dirCreateFileAtomic,
|
|
.dirOpenFile = &dirOpenFile,
|
|
.dirClose = &dirClose,
|
|
.dirRead = &dirRead,
|
|
.dirRealPath = &dirRealPath,
|
|
.dirRealPathFile = &dirRealPathFile,
|
|
.dirDeleteFile = &dirDeleteFile,
|
|
.dirDeleteDir = &dirDeleteDir,
|
|
.dirRename = &dirRename,
|
|
.dirRenamePreserve = &dirRenamePreserve,
|
|
.dirSymLink = &dirSymLink,
|
|
.dirReadLink = &dirReadLink,
|
|
.dirSetOwner = &dirSetOwner,
|
|
.dirSetFileOwner = &dirSetFileOwner,
|
|
.dirSetPermissions = &dirSetPermissions,
|
|
.dirSetFilePermissions = &dirSetFilePermissions,
|
|
.dirSetTimestamps = &dirSetTimestamps,
|
|
.dirHardLink = &dirHardLink,
|
|
|
|
.fileStat = &fileStat,
|
|
.fileLength = &fileLength,
|
|
.fileClose = &fileClose,
|
|
.fileWriteStreaming = &fileWriteStreaming,
|
|
.fileWritePositional = &fileWritePositional,
|
|
.fileWriteFileStreaming = &fileWriteFileStreaming,
|
|
.fileWriteFilePositional = &fileWriteFilePositional,
|
|
.fileReadStreaming = &fileReadStreaming,
|
|
.fileReadPositional = &fileReadPositional,
|
|
.fileSeekBy = &fileSeekBy,
|
|
.fileSeekTo = &fileSeekTo,
|
|
.fileSync = &fileSync,
|
|
.fileIsTty = &fileIsTty,
|
|
.fileEnableAnsiEscapeCodes = &fileEnableAnsiEscapeCodes,
|
|
.fileSupportsAnsiEscapeCodes = &fileSupportsAnsiEscapeCodes,
|
|
.fileSetLength = &fileSetLength,
|
|
.fileSetOwner = &fileSetOwner,
|
|
.fileSetPermissions = &fileSetPermissions,
|
|
.fileSetTimestamps = &fileSetTimestamps,
|
|
.fileLock = &fileLock,
|
|
.fileTryLock = &fileTryLock,
|
|
.fileUnlock = &fileUnlock,
|
|
.fileDowngradeLock = &fileDowngradeLock,
|
|
.fileRealPath = &fileRealPath,
|
|
.fileHardLink = &fileHardLink,
|
|
|
|
.processExecutableOpen = &processExecutableOpen,
|
|
.processExecutablePath = &processExecutablePath,
|
|
.lockStderr = &lockStderr,
|
|
.tryLockStderr = &tryLockStderr,
|
|
.unlockStderr = &unlockStderr,
|
|
.processSetCurrentDir = &processSetCurrentDir,
|
|
.processReplace = &processReplace,
|
|
.processReplacePath = &processReplacePath,
|
|
.processSpawn = &processSpawn,
|
|
.processSpawnPath = &processSpawnPath,
|
|
.childWait = &childWait,
|
|
.childKill = &childKill,
|
|
|
|
.progressParentFile = &progressParentFile,
|
|
|
|
.now = &now,
|
|
.sleep = &sleep,
|
|
|
|
.random = &random,
|
|
.randomSecure = &randomSecure,
|
|
|
|
.netListenIp = &netListenIp,
|
|
.netAccept = &netAccept,
|
|
.netBindIp = &netBindIp,
|
|
.netConnectIp = &netConnectIp,
|
|
.netListenUnix = &netListenUnix,
|
|
.netConnectUnix = &netConnectUnix,
|
|
.netSend = &netSend,
|
|
.netReceive = &netReceive,
|
|
|
|
.netRead = &netRead,
|
|
.netWrite = &netWrite,
|
|
.netWriteFile = &netWriteFile,
|
|
.netClose = &netClose,
|
|
.netShutdown = &netShutdown,
|
|
.netInterfaceNameResolve = &netInterfaceNameResolve,
|
|
.netInterfaceName = &netInterfaceName,
|
|
.netLookup = &netLookup,
|
|
},
|
|
};
|
|
}
|
|
|
|
fn trackOpenFile(dbg: *Debug, file: Io.File, ra: usize) void {
|
|
dbg.mutex.lock();
|
|
defer dbg.mutex.unlock();
|
|
const gop = dbg.open_files.getOrPut(dbg.gpa, file.handle) catch |err| switch (err) {
|
|
error.OutOfMemory => {
|
|
dbg.oom_count += 1;
|
|
return;
|
|
},
|
|
};
|
|
assert(!gop.found_existing); // underlying implementation returned duplicate handle
|
|
const st = std.debug.captureCurrentStackTrace(.{ .first_address = ra }, &gop.value_ptr.buf);
|
|
gop.value_ptr.index = st.index;
|
|
}
|
|
|
|
fn trackCloseFile(dbg: *Debug, file: Io.File, ra: usize) void {
|
|
dbg.mutex.lock();
|
|
defer dbg.mutex.unlock();
|
|
if (!dbg.open_files.swapRemove(file.handle)) {
|
|
// If there was an OOM we might have failed to track the handle, but otherwise this is
|
|
// definitely incorrect usage.
|
|
if (dbg.oom_count == 0) {
|
|
std.debug.panicExtra(ra, "attempted to close file handle '{any}' which is not open", .{file.handle});
|
|
}
|
|
}
|
|
}
|
|
|
|
fn trackOpenDir(dbg: *Debug, dir: Io.Dir, ra: usize) void {
|
|
dbg.mutex.lock();
|
|
defer dbg.mutex.unlock();
|
|
const gop = dbg.open_dirs.getOrPut(dbg.gpa, dir.handle) catch |err| switch (err) {
|
|
error.OutOfMemory => {
|
|
dbg.oom_count += 1;
|
|
return;
|
|
},
|
|
};
|
|
assert(!gop.found_existing); // underlying implementation returned duplicate handle
|
|
const st = std.debug.captureCurrentStackTrace(.{ .first_address = ra }, &gop.value_ptr.buf);
|
|
gop.value_ptr.index = st.index;
|
|
}
|
|
|
|
fn trackCloseDir(dbg: *Debug, dir: Io.Dir, ra: usize) void {
|
|
dbg.mutex.lock();
|
|
defer dbg.mutex.unlock();
|
|
if (!dbg.open_dirs.swapRemove(dir.handle)) {
|
|
// If there was an OOM we might have failed to track the handle, but otherwise this is
|
|
// definitely incorrect usage.
|
|
if (dbg.oom_count == 0) {
|
|
std.debug.panicExtra(ra, "attempted to close dir handle '{any}' which is not open", .{dir.handle});
|
|
}
|
|
}
|
|
}
|
|
|
|
fn async(userdata: ?*anyopaque, result: []u8, result_alignment: std.mem.Alignment, context: []const u8, context_alignment: std.mem.Alignment, start: *const fn (context: *const anyopaque, result: *anyopaque) void) ?*Io.AnyFuture {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.async(dbg.impl.userdata, result, result_alignment, context, context_alignment, start);
|
|
}
|
|
|
|
fn concurrent(userdata: ?*anyopaque, result_len: usize, result_alignment: std.mem.Alignment, context: []const u8, context_alignment: std.mem.Alignment, start: *const fn (context: *const anyopaque, result: *anyopaque) void) Io.ConcurrentError!*Io.AnyFuture {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.concurrent(dbg.impl.userdata, result_len, result_alignment, context, context_alignment, start);
|
|
}
|
|
|
|
fn await(userdata: ?*anyopaque, any_future: *Io.AnyFuture, result: []u8, result_alignment: std.mem.Alignment) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.await(dbg.impl.userdata, any_future, result, result_alignment);
|
|
}
|
|
|
|
fn cancel(userdata: ?*anyopaque, any_future: *Io.AnyFuture, result: []u8, result_alignment: std.mem.Alignment) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.cancel(dbg.impl.userdata, any_future, result, result_alignment);
|
|
}
|
|
|
|
fn groupAsync(userdata: ?*anyopaque, group: *Io.Group, context: []const u8, context_alignment: std.mem.Alignment, start: *const fn (context: *const anyopaque) Cancelable!void) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.groupAsync(dbg.impl.userdata, group, context, context_alignment, start);
|
|
}
|
|
|
|
fn groupConcurrent(userdata: ?*anyopaque, group: *Io.Group, context: []const u8, context_alignment: std.mem.Alignment, start: *const fn (context: *const anyopaque) Cancelable!void) Io.ConcurrentError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.groupConcurrent(dbg.impl.userdata, group, context, context_alignment, start);
|
|
}
|
|
fn groupAwait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) Cancelable!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.groupAwait(dbg.impl.userdata, group, token);
|
|
}
|
|
fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.groupCancel(dbg.impl.userdata, group, token);
|
|
}
|
|
|
|
fn recancel(userdata: ?*anyopaque) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.recancel(dbg.impl.userdata);
|
|
}
|
|
fn swapCancelProtection(userdata: ?*anyopaque, new: Io.CancelProtection) Io.CancelProtection {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.swapCancelProtection(dbg.impl.userdata, new);
|
|
}
|
|
fn checkCancel(userdata: ?*anyopaque) Cancelable!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.checkCancel(dbg.impl.userdata);
|
|
}
|
|
|
|
fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) Cancelable!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.select(dbg.impl.userdata, futures);
|
|
}
|
|
|
|
fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.Timeout) Cancelable!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.futexWait(dbg.impl.userdata, ptr, expected, timeout);
|
|
}
|
|
fn futexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.futexWaitUncancelable(dbg.impl.userdata, ptr, expected);
|
|
}
|
|
fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.futexWake(dbg.impl.userdata, ptr, max_waiters);
|
|
}
|
|
|
|
fn dirCreateDir(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, permissions: Io.Dir.Permissions) Io.Dir.CreateDirError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirCreateDir(dbg.impl.userdata, dir, sub_path, permissions);
|
|
}
|
|
fn dirCreateDirPath(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, permissions: Io.Dir.Permissions) Io.Dir.CreateDirPathError!Io.Dir.CreatePathStatus {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirCreateDirPath(dbg.impl.userdata, dir, sub_path, permissions);
|
|
}
|
|
fn dirCreateDirPathOpen(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, permissions: Io.Dir.Permissions, options: Io.Dir.OpenOptions) Io.Dir.CreateDirPathOpenError!Io.Dir {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
const new_dir = try dbg.impl.vtable.dirCreateDirPathOpen(dbg.impl.userdata, dir, sub_path, permissions, options);
|
|
dbg.trackOpenDir(new_dir, @returnAddress());
|
|
return new_dir;
|
|
}
|
|
fn dirOpenDir(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, options: Io.Dir.OpenOptions) Io.Dir.OpenError!Io.Dir {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
const new_dir = try dbg.impl.vtable.dirOpenDir(dbg.impl.userdata, dir, sub_path, options);
|
|
dbg.trackOpenDir(new_dir, @returnAddress());
|
|
return new_dir;
|
|
}
|
|
fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirStat(dbg.impl.userdata, dir);
|
|
}
|
|
fn dirStatFile(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, options: Io.Dir.StatFileOptions) Io.Dir.StatFileError!Io.File.Stat {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirStatFile(dbg.impl.userdata, dir, sub_path, options);
|
|
}
|
|
fn dirAccess(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, options: Io.Dir.AccessOptions) Io.Dir.AccessError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirAccess(dbg.impl.userdata, dir, sub_path, options);
|
|
}
|
|
fn dirCreateFile(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, flags: Io.File.CreateFlags) Io.File.OpenError!Io.File {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
const file = try dbg.impl.vtable.dirCreateFile(dbg.impl.userdata, dir, sub_path, flags);
|
|
dbg.trackOpenFile(file, @returnAddress());
|
|
return file;
|
|
}
|
|
fn dirCreateFileAtomic(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, options: Io.Dir.CreateFileAtomicOptions) Io.Dir.CreateFileAtomicError!Io.File.Atomic {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
const af = try dbg.impl.vtable.dirCreateFileAtomic(dbg.impl.userdata, dir, sub_path, options);
|
|
if (af.file_open) dbg.trackOpenFile(af.file, @returnAddress());
|
|
return af;
|
|
}
|
|
fn dirOpenFile(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, flags: Io.File.OpenFlags) Io.File.OpenError!Io.File {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
const file = try dbg.impl.vtable.dirOpenFile(dbg.impl.userdata, dir, sub_path, flags);
|
|
dbg.trackOpenFile(file, @returnAddress());
|
|
return file;
|
|
}
|
|
fn dirClose(userdata: ?*anyopaque, dirs: []const Io.Dir) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
for (dirs) |dir| dbg.trackCloseDir(dir, @returnAddress());
|
|
return dbg.impl.vtable.dirClose(dbg.impl.userdata, dirs);
|
|
}
|
|
fn dirRead(userdata: ?*anyopaque, dr: *Io.Dir.Reader, buffer: []Io.Dir.Entry) Io.Dir.Reader.Error!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirRead(dbg.impl.userdata, dr, buffer);
|
|
}
|
|
fn dirRealPath(userdata: ?*anyopaque, dir: Io.Dir, out_buffer: []u8) Io.Dir.RealPathError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirRealPath(dbg.impl.userdata, dir, out_buffer);
|
|
}
|
|
fn dirRealPathFile(userdata: ?*anyopaque, dir: Io.Dir, path_name: []const u8, out_buffer: []u8) Io.Dir.RealPathFileError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirRealPathFile(dbg.impl.userdata, dir, path_name, out_buffer);
|
|
}
|
|
fn dirDeleteFile(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir.DeleteFileError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirDeleteFile(dbg.impl.userdata, dir, sub_path);
|
|
}
|
|
fn dirDeleteDir(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir.DeleteDirError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirDeleteDir(dbg.impl.userdata, dir, sub_path);
|
|
}
|
|
fn dirRename(userdata: ?*anyopaque, old_dir: Io.Dir, old_sub_path: []const u8, new_dir: Io.Dir, new_sub_path: []const u8) Io.Dir.RenameError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirRename(dbg.impl.userdata, old_dir, old_sub_path, new_dir, new_sub_path);
|
|
}
|
|
fn dirRenamePreserve(userdata: ?*anyopaque, old_dir: Io.Dir, old_sub_path: []const u8, new_dir: Io.Dir, new_sub_path: []const u8) Io.Dir.RenamePreserveError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirRenamePreserve(dbg.impl.userdata, old_dir, old_sub_path, new_dir, new_sub_path);
|
|
}
|
|
fn dirSymLink(userdata: ?*anyopaque, dir: Io.Dir, target_path: []const u8, sym_link_path: []const u8, flags: Io.Dir.SymLinkFlags) Io.Dir.SymLinkError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirSymLink(dbg.impl.userdata, dir, target_path, sym_link_path, flags);
|
|
}
|
|
fn dirReadLink(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, buffer: []u8) Io.Dir.ReadLinkError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirReadLink(dbg.impl.userdata, dir, sub_path, buffer);
|
|
}
|
|
fn dirSetOwner(userdata: ?*anyopaque, dir: Io.Dir, uid: ?Io.File.Uid, gid: ?Io.File.Gid) Io.Dir.SetOwnerError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirSetOwner(dbg.impl.userdata, dir, uid, gid);
|
|
}
|
|
fn dirSetFileOwner(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, uid: ?Io.File.Uid, gid: ?Io.File.Gid, options: Io.Dir.SetFileOwnerOptions) Io.Dir.SetFileOwnerError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirSetFileOwner(dbg.impl.userdata, dir, sub_path, uid, gid, options);
|
|
}
|
|
fn dirSetPermissions(userdata: ?*anyopaque, dir: Io.Dir, permissions: Io.Dir.Permissions) Io.Dir.SetPermissionsError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirSetPermissions(dbg.impl.userdata, dir, permissions);
|
|
}
|
|
fn dirSetFilePermissions(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, permissions: Io.File.Permissions, options: Io.Dir.SetFilePermissionsOptions) Io.Dir.SetFilePermissionsError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirSetFilePermissions(dbg.impl.userdata, dir, sub_path, permissions, options);
|
|
}
|
|
fn dirSetTimestamps(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, options: Io.Dir.SetTimestampsOptions) Io.Dir.SetTimestampsError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirSetTimestamps(dbg.impl.userdata, dir, sub_path, options);
|
|
}
|
|
fn dirHardLink(userdata: ?*anyopaque, old_dir: Io.Dir, old_sub_path: []const u8, new_dir: Io.Dir, new_sub_path: []const u8, options: Io.Dir.HardLinkOptions) Io.Dir.HardLinkError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.dirHardLink(dbg.impl.userdata, old_dir, old_sub_path, new_dir, new_sub_path, options);
|
|
}
|
|
|
|
fn fileStat(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileStat(dbg.impl.userdata, file);
|
|
}
|
|
fn fileLength(userdata: ?*anyopaque, file: Io.File) Io.File.LengthError!u64 {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileLength(dbg.impl.userdata, file);
|
|
}
|
|
fn fileClose(userdata: ?*anyopaque, files: []const Io.File) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
for (files) |file| dbg.trackCloseFile(file, @returnAddress());
|
|
return dbg.impl.vtable.fileClose(dbg.impl.userdata, files);
|
|
}
|
|
fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, header: []const u8, data: []const []const u8, splat: usize) Io.File.Writer.Error!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileWriteStreaming(dbg.impl.userdata, file, header, data, splat);
|
|
}
|
|
fn fileWritePositional(userdata: ?*anyopaque, file: Io.File, header: []const u8, data: []const []const u8, splat: usize, offset: u64) Io.File.WritePositionalError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileWritePositional(dbg.impl.userdata, file, header, data, splat, offset);
|
|
}
|
|
fn fileWriteFileStreaming(userdata: ?*anyopaque, file: Io.File, header: []const u8, fr: *Io.File.Reader, limit: Io.Limit) Io.File.Writer.WriteFileError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileWriteFileStreaming(dbg.impl.userdata, file, header, fr, limit);
|
|
}
|
|
fn fileWriteFilePositional(userdata: ?*anyopaque, file: Io.File, header: []const u8, fr: *Io.File.Reader, limit: Io.Limit, offset: u64) Io.File.WriteFilePositionalError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileWriteFilePositional(dbg.impl.userdata, file, header, fr, limit, offset);
|
|
}
|
|
|
|
fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: []const []u8) Io.File.Reader.Error!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileReadStreaming(dbg.impl.userdata, file, data);
|
|
}
|
|
|
|
fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: []const []u8, offset: u64) Io.File.ReadPositionalError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileReadPositional(dbg.impl.userdata, file, data, offset);
|
|
}
|
|
fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, relative_offset: i64) Io.File.SeekError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSeekBy(dbg.impl.userdata, file, relative_offset);
|
|
}
|
|
fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, absolute_offset: u64) Io.File.SeekError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSeekTo(dbg.impl.userdata, file, absolute_offset);
|
|
}
|
|
fn fileSync(userdata: ?*anyopaque, file: Io.File) Io.File.SyncError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSync(dbg.impl.userdata, file);
|
|
}
|
|
fn fileIsTty(userdata: ?*anyopaque, file: Io.File) Cancelable!bool {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileIsTty(dbg.impl.userdata, file);
|
|
}
|
|
fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: Io.File) Io.File.EnableAnsiEscapeCodesError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileEnableAnsiEscapeCodes(dbg.impl.userdata, file);
|
|
}
|
|
fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: Io.File) Cancelable!bool {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSupportsAnsiEscapeCodes(dbg.impl.userdata, file);
|
|
}
|
|
fn fileSetLength(userdata: ?*anyopaque, file: Io.File, length: u64) Io.File.SetLengthError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSetLength(dbg.impl.userdata, file, length);
|
|
}
|
|
fn fileSetOwner(userdata: ?*anyopaque, file: Io.File, uid: ?Io.File.Uid, gid: ?Io.File.Gid) Io.File.SetOwnerError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSetOwner(dbg.impl.userdata, file, uid, gid);
|
|
}
|
|
fn fileSetPermissions(userdata: ?*anyopaque, file: Io.File, permissions: Io.File.Permissions) Io.File.SetPermissionsError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSetPermissions(dbg.impl.userdata, file, permissions);
|
|
}
|
|
fn fileSetTimestamps(userdata: ?*anyopaque, file: Io.File, options: Io.File.SetTimestampsOptions) Io.File.SetTimestampsError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileSetTimestamps(dbg.impl.userdata, file, options);
|
|
}
|
|
fn fileLock(userdata: ?*anyopaque, file: Io.File, lock: Io.File.Lock) Io.File.LockError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileLock(dbg.impl.userdata, file, lock);
|
|
}
|
|
fn fileTryLock(userdata: ?*anyopaque, file: Io.File, lock: Io.File.Lock) Io.File.LockError!bool {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileTryLock(dbg.impl.userdata, file, lock);
|
|
}
|
|
fn fileUnlock(userdata: ?*anyopaque, file: Io.File) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileUnlock(dbg.impl.userdata, file);
|
|
}
|
|
fn fileDowngradeLock(userdata: ?*anyopaque, file: Io.File) Io.File.DowngradeLockError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileDowngradeLock(dbg.impl.userdata, file);
|
|
}
|
|
fn fileRealPath(userdata: ?*anyopaque, file: Io.File, out_buffer: []u8) Io.File.RealPathError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileRealPath(dbg.impl.userdata, file, out_buffer);
|
|
}
|
|
fn fileHardLink(userdata: ?*anyopaque, file: Io.File, dir: Io.Dir, sub_path: []const u8, options: Io.File.HardLinkOptions) Io.File.HardLinkError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.fileHardLink(dbg.impl.userdata, file, dir, sub_path, options);
|
|
}
|
|
|
|
fn processExecutableOpen(userdata: ?*anyopaque, flags: Io.File.OpenFlags) std.process.OpenExecutableError!Io.File {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
const file = try dbg.impl.vtable.processExecutableOpen(dbg.impl.userdata, flags);
|
|
dbg.trackOpenFile(file, @returnAddress());
|
|
return file;
|
|
}
|
|
fn processExecutablePath(userdata: ?*anyopaque, buffer: []u8) std.process.ExecutablePathError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.processExecutablePath(dbg.impl.userdata, buffer);
|
|
}
|
|
fn lockStderr(userdata: ?*anyopaque, mode: ?Io.Terminal.Mode) Cancelable!Io.LockedStderr {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.lockStderr(dbg.impl.userdata, mode);
|
|
}
|
|
fn tryLockStderr(userdata: ?*anyopaque, mode: ?Io.Terminal.Mode) Cancelable!?Io.LockedStderr {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.tryLockStderr(dbg.impl.userdata, mode);
|
|
}
|
|
fn unlockStderr(userdata: ?*anyopaque) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.unlockStderr(dbg.impl.userdata);
|
|
}
|
|
fn processSetCurrentDir(userdata: ?*anyopaque, dir: Io.Dir) std.process.SetCurrentDirError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.processSetCurrentDir(dbg.impl.userdata, dir);
|
|
}
|
|
fn processReplace(userdata: ?*anyopaque, options: std.process.ReplaceOptions) std.process.ReplaceError {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.processReplace(dbg.impl.userdata, options);
|
|
}
|
|
fn processReplacePath(userdata: ?*anyopaque, dir: Io.Dir, options: std.process.ReplaceOptions) std.process.ReplaceError {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.processReplacePath(dbg.impl.userdata, dir, options);
|
|
}
|
|
fn processSpawn(userdata: ?*anyopaque, options: std.process.SpawnOptions) std.process.SpawnError!std.process.Child {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.processSpawn(dbg.impl.userdata, options);
|
|
}
|
|
fn processSpawnPath(userdata: ?*anyopaque, dir: Io.Dir, options: std.process.SpawnOptions) std.process.SpawnError!std.process.Child {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.processSpawnPath(dbg.impl.userdata, dir, options);
|
|
}
|
|
fn childWait(userdata: ?*anyopaque, child: *std.process.Child) std.process.Child.WaitError!std.process.Child.Term {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.childWait(dbg.impl.userdata, child);
|
|
}
|
|
fn childKill(userdata: ?*anyopaque, child: *std.process.Child) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.childKill(dbg.impl.userdata, child);
|
|
}
|
|
|
|
fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!Io.File {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.progressParentFile(dbg.impl.userdata);
|
|
}
|
|
|
|
fn now(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.now(dbg.impl.userdata, clock);
|
|
}
|
|
fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.sleep(dbg.impl.userdata, timeout);
|
|
}
|
|
|
|
fn random(userdata: ?*anyopaque, buffer: []u8) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.random(dbg.impl.userdata, buffer);
|
|
}
|
|
fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.randomSecure(dbg.impl.userdata, buffer);
|
|
}
|
|
|
|
fn netListenIp(userdata: ?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netListenIp(dbg.impl.userdata, address, options);
|
|
}
|
|
fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle) net.Server.AcceptError!net.Stream {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netAccept(dbg.impl.userdata, server);
|
|
}
|
|
fn netBindIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netBindIp(dbg.impl.userdata, address, options);
|
|
}
|
|
fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netConnectIp(dbg.impl.userdata, address, options);
|
|
}
|
|
fn netListenUnix(userdata: ?*anyopaque, address: *const net.UnixAddress, options: net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netListenUnix(dbg.impl.userdata, address, options);
|
|
}
|
|
fn netConnectUnix(userdata: ?*anyopaque, address: *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netConnectUnix(dbg.impl.userdata, address);
|
|
}
|
|
fn netSend(userdata: ?*anyopaque, handle: net.Socket.Handle, messages: []net.OutgoingMessage, flags: net.SendFlags) struct { ?net.Socket.SendError, usize } {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netSend(dbg.impl.userdata, handle, messages, flags);
|
|
}
|
|
fn netReceive(userdata: ?*anyopaque, handle: net.Socket.Handle, message_buffer: []net.IncomingMessage, data_buffer: []u8, flags: net.ReceiveFlags, timeout: Io.Timeout) struct { ?net.Socket.ReceiveTimeoutError, usize } {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netReceive(dbg.impl.userdata, handle, message_buffer, data_buffer, flags, timeout);
|
|
}
|
|
|
|
fn netRead(userdata: ?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netRead(dbg.impl.userdata, src, data);
|
|
}
|
|
fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netWrite(dbg.impl.userdata, dest, header, data, splat);
|
|
}
|
|
fn netWriteFile(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, fr: *Io.File.Reader, limit: Io.Limit) net.Stream.Writer.WriteFileError!usize {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netWriteFile(dbg.impl.userdata, dest, header, fr, limit);
|
|
}
|
|
fn netClose(userdata: ?*anyopaque, handle: []const net.Socket.Handle) void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netClose(dbg.impl.userdata, handle);
|
|
}
|
|
fn netShutdown(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netShutdown(dbg.impl.userdata, handle, how);
|
|
}
|
|
fn netInterfaceNameResolve(userdata: ?*anyopaque, name: *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netInterfaceNameResolve(dbg.impl.userdata, name);
|
|
}
|
|
fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netInterfaceName(dbg.impl.userdata, interface);
|
|
}
|
|
fn netLookup(userdata: ?*anyopaque, host_name: net.HostName, resolved: *Io.Queue(net.HostName.LookupResult), options: net.HostName.LookupOptions) net.HostName.LookupError!void {
|
|
const dbg: *Debug = @ptrCast(@alignCast(userdata));
|
|
return dbg.impl.vtable.netLookup(dbg.impl.userdata, host_name, resolved, options);
|
|
}
|
|
|
|
const std = @import("../std.zig");
|
|
const Allocator = std.mem.Allocator;
|
|
const Cancelable = Io.Cancelable;
|
|
const Io = std.Io;
|
|
const assert = std.debug.assert;
|
|
const net = Io.net;
|