feature. See also
. The project being documented here (as the example) is the Zig library itself.
Dispatch.fileWriteFileStreaming
fn fileWriteFileStreaming(
userdata: ?*anyopaque,
file: File,
header: []const u8,
file_reader: *File.Reader,
limit: Io.Limit,
) File.Writer.WriteFileError!usize
File
Code
fn fileWriteFileStreaming(
userdata: ?*anyopaque,
file: File,
header: []const u8,
file_reader: *File.Reader,
limit: Io.Limit,
) File.Writer.WriteFileError!usize {
const ev: *Evented = @ptrCast(@alignCast(userdata));
const reader_buffered = file_reader.interface.buffered();
if (reader_buffered.len >= @backingInt(limit)) {
const n = try fileWriteStreaming(ev, file, header, &.{limit.slice(reader_buffered)}, 1);
file_reader.interface.toss(n -| header.len);
return n;
}
const file_limit = @backingInt(limit) - reader_buffered.len;
const out_fd = file.handle;
const in_fd = file_reader.file.handle;
if (file_reader.size) |size| {
if (size - file_reader.pos == 0) {
if (reader_buffered.len != 0) {
const n = try fileWriteStreaming(ev, file, header, &.{limit.slice(reader_buffered)}, 1);
file_reader.interface.toss(n -| header.len);
return n;
} else {
return error.EndOfStream;
}
}
}
if (@atomicLoad(UseSendfile, &ev.use_sendfile, .monotonic) == .disabled) return error.Unimplemented;
const offset = std.math.cast(c.off_t, file_reader.pos) orelse return error.Unimplemented;
var hdtr_data: c.sf_hdtr = undefined;
var headers: [2]iovec_const = undefined;
var headers_i: u8 = 0;
if (header.len != 0) {
headers[headers_i] = .{ .base = header.ptr, .len = header.len };
headers_i += 1;
}
if (reader_buffered.len != 0) {
headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len };
headers_i += 1;
}
const hdtr: ?*c.sf_hdtr = if (headers_i == 0) null else b: {
hdtr_data = .{
.headers = &headers,
.hdr_cnt = headers_i,
.trailers = null,
.trl_cnt = 0,
};
break :b &hdtr_data;
};
const max_count = std.math.maxInt(i32);
var len: c.off_t = @min(file_limit, max_count);
const flags = 0;
while (true) switch (c.errno(c.sendfile(in_fd, out_fd, offset, &len, hdtr, flags))) {
.SUCCESS => break,
.OPNOTSUPP, .NOTSOCK, .NOSYS => {
// something else.
@atomicStore(UseSendfile, &ev.use_sendfile, .disabled, .monotonic);
return 0;
},
.INTR => if (len > 0) break,
.AGAIN => {
if (len == 0) return error.WouldBlock;
break;
},
else => |e| {
assert(error.Unexpected == switch (e) {
.NOTCONN => return error.BrokenPipe,
.IO => return error.InputOutput,
.PIPE => return error.BrokenPipe,
.BADF => |err| errnoBug(err),
.FAULT => |err| errnoBug(err),
.INVAL => |err| errnoBug(err),
else => |err| unexpectedErrno(err),
});
// something else.
@atomicStore(UseSendfile, &ev.use_sendfile, .disabled, .monotonic);
return 0;
},
};
if (len == 0) {
file_reader.size = file_reader.pos;
return error.EndOfStream;
}
const u_len: usize = @bitCast(len);
file_reader.interface.toss(u_len -| header.len);
return u_len;
}