mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
WIP land the std.Io interface
fix std lib compilation errors caused by introducing std.Io
This commit is contained in:
parent
85a6fea3be
commit
00f26cb0a4
@ -2,12 +2,12 @@ gpa: Allocator,
|
||||
thread_pool: *std.Thread.Pool,
|
||||
graph: *const Build.Graph,
|
||||
all_steps: []const *Build.Step,
|
||||
listen_address: std.net.Address,
|
||||
listen_address: net.IpAddress,
|
||||
ttyconf: std.Io.tty.Config,
|
||||
root_prog_node: std.Progress.Node,
|
||||
watch: bool,
|
||||
|
||||
tcp_server: ?std.net.Server,
|
||||
tcp_server: ?net.Server,
|
||||
serve_thread: ?std.Thread,
|
||||
|
||||
base_timestamp: i128,
|
||||
@ -56,7 +56,7 @@ pub const Options = struct {
|
||||
ttyconf: std.Io.tty.Config,
|
||||
root_prog_node: std.Progress.Node,
|
||||
watch: bool,
|
||||
listen_address: std.net.Address,
|
||||
listen_address: net.IpAddress,
|
||||
};
|
||||
pub fn init(opts: Options) WebServer {
|
||||
// The upcoming `std.Io` interface should allow us to use `Io.async` and `Io.concurrent`
|
||||
@ -244,7 +244,7 @@ pub fn now(s: *const WebServer) i64 {
|
||||
return @intCast(std.time.nanoTimestamp() - s.base_timestamp);
|
||||
}
|
||||
|
||||
fn accept(ws: *WebServer, connection: std.net.Server.Connection) void {
|
||||
fn accept(ws: *WebServer, connection: net.Server.Connection) void {
|
||||
defer connection.stream.close();
|
||||
|
||||
var send_buffer: [4096]u8 = undefined;
|
||||
@ -851,5 +851,6 @@ const Cache = Build.Cache;
|
||||
const Fuzz = Build.Fuzz;
|
||||
const abi = Build.abi;
|
||||
const http = std.http;
|
||||
const net = std.Io.net;
|
||||
|
||||
const WebServer = @This();
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
const File = @This();
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const native_os = builtin.os.tag;
|
||||
const is_windows = native_os == .windows;
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const Io = std.Io;
|
||||
@ -131,6 +133,18 @@ pub const Stat = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn stdout() File {
|
||||
return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdOutput else std.posix.STDOUT_FILENO };
|
||||
}
|
||||
|
||||
pub fn stderr() File {
|
||||
return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdError else std.posix.STDERR_FILENO };
|
||||
}
|
||||
|
||||
pub fn stdin() File {
|
||||
return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdInput else std.posix.STDIN_FILENO };
|
||||
}
|
||||
|
||||
pub const StatError = std.posix.FStatError || Io.Cancelable;
|
||||
|
||||
/// Returns `Stat` containing basic information about the `File`.
|
||||
@ -183,6 +197,11 @@ pub fn write(file: File, io: Io, buffer: []const u8) WriteError!usize {
|
||||
return @errorCast(file.pwrite(io, buffer, -1));
|
||||
}
|
||||
|
||||
pub fn writeAll(file: File, io: Io, bytes: []const u8) WriteError!void {
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) index += try file.write(io, bytes[index..]);
|
||||
}
|
||||
|
||||
pub const PWriteError = std.fs.File.PWriteError || Io.Cancelable;
|
||||
|
||||
pub fn pwrite(file: File, io: Io, buffer: []const u8, offset: std.posix.off_t) PWriteError!usize {
|
||||
@ -350,7 +369,7 @@ pub const Reader = struct {
|
||||
const io = r.io;
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
|
||||
setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
if (std.posix.SEEK == void) {
|
||||
@ -359,7 +378,7 @@ pub const Reader = struct {
|
||||
}
|
||||
const seek_err = r.seek_err orelse e: {
|
||||
if (io.vtable.fileSeekBy(io.userdata, r.file, offset)) |_| {
|
||||
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
|
||||
setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
|
||||
return;
|
||||
} else |err| {
|
||||
r.seek_err = err;
|
||||
@ -384,16 +403,17 @@ pub const Reader = struct {
|
||||
const io = r.io;
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
setPosAdjustingBuffer(r, offset);
|
||||
setLogicalPos(r, offset);
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));
|
||||
const logical_pos = logicalPos(r);
|
||||
if (offset >= logical_pos) return Reader.seekBy(r, @intCast(offset - logical_pos));
|
||||
if (r.seek_err) |err| return err;
|
||||
io.vtable.fileSeekTo(io.userdata, r.file, offset) catch |err| {
|
||||
r.seek_err = err;
|
||||
return err;
|
||||
};
|
||||
setPosAdjustingBuffer(r, offset);
|
||||
setLogicalPos(r, offset);
|
||||
},
|
||||
.failure => return r.seek_err.?,
|
||||
}
|
||||
@ -403,7 +423,7 @@ pub const Reader = struct {
|
||||
return r.pos - r.interface.bufferedLen();
|
||||
}
|
||||
|
||||
fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {
|
||||
fn setLogicalPos(r: *Reader, offset: u64) void {
|
||||
const logical_pos = logicalPos(r);
|
||||
if (offset < logical_pos or offset >= r.pos) {
|
||||
r.interface.seek = 0;
|
||||
@ -544,9 +564,10 @@ pub const Reader = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the stream is at the logical end.
|
||||
pub fn atEnd(r: *Reader) bool {
|
||||
// Even if stat fails, size is set when end is encountered.
|
||||
const size = r.size orelse return false;
|
||||
return size - r.pos == 0;
|
||||
return size - logicalPos(r) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -43,6 +43,14 @@ pub const Protocol = enum(u32) {
|
||||
mptcp = 262,
|
||||
};
|
||||
|
||||
/// Windows 10 added support for unix sockets in build 17063, redstone 4 is the
|
||||
/// first release to support them.
|
||||
pub const has_unix_sockets = switch (native_os) {
|
||||
.windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false,
|
||||
.wasi => false,
|
||||
else => true,
|
||||
};
|
||||
|
||||
pub const IpAddress = union(enum) {
|
||||
ip4: Ip4Address,
|
||||
ip6: Ip6Address,
|
||||
@ -980,7 +988,13 @@ pub const Stream = struct {
|
||||
stream: Stream,
|
||||
err: ?Error,
|
||||
|
||||
pub const Error = std.net.Stream.ReadError || Io.Cancelable || Io.Writer.Error || error{EndOfStream};
|
||||
pub const Error = std.posix.ReadError || error{
|
||||
SocketNotBound,
|
||||
MessageTooBig,
|
||||
NetworkSubsystemFailed,
|
||||
ConnectionResetByPeer,
|
||||
SocketUnconnected,
|
||||
} || Io.Cancelable || Io.Writer.Error || error{EndOfStream};
|
||||
|
||||
pub fn init(stream: Stream, buffer: []u8) Reader {
|
||||
return .{
|
||||
@ -1019,7 +1033,15 @@ pub const Stream = struct {
|
||||
stream: Stream,
|
||||
err: ?Error = null,
|
||||
|
||||
pub const Error = std.net.Stream.WriteError || Io.Cancelable;
|
||||
pub const Error = std.posix.SendMsgError || error{
|
||||
ConnectionResetByPeer,
|
||||
SocketNotBound,
|
||||
MessageTooBig,
|
||||
NetworkSubsystemFailed,
|
||||
SystemResources,
|
||||
SocketUnconnected,
|
||||
Unexpected,
|
||||
} || Io.Cancelable;
|
||||
|
||||
pub fn init(stream: Stream, buffer: []u8) Writer {
|
||||
return .{
|
||||
@ -1096,4 +1118,5 @@ fn testIp6ParseTransform(expected: []const u8, input: []const u8) !void {
|
||||
|
||||
test {
|
||||
_ = HostName;
|
||||
_ = @import("net/test.zig");
|
||||
}
|
||||
|
||||
@ -1,38 +1,38 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const net = std.net;
|
||||
const net = std.Io.net;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
|
||||
test "parse and render IP addresses at comptime" {
|
||||
comptime {
|
||||
const ipv6addr = net.Address.parseIp("::1", 0) catch unreachable;
|
||||
const ipv6addr = net.IpAddress.parseIp("::1", 0) catch unreachable;
|
||||
try std.testing.expectFmt("[::1]:0", "{f}", .{ipv6addr});
|
||||
|
||||
const ipv4addr = net.Address.parseIp("127.0.0.1", 0) catch unreachable;
|
||||
const ipv4addr = net.IpAddress.parseIp("127.0.0.1", 0) catch unreachable;
|
||||
try std.testing.expectFmt("127.0.0.1:0", "{f}", .{ipv4addr});
|
||||
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.Address.parseIp("::123.123.123.123", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.Address.parseIp("127.01.0.1", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.Address.resolveIp("::123.123.123.123", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.Address.resolveIp("127.01.0.1", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.IpAddress.parseIp("::123.123.123.123", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.IpAddress.parseIp("127.01.0.1", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.IpAddress.resolveIp("::123.123.123.123", 0));
|
||||
try testing.expectError(error.InvalidIpAddressFormat, net.IpAddress.resolveIp("127.01.0.1", 0));
|
||||
}
|
||||
}
|
||||
|
||||
test "format IPv6 address with no zero runs" {
|
||||
const addr = try std.net.Address.parseIp6("2001:db8:1:2:3:4:5:6", 0);
|
||||
const addr = try std.net.IpAddress.parseIp6("2001:db8:1:2:3:4:5:6", 0);
|
||||
try std.testing.expectFmt("[2001:db8:1:2:3:4:5:6]:0", "{f}", .{addr});
|
||||
}
|
||||
|
||||
test "parse IPv6 addresses and check compressed form" {
|
||||
try std.testing.expectFmt("[2001:db8::1:0:0:2]:0", "{f}", .{
|
||||
try std.net.Address.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0),
|
||||
try std.net.IpAddress.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0),
|
||||
});
|
||||
try std.testing.expectFmt("[2001:db8::1:2]:0", "{f}", .{
|
||||
try std.net.Address.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0),
|
||||
try std.net.IpAddress.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0),
|
||||
});
|
||||
try std.testing.expectFmt("[2001:db8:1:0:1::2]:0", "{f}", .{
|
||||
try std.net.Address.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0),
|
||||
try std.net.IpAddress.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0),
|
||||
});
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ test "parse IPv6 address, check raw bytes" {
|
||||
0x00, 0x00, 0x00, 0x02, // :0000:0002
|
||||
};
|
||||
|
||||
const addr = try std.net.Address.parseIp6("2001:db8:0000:0000:0001:0000:0000:0002", 0);
|
||||
const addr = try std.net.IpAddress.parseIp6("2001:db8:0000:0000:0001:0000:0000:0002", 0);
|
||||
|
||||
const actual_raw = addr.in6.sa.addr[0..];
|
||||
try std.testing.expectEqualSlices(u8, expected_raw[0..], actual_raw);
|
||||
@ -77,30 +77,30 @@ test "parse and render IPv6 addresses" {
|
||||
"::ffff:123.5.123.5",
|
||||
};
|
||||
for (ips, 0..) |ip, i| {
|
||||
const addr = net.Address.parseIp6(ip, 0) catch unreachable;
|
||||
const addr = net.IpAddress.parseIp6(ip, 0) catch unreachable;
|
||||
var newIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr}) catch unreachable;
|
||||
try std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3]));
|
||||
|
||||
if (builtin.os.tag == .linux) {
|
||||
const addr_via_resolve = net.Address.resolveIp6(ip, 0) catch unreachable;
|
||||
const addr_via_resolve = net.IpAddress.resolveIp6(ip, 0) catch unreachable;
|
||||
var newResolvedIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr_via_resolve}) catch unreachable;
|
||||
try std.testing.expect(std.mem.eql(u8, printed[i], newResolvedIp[1 .. newResolvedIp.len - 3]));
|
||||
}
|
||||
}
|
||||
|
||||
try testing.expectError(error.InvalidCharacter, net.Address.parseIp6(":::", 0));
|
||||
try testing.expectError(error.Overflow, net.Address.parseIp6("FF001::FB", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.Address.parseIp6("FF01::Fb:zig", 0));
|
||||
try testing.expectError(error.InvalidEnd, net.Address.parseIp6("FF01:0:0:0:0:0:0:FB:", 0));
|
||||
try testing.expectError(error.Incomplete, net.Address.parseIp6("FF01:", 0));
|
||||
try testing.expectError(error.InvalidIpv4Mapping, net.Address.parseIp6("::123.123.123.123", 0));
|
||||
try testing.expectError(error.Incomplete, net.Address.parseIp6("1", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp6(":::", 0));
|
||||
try testing.expectError(error.Overflow, net.IpAddress.parseIp6("FF001::FB", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp6("FF01::Fb:zig", 0));
|
||||
try testing.expectError(error.InvalidEnd, net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB:", 0));
|
||||
try testing.expectError(error.Incomplete, net.IpAddress.parseIp6("FF01:", 0));
|
||||
try testing.expectError(error.InvalidIpv4Mapping, net.IpAddress.parseIp6("::123.123.123.123", 0));
|
||||
try testing.expectError(error.Incomplete, net.IpAddress.parseIp6("1", 0));
|
||||
// TODO Make this test pass on other operating systems.
|
||||
if (builtin.os.tag == .linux or comptime builtin.os.tag.isDarwin() or builtin.os.tag == .windows) {
|
||||
try testing.expectError(error.Incomplete, net.Address.resolveIp6("ff01::fb%", 0));
|
||||
try testing.expectError(error.Incomplete, net.IpAddress.resolveIp6("ff01::fb%", 0));
|
||||
// Assumes IFNAMESIZE will always be a multiple of 2
|
||||
try testing.expectError(error.Overflow, net.Address.resolveIp6("ff01::fb%wlp3" ++ "s0" ** @divExact(std.posix.IFNAMESIZE - 4, 2), 0));
|
||||
try testing.expectError(error.Overflow, net.Address.resolveIp6("ff01::fb%12345678901234", 0));
|
||||
try testing.expectError(error.Overflow, net.IpAddress.resolveIp6("ff01::fb%wlp3" ++ "s0" ** @divExact(std.posix.IFNAMESIZE - 4, 2), 0));
|
||||
try testing.expectError(error.Overflow, net.IpAddress.resolveIp6("ff01::fb%12345678901234", 0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ test "invalid but parseable IPv6 scope ids" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testing.expectError(error.InterfaceNotFound, net.Address.resolveIp6("ff01::fb%123s45678901234", 0));
|
||||
try testing.expectError(error.InterfaceNotFound, net.IpAddress.resolveIp6("ff01::fb%123s45678901234", 0));
|
||||
}
|
||||
|
||||
test "parse and render IPv4 addresses" {
|
||||
@ -123,17 +123,17 @@ test "parse and render IPv4 addresses" {
|
||||
"123.255.0.91",
|
||||
"127.0.0.1",
|
||||
}) |ip| {
|
||||
const addr = net.Address.parseIp4(ip, 0) catch unreachable;
|
||||
const addr = net.IpAddress.parseIp4(ip, 0) catch unreachable;
|
||||
var newIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr}) catch unreachable;
|
||||
try std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
|
||||
}
|
||||
|
||||
try testing.expectError(error.Overflow, net.Address.parseIp4("256.0.0.1", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.Address.parseIp4("x.0.0.1", 0));
|
||||
try testing.expectError(error.InvalidEnd, net.Address.parseIp4("127.0.0.1.1", 0));
|
||||
try testing.expectError(error.Incomplete, net.Address.parseIp4("127.0.0.", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.Address.parseIp4("100..0.1", 0));
|
||||
try testing.expectError(error.NonCanonical, net.Address.parseIp4("127.01.0.1", 0));
|
||||
try testing.expectError(error.Overflow, net.IpAddress.parseIp4("256.0.0.1", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("x.0.0.1", 0));
|
||||
try testing.expectError(error.InvalidEnd, net.IpAddress.parseIp4("127.0.0.1.1", 0));
|
||||
try testing.expectError(error.Incomplete, net.IpAddress.parseIp4("127.0.0.", 0));
|
||||
try testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("100..0.1", 0));
|
||||
try testing.expectError(error.NonCanonical, net.IpAddress.parseIp4("127.01.0.1", 0));
|
||||
}
|
||||
|
||||
test "parse and render UNIX addresses" {
|
||||
@ -161,8 +161,8 @@ test "resolve DNS" {
|
||||
|
||||
// Resolve localhost, this should not fail.
|
||||
{
|
||||
const localhost_v4 = try net.Address.parseIp("127.0.0.1", 80);
|
||||
const localhost_v6 = try net.Address.parseIp("::2", 80);
|
||||
const localhost_v4 = try net.IpAddress.parseIp("127.0.0.1", 80);
|
||||
const localhost_v6 = try net.IpAddress.parseIp("::2", 80);
|
||||
|
||||
const result = try net.getAddressList(testing.allocator, "localhost", 80);
|
||||
defer result.deinit();
|
||||
@ -198,13 +198,13 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
|
||||
// Try only the IPv4 variant as some CI builders have no IPv6 localhost
|
||||
// configured.
|
||||
const localhost = try net.Address.parseIp("127.0.0.1", 0);
|
||||
const localhost = try net.IpAddress.parseIp("127.0.0.1", 0);
|
||||
|
||||
var server = try localhost.listen(.{});
|
||||
defer server.deinit();
|
||||
|
||||
const S = struct {
|
||||
fn clientFn(server_address: net.Address) !void {
|
||||
fn clientFn(server_address: net.IpAddress) !void {
|
||||
const socket = try net.tcpConnectToAddress(server_address);
|
||||
defer socket.close();
|
||||
|
||||
@ -232,7 +232,7 @@ test "listen on an in use port" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
const localhost = try net.Address.parseIp("127.0.0.1", 0);
|
||||
const localhost = try net.IpAddress.parseIp("127.0.0.1", 0);
|
||||
|
||||
var server1 = try localhost.listen(.{ .reuse_address = true });
|
||||
defer server1.deinit();
|
||||
@ -253,7 +253,7 @@ fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyer
|
||||
try testing.expect(mem.eql(u8, msg, "hello from server\n"));
|
||||
}
|
||||
|
||||
fn testClient(addr: net.Address) anyerror!void {
|
||||
fn testClient(addr: net.IpAddress) anyerror!void {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const socket_file = try net.tcpConnectToAddress(addr);
|
||||
@ -290,7 +290,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
|
||||
const socket_path = try generateFileName("socket.unix");
|
||||
defer testing.allocator.free(socket_path);
|
||||
|
||||
const socket_addr = try net.Address.initUnix(socket_path);
|
||||
const socket_addr = try net.IpAddress.initUnix(socket_path);
|
||||
defer std.fs.cwd().deleteFile(socket_path) catch {};
|
||||
|
||||
var server = try socket_addr.listen(.{});
|
||||
@ -351,7 +351,7 @@ test "non-blocking tcp server" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
const localhost = try net.Address.parseIp("127.0.0.1", 0);
|
||||
const localhost = try net.IpAddress.parseIp("127.0.0.1", 0);
|
||||
var server = localhost.listen(.{ .force_nonblocking = true });
|
||||
defer server.deinit();
|
||||
|
||||
@ -523,9 +523,7 @@ pub fn setStatus(new_status: Status) void {
|
||||
|
||||
/// Returns whether a resize is needed to learn the terminal size.
|
||||
fn wait(timeout_ns: u64) bool {
|
||||
const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|
|
||||
true
|
||||
else |err| switch (err) {
|
||||
const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_| true else |err| switch (err) {
|
||||
error.Timeout => false,
|
||||
};
|
||||
global_progress.redraw_event.reset();
|
||||
|
||||
@ -71,7 +71,7 @@ pub const ResetEvent = enum(u32) {
|
||||
///
|
||||
/// The memory accesses before the set() can be said to happen before
|
||||
/// timedWait() returns without error.
|
||||
pub fn timedWait(re: *ResetEvent, timeout_ns: u64) void {
|
||||
pub fn timedWait(re: *ResetEvent, timeout_ns: u64) error{Timeout}!void {
|
||||
if (builtin.single_threaded) switch (re.*) {
|
||||
.unset => {
|
||||
sleep(timeout_ns);
|
||||
@ -1774,9 +1774,9 @@ test "setName, getName" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
const Context = struct {
|
||||
start_wait_event: ResetEvent = .{},
|
||||
test_done_event: ResetEvent = .{},
|
||||
thread_done_event: ResetEvent = .{},
|
||||
start_wait_event: ResetEvent = .unset,
|
||||
test_done_event: ResetEvent = .unset,
|
||||
thread_done_event: ResetEvent = .unset,
|
||||
|
||||
done: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
|
||||
thread: Thread = undefined,
|
||||
@ -1843,7 +1843,7 @@ test join {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var value: usize = 0;
|
||||
var event = ResetEvent{};
|
||||
var event: ResetEvent = .unset;
|
||||
|
||||
const thread = try Thread.spawn(.{}, testIncrementNotify, .{ &value, &event });
|
||||
thread.join();
|
||||
@ -1855,7 +1855,7 @@ test detach {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var value: usize = 0;
|
||||
var event = ResetEvent{};
|
||||
var event: ResetEvent = .unset;
|
||||
|
||||
const thread = try Thread.spawn(.{}, testIncrementNotify, .{ &value, &event });
|
||||
thread.detach();
|
||||
@ -1902,8 +1902,7 @@ fn testTls() !void {
|
||||
}
|
||||
|
||||
test "ResetEvent smoke test" {
|
||||
// make sure the event is unset
|
||||
var event = ResetEvent{};
|
||||
var event: ResetEvent = .unset;
|
||||
try testing.expectEqual(false, event.isSet());
|
||||
|
||||
// make sure the event gets set
|
||||
@ -1932,8 +1931,8 @@ test "ResetEvent signaling" {
|
||||
}
|
||||
|
||||
const Context = struct {
|
||||
in: ResetEvent = .{},
|
||||
out: ResetEvent = .{},
|
||||
in: ResetEvent = .unset,
|
||||
out: ResetEvent = .unset,
|
||||
value: usize = 0,
|
||||
|
||||
fn input(self: *@This()) !void {
|
||||
@ -1994,7 +1993,7 @@ test "ResetEvent broadcast" {
|
||||
|
||||
const num_threads = 10;
|
||||
const Barrier = struct {
|
||||
event: ResetEvent = .{},
|
||||
event: ResetEvent = .unset,
|
||||
counter: std.atomic.Value(usize) = std.atomic.Value(usize).init(num_threads),
|
||||
|
||||
fn wait(self: *@This()) void {
|
||||
|
||||
@ -97,25 +97,6 @@ pub const base64_encoder = base64.Base64Encoder.init(base64_alphabet, null);
|
||||
/// Base64 decoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.
|
||||
pub const base64_decoder = base64.Base64Decoder.init(base64_alphabet, null);
|
||||
|
||||
/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path`
|
||||
/// are absolute. See `Dir.updateFile` for a function that operates on both
|
||||
/// absolute and relative paths.
|
||||
/// On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// On WASI, both paths should be encoded as valid UTF-8.
|
||||
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn updateFileAbsolute(
|
||||
source_path: []const u8,
|
||||
dest_path: []const u8,
|
||||
args: Dir.CopyFileOptions,
|
||||
) !std.Io.Dir.PrevStatus {
|
||||
assert(path.isAbsolute(source_path));
|
||||
assert(path.isAbsolute(dest_path));
|
||||
const my_cwd = cwd();
|
||||
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args);
|
||||
}
|
||||
|
||||
test updateFileAbsolute {}
|
||||
|
||||
/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path`
|
||||
/// are absolute. See `Dir.copyFile` for a function that operates on both
|
||||
/// absolute and relative paths.
|
||||
|
||||
@ -698,17 +698,6 @@ pub fn read(self: File, buffer: []u8) ReadError!usize {
|
||||
return posix.read(self.handle, buffer);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Reader`.
|
||||
pub fn readAll(self: File, buffer: []u8) ReadError!usize {
|
||||
var index: usize = 0;
|
||||
while (index != buffer.len) {
|
||||
const amt = try self.read(buffer[index..]);
|
||||
if (amt == 0) break;
|
||||
index += amt;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/// On Windows, this function currently does alter the file pointer.
|
||||
/// https://github.com/ziglang/zig/issues/12783
|
||||
pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
|
||||
@ -719,17 +708,6 @@ pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
|
||||
return posix.pread(self.handle, buffer, offset);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Reader`.
|
||||
pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize {
|
||||
var index: usize = 0;
|
||||
while (index != buffer.len) {
|
||||
const amt = try self.pread(buffer[index..], offset + index);
|
||||
if (amt == 0) break;
|
||||
index += amt;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/// See https://github.com/ziglang/zig/issues/7699
|
||||
pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize {
|
||||
if (is_windows) {
|
||||
@ -741,36 +719,6 @@ pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize {
|
||||
return posix.readv(self.handle, iovecs);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Reader`.
|
||||
pub fn readvAll(self: File, iovecs: []posix.iovec) ReadError!usize {
|
||||
if (iovecs.len == 0) return 0;
|
||||
|
||||
// We use the address of this local variable for all zero-length
|
||||
// vectors so that the OS does not complain that we are giving it
|
||||
// addresses outside the application's address space.
|
||||
var garbage: [1]u8 = undefined;
|
||||
for (iovecs) |*v| {
|
||||
if (v.len == 0) v.base = &garbage;
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
var off: usize = 0;
|
||||
while (true) {
|
||||
var amt = try self.readv(iovecs[i..]);
|
||||
var eof = amt == 0;
|
||||
off += amt;
|
||||
while (amt >= iovecs[i].len) {
|
||||
amt -= iovecs[i].len;
|
||||
i += 1;
|
||||
if (i >= iovecs.len) return off;
|
||||
eof = false;
|
||||
}
|
||||
if (eof) return off;
|
||||
iovecs[i].base += amt;
|
||||
iovecs[i].len -= amt;
|
||||
}
|
||||
}
|
||||
|
||||
/// See https://github.com/ziglang/zig/issues/7699
|
||||
/// On Windows, this function currently does alter the file pointer.
|
||||
/// https://github.com/ziglang/zig/issues/12783
|
||||
@ -784,28 +732,6 @@ pub fn preadv(self: File, iovecs: []const posix.iovec, offset: u64) PReadError!u
|
||||
return posix.preadv(self.handle, iovecs, offset);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Reader`.
|
||||
pub fn preadvAll(self: File, iovecs: []posix.iovec, offset: u64) PReadError!usize {
|
||||
if (iovecs.len == 0) return 0;
|
||||
|
||||
var i: usize = 0;
|
||||
var off: usize = 0;
|
||||
while (true) {
|
||||
var amt = try self.preadv(iovecs[i..], offset + off);
|
||||
var eof = amt == 0;
|
||||
off += amt;
|
||||
while (amt >= iovecs[i].len) {
|
||||
amt -= iovecs[i].len;
|
||||
i += 1;
|
||||
if (i >= iovecs.len) return off;
|
||||
eof = false;
|
||||
}
|
||||
if (eof) return off;
|
||||
iovecs[i].base += amt;
|
||||
iovecs[i].len -= amt;
|
||||
}
|
||||
}
|
||||
|
||||
pub const WriteError = posix.WriteError;
|
||||
pub const PWriteError = posix.PWriteError;
|
||||
|
||||
@ -817,7 +743,6 @@ pub fn write(self: File, bytes: []const u8) WriteError!usize {
|
||||
return posix.write(self.handle, bytes);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Writer`.
|
||||
pub fn writeAll(self: File, bytes: []const u8) WriteError!void {
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) {
|
||||
@ -835,14 +760,6 @@ pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
|
||||
return posix.pwrite(self.handle, bytes, offset);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Writer`.
|
||||
pub fn pwriteAll(self: File, bytes: []const u8, offset: u64) PWriteError!void {
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) {
|
||||
index += try self.pwrite(bytes[index..], offset + index);
|
||||
}
|
||||
}
|
||||
|
||||
/// See https://github.com/ziglang/zig/issues/7699
|
||||
pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize {
|
||||
if (is_windows) {
|
||||
@ -855,31 +772,6 @@ pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize {
|
||||
return posix.writev(self.handle, iovecs);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Writer`.
|
||||
pub fn writevAll(self: File, iovecs: []posix.iovec_const) WriteError!void {
|
||||
if (iovecs.len == 0) return;
|
||||
|
||||
// We use the address of this local variable for all zero-length
|
||||
// vectors so that the OS does not complain that we are giving it
|
||||
// addresses outside the application's address space.
|
||||
var garbage: [1]u8 = undefined;
|
||||
for (iovecs) |*v| {
|
||||
if (v.len == 0) v.base = &garbage;
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
var amt = try self.writev(iovecs[i..]);
|
||||
while (amt >= iovecs[i].len) {
|
||||
amt -= iovecs[i].len;
|
||||
i += 1;
|
||||
if (i >= iovecs.len) return;
|
||||
}
|
||||
iovecs[i].base += amt;
|
||||
iovecs[i].len -= amt;
|
||||
}
|
||||
}
|
||||
|
||||
/// See https://github.com/ziglang/zig/issues/7699
|
||||
/// On Windows, this function currently does alter the file pointer.
|
||||
/// https://github.com/ziglang/zig/issues/12783
|
||||
@ -893,485 +785,8 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError
|
||||
return posix.pwritev(self.handle, iovecs, offset);
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Writer`.
|
||||
pub fn pwritevAll(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError!void {
|
||||
if (iovecs.len == 0) return;
|
||||
var i: usize = 0;
|
||||
var off: u64 = 0;
|
||||
while (true) {
|
||||
var amt = try self.pwritev(iovecs[i..], offset + off);
|
||||
off += amt;
|
||||
while (amt >= iovecs[i].len) {
|
||||
amt -= iovecs[i].len;
|
||||
i += 1;
|
||||
if (i >= iovecs.len) return;
|
||||
}
|
||||
iovecs[i].base += amt;
|
||||
iovecs[i].len -= amt;
|
||||
}
|
||||
}
|
||||
|
||||
pub const CopyRangeError = posix.CopyFileRangeError;
|
||||
|
||||
/// Deprecated in favor of `Writer`.
|
||||
pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
|
||||
const adjusted_len = math.cast(usize, len) orelse maxInt(usize);
|
||||
const result = try posix.copy_file_range(in.handle, in_offset, out.handle, out_offset, adjusted_len, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Writer`.
|
||||
pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
|
||||
var total_bytes_copied: u64 = 0;
|
||||
var in_off = in_offset;
|
||||
var out_off = out_offset;
|
||||
while (total_bytes_copied < len) {
|
||||
const amt_copied = try copyRange(in, in_off, out, out_off, len - total_bytes_copied);
|
||||
if (amt_copied == 0) return total_bytes_copied;
|
||||
total_bytes_copied += amt_copied;
|
||||
in_off += amt_copied;
|
||||
out_off += amt_copied;
|
||||
}
|
||||
return total_bytes_copied;
|
||||
}
|
||||
|
||||
/// Memoizes key information about a file handle such as:
|
||||
/// * The size from calling stat, or the error that occurred therein.
|
||||
/// * The current seek position.
|
||||
/// * The error that occurred when trying to seek.
|
||||
/// * Whether reading should be done positionally or streaming.
|
||||
/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`)
|
||||
/// versus plain variants (e.g. `read`).
|
||||
///
|
||||
/// Fulfills the `std.Io.Reader` interface.
|
||||
pub const Reader = struct {
|
||||
file: File,
|
||||
err: ?ReadError = null,
|
||||
mode: Reader.Mode = .positional,
|
||||
/// Tracks the true seek position in the file. To obtain the logical
|
||||
/// position, use `logicalPos`.
|
||||
pos: u64 = 0,
|
||||
size: ?u64 = null,
|
||||
size_err: ?SizeError = null,
|
||||
seek_err: ?Reader.SeekError = null,
|
||||
interface: std.Io.Reader,
|
||||
|
||||
pub const SizeError = std.os.windows.GetFileSizeError || StatError || error{
|
||||
/// Occurs if, for example, the file handle is a network socket and therefore does not have a size.
|
||||
Streaming,
|
||||
};
|
||||
|
||||
pub const SeekError = File.SeekError || error{
|
||||
/// Seeking fell back to reading, and reached the end before the requested seek position.
|
||||
/// `pos` remains at the end of the file.
|
||||
EndOfStream,
|
||||
/// Seeking fell back to reading, which failed.
|
||||
ReadFailed,
|
||||
};
|
||||
|
||||
pub const Mode = enum {
|
||||
streaming,
|
||||
positional,
|
||||
/// Avoid syscalls other than `read` and `readv`.
|
||||
streaming_reading,
|
||||
/// Avoid syscalls other than `pread` and `preadv`.
|
||||
positional_reading,
|
||||
/// Indicates reading cannot continue because of a seek failure.
|
||||
failure,
|
||||
|
||||
pub fn toStreaming(m: @This()) @This() {
|
||||
return switch (m) {
|
||||
.positional, .streaming => .streaming,
|
||||
.positional_reading, .streaming_reading => .streaming_reading,
|
||||
.failure => .failure,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toReading(m: @This()) @This() {
|
||||
return switch (m) {
|
||||
.positional, .positional_reading => .positional_reading,
|
||||
.streaming, .streaming_reading => .streaming_reading,
|
||||
.failure => .failure,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn initInterface(buffer: []u8) std.Io.Reader {
|
||||
return .{
|
||||
.vtable = &.{
|
||||
.stream = Reader.stream,
|
||||
.discard = Reader.discard,
|
||||
.readVec = Reader.readVec,
|
||||
},
|
||||
.buffer = buffer,
|
||||
.seek = 0,
|
||||
.end = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(file: File, buffer: []u8) Reader {
|
||||
return .{
|
||||
.file = file,
|
||||
.interface = initInterface(buffer),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn initSize(file: File, buffer: []u8, size: ?u64) Reader {
|
||||
return .{
|
||||
.file = file,
|
||||
.interface = initInterface(buffer),
|
||||
.size = size,
|
||||
};
|
||||
}
|
||||
|
||||
/// Positional is more threadsafe, since the global seek position is not
|
||||
/// affected, but when such syscalls are not available, preemptively
|
||||
/// initializing in streaming mode skips a failed syscall.
|
||||
pub fn initStreaming(file: File, buffer: []u8) Reader {
|
||||
return .{
|
||||
.file = file,
|
||||
.interface = Reader.initInterface(buffer),
|
||||
.mode = .streaming,
|
||||
.seek_err = error.Unseekable,
|
||||
.size_err = error.Streaming,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getSize(r: *Reader) SizeError!u64 {
|
||||
return r.size orelse {
|
||||
if (r.size_err) |err| return err;
|
||||
if (is_windows) {
|
||||
if (windows.GetFileSizeEx(r.file.handle)) |size| {
|
||||
r.size = size;
|
||||
return size;
|
||||
} else |err| {
|
||||
r.size_err = err;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (posix.Stat == void) {
|
||||
r.size_err = error.Streaming;
|
||||
return error.Streaming;
|
||||
}
|
||||
if (stat(r.file)) |st| {
|
||||
if (st.kind == .file) {
|
||||
r.size = st.size;
|
||||
return st.size;
|
||||
} else {
|
||||
r.mode = r.mode.toStreaming();
|
||||
r.size_err = error.Streaming;
|
||||
return error.Streaming;
|
||||
}
|
||||
} else |err| {
|
||||
r.size_err = err;
|
||||
return err;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
if (posix.SEEK == void) {
|
||||
r.seek_err = error.Unseekable;
|
||||
return error.Unseekable;
|
||||
}
|
||||
const seek_err = r.seek_err orelse e: {
|
||||
if (posix.lseek_CUR(r.file.handle, offset)) |_| {
|
||||
setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
|
||||
return;
|
||||
} else |err| {
|
||||
r.seek_err = err;
|
||||
break :e err;
|
||||
}
|
||||
};
|
||||
var remaining = std.math.cast(u64, offset) orelse return seek_err;
|
||||
while (remaining > 0) {
|
||||
remaining -= discard(&r.interface, .limited64(remaining)) catch |err| {
|
||||
r.seek_err = err;
|
||||
return err;
|
||||
};
|
||||
}
|
||||
r.interface.seek = 0;
|
||||
r.interface.end = 0;
|
||||
},
|
||||
.failure => return r.seek_err.?,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
setLogicalPos(r, offset);
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
const logical_pos = logicalPos(r);
|
||||
if (offset >= logical_pos) return Reader.seekBy(r, @intCast(offset - logical_pos));
|
||||
if (r.seek_err) |err| return err;
|
||||
posix.lseek_SET(r.file.handle, offset) catch |err| {
|
||||
r.seek_err = err;
|
||||
return err;
|
||||
};
|
||||
setLogicalPos(r, offset);
|
||||
},
|
||||
.failure => return r.seek_err.?,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn logicalPos(r: *const Reader) u64 {
|
||||
return r.pos - r.interface.bufferedLen();
|
||||
}
|
||||
|
||||
fn setLogicalPos(r: *Reader, offset: u64) void {
|
||||
const logical_pos = logicalPos(r);
|
||||
if (offset < logical_pos or offset >= r.pos) {
|
||||
r.interface.seek = 0;
|
||||
r.interface.end = 0;
|
||||
r.pos = offset;
|
||||
} else {
|
||||
const logical_delta: usize = @intCast(offset - logical_pos);
|
||||
r.interface.seek += logical_delta;
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of slices to store on the stack, when trying to send as many byte
|
||||
/// vectors through the underlying read calls as possible.
|
||||
const max_buffers_len = 16;
|
||||
|
||||
fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
|
||||
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
|
||||
switch (r.mode) {
|
||||
.positional, .streaming => @panic("TODO"),
|
||||
.positional_reading => {
|
||||
const dest = limit.slice(try w.writableSliceGreedy(1));
|
||||
var data: [1][]u8 = .{dest};
|
||||
const n = try readVecPositional(r, &data);
|
||||
w.advance(n);
|
||||
return n;
|
||||
},
|
||||
.streaming_reading => {
|
||||
const dest = limit.slice(try w.writableSliceGreedy(1));
|
||||
var data: [1][]u8 = .{dest};
|
||||
const n = try readVecStreaming(r, &data);
|
||||
w.advance(n);
|
||||
return n;
|
||||
},
|
||||
.failure => return error.ReadFailed,
|
||||
}
|
||||
}
|
||||
|
||||
fn readVec(io_reader: *std.Io.Reader, data: [][]u8) std.Io.Reader.Error!usize {
|
||||
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => return readVecPositional(r, data),
|
||||
.streaming, .streaming_reading => return readVecStreaming(r, data),
|
||||
.failure => return error.ReadFailed,
|
||||
}
|
||||
}
|
||||
|
||||
fn readVecPositional(r: *Reader, data: [][]u8) std.Io.Reader.Error!usize {
|
||||
const io_reader = &r.interface;
|
||||
if (is_windows) {
|
||||
// Unfortunately, `ReadFileScatter` cannot be used since it
|
||||
// requires page alignment.
|
||||
if (io_reader.seek == io_reader.end) {
|
||||
io_reader.seek = 0;
|
||||
io_reader.end = 0;
|
||||
}
|
||||
const first = data[0];
|
||||
if (first.len >= io_reader.buffer.len - io_reader.end) {
|
||||
return readPositional(r, first);
|
||||
} else {
|
||||
io_reader.end += try readPositional(r, io_reader.buffer[io_reader.end..]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
|
||||
const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
|
||||
const dest = iovecs_buffer[0..dest_n];
|
||||
assert(dest[0].len > 0);
|
||||
const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) {
|
||||
error.Unseekable => {
|
||||
r.mode = r.mode.toStreaming();
|
||||
const pos = r.pos;
|
||||
if (pos != 0) {
|
||||
r.pos = 0;
|
||||
r.seekBy(@intCast(pos)) catch {
|
||||
r.mode = .failure;
|
||||
return error.ReadFailed;
|
||||
};
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
else => |e| {
|
||||
r.err = e;
|
||||
return error.ReadFailed;
|
||||
},
|
||||
};
|
||||
if (n == 0) {
|
||||
r.size = r.pos;
|
||||
return error.EndOfStream;
|
||||
}
|
||||
r.pos += n;
|
||||
if (n > data_size) {
|
||||
io_reader.end += n - data_size;
|
||||
return data_size;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
fn readVecStreaming(r: *Reader, data: [][]u8) std.Io.Reader.Error!usize {
|
||||
const io_reader = &r.interface;
|
||||
if (is_windows) {
|
||||
// Unfortunately, `ReadFileScatter` cannot be used since it
|
||||
// requires page alignment.
|
||||
if (io_reader.seek == io_reader.end) {
|
||||
io_reader.seek = 0;
|
||||
io_reader.end = 0;
|
||||
}
|
||||
const first = data[0];
|
||||
if (first.len >= io_reader.buffer.len - io_reader.end) {
|
||||
return readStreaming(r, first);
|
||||
} else {
|
||||
io_reader.end += try readStreaming(r, io_reader.buffer[io_reader.end..]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
|
||||
const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
|
||||
const dest = iovecs_buffer[0..dest_n];
|
||||
assert(dest[0].len > 0);
|
||||
const n = posix.readv(r.file.handle, dest) catch |err| {
|
||||
r.err = err;
|
||||
return error.ReadFailed;
|
||||
};
|
||||
if (n == 0) {
|
||||
r.size = r.pos;
|
||||
return error.EndOfStream;
|
||||
}
|
||||
r.pos += n;
|
||||
if (n > data_size) {
|
||||
io_reader.end += n - data_size;
|
||||
return data_size;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
fn discard(io_reader: *std.Io.Reader, limit: std.Io.Limit) std.Io.Reader.Error!usize {
|
||||
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
|
||||
const file = r.file;
|
||||
const pos = r.pos;
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
const size = r.getSize() catch {
|
||||
r.mode = r.mode.toStreaming();
|
||||
return 0;
|
||||
};
|
||||
const delta = @min(@intFromEnum(limit), size - pos);
|
||||
r.pos = pos + delta;
|
||||
return delta;
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
// Unfortunately we can't seek forward without knowing the
|
||||
// size because the seek syscalls provided to us will not
|
||||
// return the true end position if a seek would exceed the
|
||||
// end.
|
||||
fallback: {
|
||||
if (r.size_err == null and r.seek_err == null) break :fallback;
|
||||
var trash_buffer: [128]u8 = undefined;
|
||||
if (is_windows) {
|
||||
const n = windows.ReadFile(file.handle, limit.slice(&trash_buffer), null) catch |err| {
|
||||
r.err = err;
|
||||
return error.ReadFailed;
|
||||
};
|
||||
if (n == 0) {
|
||||
r.size = pos;
|
||||
return error.EndOfStream;
|
||||
}
|
||||
r.pos = pos + n;
|
||||
return n;
|
||||
}
|
||||
var iovecs: [max_buffers_len]std.posix.iovec = undefined;
|
||||
var iovecs_i: usize = 0;
|
||||
var remaining = @intFromEnum(limit);
|
||||
while (remaining > 0 and iovecs_i < iovecs.len) {
|
||||
iovecs[iovecs_i] = .{ .base = &trash_buffer, .len = @min(trash_buffer.len, remaining) };
|
||||
remaining -= iovecs[iovecs_i].len;
|
||||
iovecs_i += 1;
|
||||
}
|
||||
const n = posix.readv(file.handle, iovecs[0..iovecs_i]) catch |err| {
|
||||
r.err = err;
|
||||
return error.ReadFailed;
|
||||
};
|
||||
if (n == 0) {
|
||||
r.size = pos;
|
||||
return error.EndOfStream;
|
||||
}
|
||||
r.pos = pos + n;
|
||||
return n;
|
||||
}
|
||||
const size = r.getSize() catch return 0;
|
||||
const n = @min(size - pos, maxInt(i64), @intFromEnum(limit));
|
||||
file.seekBy(n) catch |err| {
|
||||
r.seek_err = err;
|
||||
return 0;
|
||||
};
|
||||
r.pos = pos + n;
|
||||
return n;
|
||||
},
|
||||
.failure => return error.ReadFailed,
|
||||
}
|
||||
}
|
||||
|
||||
fn readPositional(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
|
||||
const n = r.file.pread(dest, r.pos) catch |err| switch (err) {
|
||||
error.Unseekable => {
|
||||
r.mode = r.mode.toStreaming();
|
||||
const pos = r.pos;
|
||||
if (pos != 0) {
|
||||
r.pos = 0;
|
||||
r.seekBy(@intCast(pos)) catch {
|
||||
r.mode = .failure;
|
||||
return error.ReadFailed;
|
||||
};
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
else => |e| {
|
||||
r.err = e;
|
||||
return error.ReadFailed;
|
||||
},
|
||||
};
|
||||
if (n == 0) {
|
||||
r.size = r.pos;
|
||||
return error.EndOfStream;
|
||||
}
|
||||
r.pos += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
fn readStreaming(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
|
||||
const n = r.file.read(dest) catch |err| {
|
||||
r.err = err;
|
||||
return error.ReadFailed;
|
||||
};
|
||||
if (n == 0) {
|
||||
r.size = r.pos;
|
||||
return error.EndOfStream;
|
||||
}
|
||||
r.pos += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
pub fn atEnd(r: *Reader) bool {
|
||||
// Even if stat fails, size is set when end is encountered.
|
||||
const size = r.size orelse return false;
|
||||
return size - r.pos == 0;
|
||||
}
|
||||
};
|
||||
/// Deprecated in favor of `std.Io.File.Reader`.
|
||||
pub const Reader = std.Io.File.Reader;
|
||||
|
||||
pub const Writer = struct {
|
||||
file: File,
|
||||
|
||||
2424
lib/std/net.zig
2424
lib/std/net.zig
File diff suppressed because it is too large
Load Diff
@ -85,7 +85,6 @@ pub const macho = @import("macho.zig");
|
||||
pub const math = @import("math.zig");
|
||||
pub const mem = @import("mem.zig");
|
||||
pub const meta = @import("meta.zig");
|
||||
pub const net = @import("net.zig");
|
||||
pub const os = @import("os.zig");
|
||||
pub const once = @import("once.zig").once;
|
||||
pub const pdb = @import("pdb.zig");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user