authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-13 20:57:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:26-07:00
logc872a9fd49b090efc5b6132ec0ab959d7fe8e70f
tree82a6d9e386bd803e7552b7efe4cf1d295fd9955a
parentf3d0fc7a66fa40e86036e7c626231e7de265cd64

std.net.Stream: implement Reader


2 files changed, 57 insertions(+), 43 deletions(-)

lib/std/fs/File.zig+2-2
......@@ -1631,7 +1631,7 @@ fn posReadVec(context: *anyopaque, data: []const []u8, offset: u64) anyerror!std
16311631 };
16321632}
16331633
1634fn streamRead(
1634pub fn streamRead(
16351635 context: ?*anyopaque,
16361636 bw: *std.io.BufferedWriter,
16371637 limit: std.io.Reader.Limit,
......@@ -1644,7 +1644,7 @@ fn streamRead(
16441644 };
16451645}
16461646
1647fn streamReadVec(context: ?*anyopaque, data: []const []u8) anyerror!std.io.Reader.Status {
1647pub fn streamReadVec(context: ?*anyopaque, data: []const []u8) anyerror!std.io.Reader.Status {
16481648 const handle = opaqueToHandle(context);
16491649
16501650 if (is_windows) {
lib/std/net.zig+55-41
......@@ -1837,10 +1837,20 @@ pub const Stream = struct {
18371837 Unexpected,
18381838 };
18391839
1840 pub const Reader = io.Reader(Stream, ReadError, read);
1841
1842 pub fn reader(self: Stream) Reader {
1843 return .{ .context = self };
1840 pub fn reader(stream: Stream) std.io.Reader {
1841 return .{
1842 .context = handleToOpaque(stream.handle),
1843 .vtable = switch (native_os) {
1844 .windows => &.{
1845 .read = windows_read,
1846 .readv = windows_readv,
1847 },
1848 else => &.{
1849 .read = std.fs.File.streamRead,
1850 .readv = std.fs.File.streamReadVec,
1851 },
1852 },
1853 };
18441854 }
18451855
18461856 pub fn writer(stream: Stream) std.io.Writer {
......@@ -1859,46 +1869,50 @@ pub const Stream = struct {
18591869 };
18601870 }
18611871
1862 pub fn read(self: Stream, buffer: []u8) ReadError!usize {
1863 if (native_os == .windows) {
1864 return windows.ReadFile(self.handle, buffer, null);
1865 }
1866
1867 return posix.read(self.handle, buffer);
1868 }
1869
1870 pub fn readv(s: Stream, iovecs: []const posix.iovec) ReadError!usize {
1871 if (native_os == .windows) {
1872 // TODO improve this to use ReadFileScatter
1873 if (iovecs.len == 0) return @as(usize, 0);
1874 const first = iovecs[0];
1875 return windows.ReadFile(s.handle, first.base[0..first.len], null);
1876 }
1877
1878 return posix.readv(s.handle, iovecs);
1879 }
1880
1881 /// Returns the number of bytes read. If the number read is smaller than
1882 /// `buffer.len`, it means the stream reached the end. Reaching the end of
1883 /// a stream is not an error condition.
1884 pub fn readAll(s: Stream, buffer: []u8) ReadError!usize {
1885 return readAtLeast(s, buffer, buffer.len);
1872 fn windows_read(
1873 context: ?*anyopaque,
1874 bw: *std.io.BufferedWriter,
1875 limit: std.io.Reader.Limit,
1876 ) anyerror!std.io.Reader.Status {
1877 const buf = limit.slice(try bw.writableSlice(1));
1878 const status = try windows_readv(context, &.{buf});
1879 bw.advance(status.len);
1880 return status;
18861881 }
18871882
1888 /// Returns the number of bytes read, calling the underlying read function
1889 /// the minimal number of times until the buffer has at least `len` bytes
1890 /// filled. If the number read is less than `len` it means the stream
1891 /// reached the end. Reaching the end of the stream is not an error
1892 /// condition.
1893 pub fn readAtLeast(s: Stream, buffer: []u8, len: usize) ReadError!usize {
1894 assert(len <= buffer.len);
1895 var index: usize = 0;
1896 while (index < len) {
1897 const amt = try s.read(buffer[index..]);
1898 if (amt == 0) break;
1899 index += amt;
1883 fn windows_readv(context: ?*anyopaque, data: []const []u8) anyerror!std.io.Reader.Status {
1884 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1885 var iovecs_i: usize = 0;
1886 for (data) |d| {
1887 // In case Windows checks pointer address before length, we must omit
1888 // length-zero vectors.
1889 if (d.len == 0) continue;
1890 iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len };
1891 iovecs_i += 1;
1892 if (iovecs_i >= iovecs.len) break;
19001893 }
1901 return index;
1894 const bufs = iovecs[0..iovecs_i];
1895 if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`.
1896 const handle = opaqueToHandle(context);
1897 var n: u32 = undefined;
1898 var flags: u32 = 0;
1899 const rc = windows.ws2_32.WSARecvFrom(handle, bufs.ptr, bufs.len, &n, &flags, null, null, null, null);
1900 if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) {
1901 .WSAECONNRESET => return error.ConnectionResetByPeer,
1902 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1903 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1904 .WSAEINVAL => return error.SocketNotBound,
1905 .WSAEMSGSIZE => return error.MessageTooBig,
1906 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1907 .WSAENETRESET => return error.ConnectionResetByPeer,
1908 .WSAENOTCONN => return error.SocketNotConnected,
1909 .WSAEWOULDBLOCK => return error.WouldBlock,
1910 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1911 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1912 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1913 else => |err| return windows.unexpectedWSAError(err),
1914 };
1915 return .{ .len = n, .end = n == 0 };
19021916 }
19031917
19041918 fn windows_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize {