| ... | ... | @@ -1837,10 +1837,20 @@ pub const Stream = struct { |
| 1837 | 1837 | Unexpected, |
| 1838 | 1838 | }; |
| 1839 | 1839 | |
| 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 | }; |
| 1844 | 1854 | } |
| 1845 | 1855 | |
| 1846 | 1856 | pub fn writer(stream: Stream) std.io.Writer { |
| ... | ... | @@ -1859,46 +1869,50 @@ pub const Stream = struct { |
| 1859 | 1869 | }; |
| 1860 | 1870 | } |
| 1861 | 1871 | |
| 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; |
| 1886 | 1881 | } |
| 1887 | 1882 | |
| 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; |
| 1900 | 1893 | } |
| 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 }; |
| 1902 | 1916 | } |
| 1903 | 1917 | |
| 1904 | 1918 | fn windows_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |