| ... | ... | @@ -30,20 +30,20 @@ pub const Request = struct { |
| 30 | 30 | |
| 31 | 31 | pub const PWriteV = struct { |
| 32 | 32 | fd: os.FileHandle, |
| 33 | | iov: []os.posix.iovec_const, |
| 33 | iov: []const os.posix.iovec_const, |
| 34 | 34 | offset: usize, |
| 35 | 35 | result: Error!void, |
| 36 | 36 | |
| 37 | | pub const Error = os.File.WriteError; |
| 37 | pub const Error = os.PosixWriteError; |
| 38 | 38 | }; |
| 39 | 39 | |
| 40 | 40 | pub const PReadV = struct { |
| 41 | 41 | fd: os.FileHandle, |
| 42 | | iov: []os.posix.iovec, |
| 42 | iov: []const os.posix.iovec, |
| 43 | 43 | offset: usize, |
| 44 | 44 | result: Error!usize, |
| 45 | 45 | |
| 46 | | pub const Error = os.File.ReadError; |
| 46 | pub const Error = os.PosixReadError; |
| 47 | 47 | }; |
| 48 | 48 | |
| 49 | 49 | pub const Open = struct { |
| ... | ... | @@ -72,28 +72,47 @@ pub const Request = struct { |
| 72 | 72 | }; |
| 73 | 73 | }; |
| 74 | 74 | |
| 75 | pub const PWriteVError = error{OutOfMemory} || os.File.WriteError; |
| 76 | |
| 75 | 77 | /// data - just the inner references - must live until pwritev promise completes. |
| 76 | | pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) !void { |
| 78 | pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) PWriteVError!void { |
| 79 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| 80 | suspend { |
| 81 | resume @handle(); |
| 82 | } |
| 77 | 83 | switch (builtin.os) { |
| 78 | 84 | builtin.Os.macosx, |
| 79 | 85 | builtin.Os.linux, |
| 80 | | => return await (async pwritevPosix(loop, fd, data, offset) catch unreachable), |
| 81 | | builtin.Os.windows => return await (async pwritevWindows(loop, fd, data, offset) catch unreachable), |
| 86 | => { |
| 87 | const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); |
| 88 | defer loop.allocator.free(iovecs); |
| 89 | |
| 90 | for (data) |buf, i| { |
| 91 | iovecs[i] = os.posix.iovec_const{ |
| 92 | .iov_base = buf.ptr, |
| 93 | .iov_len = buf.len, |
| 94 | }; |
| 95 | } |
| 96 | |
| 97 | return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable); |
| 98 | }, |
| 99 | builtin.Os.windows => { |
| 100 | const data_copy = try std.mem.dupe(loop.allocator, []const u8, data); |
| 101 | defer loop.allocator.free(data_copy); |
| 102 | return await (async pwritevWindows(loop, fd, data, offset) catch unreachable); |
| 103 | }, |
| 82 | 104 | else => @compileError("Unsupported OS"), |
| 83 | 105 | } |
| 84 | 106 | } |
| 85 | 107 | |
| 86 | | /// data - just the inner references - must live until pwritev promise completes. |
| 87 | | pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) !void { |
| 108 | /// data must outlive the returned promise |
| 109 | pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) os.WindowsWriteError!void { |
| 88 | 110 | if (data.len == 0) return; |
| 89 | 111 | if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable); |
| 90 | 112 | |
| 91 | | const data_copy = try std.mem.dupe(loop.allocator, []const u8, data); |
| 92 | | defer loop.allocator.free(data_copy); |
| 93 | | |
| 94 | 113 | // TODO do these in parallel |
| 95 | 114 | var off = offset; |
| 96 | | for (data_copy) |buf| { |
| 115 | for (data) |buf| { |
| 97 | 116 | try await (async pwriteWindows(loop, fd, buf, off) catch unreachable); |
| 98 | 117 | off += buf.len; |
| 99 | 118 | } |
| ... | ... | @@ -144,23 +163,18 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off |
| 144 | 163 | } |
| 145 | 164 | } |
| 146 | 165 | |
| 147 | | /// data - just the inner references - must live until pwritev promise completes. |
| 148 | | pub async fn pwritevPosix(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) !void { |
| 166 | /// iovecs must live until pwritev promise completes. |
| 167 | pub async fn pwritevPosix( |
| 168 | loop: *Loop, |
| 169 | fd: os.FileHandle, |
| 170 | iovecs: []const posix.iovec_const, |
| 171 | offset: usize, |
| 172 | ) os.PosixWriteError!void { |
| 149 | 173 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| 150 | 174 | suspend { |
| 151 | 175 | resume @handle(); |
| 152 | 176 | } |
| 153 | 177 | |
| 154 | | const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); |
| 155 | | defer loop.allocator.free(iovecs); |
| 156 | | |
| 157 | | for (data) |buf, i| { |
| 158 | | iovecs[i] = os.posix.iovec_const{ |
| 159 | | .iov_base = buf.ptr, |
| 160 | | .iov_len = buf.len, |
| 161 | | }; |
| 162 | | } |
| 163 | | |
| 164 | 178 | var req_node = RequestNode{ |
| 165 | 179 | .prev = null, |
| 166 | 180 | .next = null, |
| ... | ... | @@ -192,38 +206,59 @@ pub async fn pwritevPosix(loop: *Loop, fd: os.FileHandle, data: []const []const |
| 192 | 206 | return req_node.data.msg.PWriteV.result; |
| 193 | 207 | } |
| 194 | 208 | |
| 209 | pub const PReadVError = error{OutOfMemory} || os.File.ReadError; |
| 210 | |
| 195 | 211 | /// data - just the inner references - must live until preadv promise completes. |
| 196 | | pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) !usize { |
| 212 | pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) PReadVError!usize { |
| 213 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| 214 | suspend { |
| 215 | resume @handle(); |
| 216 | } |
| 217 | |
| 197 | 218 | assert(data.len != 0); |
| 198 | 219 | switch (builtin.os) { |
| 199 | 220 | builtin.Os.macosx, |
| 200 | 221 | builtin.Os.linux, |
| 201 | | => return await (async preadvPosix(loop, fd, data, offset) catch unreachable), |
| 202 | | builtin.Os.windows => return await (async preadvWindows(loop, fd, data, offset) catch unreachable), |
| 222 | => { |
| 223 | const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); |
| 224 | defer loop.allocator.free(iovecs); |
| 225 | |
| 226 | for (data) |buf, i| { |
| 227 | iovecs[i] = os.posix.iovec{ |
| 228 | .iov_base = buf.ptr, |
| 229 | .iov_len = buf.len, |
| 230 | }; |
| 231 | } |
| 232 | |
| 233 | return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable); |
| 234 | }, |
| 235 | builtin.Os.windows => { |
| 236 | const data_copy = try std.mem.dupe(loop.allocator, []u8, data); |
| 237 | defer loop.allocator.free(data_copy); |
| 238 | return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable); |
| 239 | }, |
| 203 | 240 | else => @compileError("Unsupported OS"), |
| 204 | 241 | } |
| 205 | 242 | } |
| 206 | 243 | |
| 207 | | pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) !usize { |
| 244 | /// data must outlive the returned promise |
| 245 | pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) os.WindowsReadError!usize { |
| 208 | 246 | assert(data.len != 0); |
| 209 | 247 | if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable); |
| 210 | 248 | |
| 211 | | const data_copy = try std.mem.dupe(loop.allocator, []u8, data); |
| 212 | | defer loop.allocator.free(data_copy); |
| 213 | | |
| 214 | 249 | // TODO do these in parallel? |
| 215 | 250 | var off: usize = 0; |
| 216 | 251 | var iov_i: usize = 0; |
| 217 | 252 | var inner_off: usize = 0; |
| 218 | 253 | while (true) { |
| 219 | | const v = data_copy[iov_i]; |
| 254 | const v = data[iov_i]; |
| 220 | 255 | const amt_read = try await (async preadWindows(loop, fd, v[inner_off .. v.len - inner_off], offset + off) catch unreachable); |
| 221 | 256 | off += amt_read; |
| 222 | 257 | inner_off += amt_read; |
| 223 | 258 | if (inner_off == v.len) { |
| 224 | 259 | iov_i += 1; |
| 225 | 260 | inner_off = 0; |
| 226 | | if (iov_i == data_copy.len) { |
| 261 | if (iov_i == data.len) { |
| 227 | 262 | return off; |
| 228 | 263 | } |
| 229 | 264 | } |
| ... | ... | @@ -275,23 +310,18 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6 |
| 275 | 310 | return usize(bytes_transferred); |
| 276 | 311 | } |
| 277 | 312 | |
| 278 | | /// data - just the inner references - must live until preadv promise completes. |
| 279 | | pub async fn preadvPosix(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) !usize { |
| 313 | /// iovecs must live until preadv promise completes |
| 314 | pub async fn preadvPosix( |
| 315 | loop: *Loop, |
| 316 | fd: os.FileHandle, |
| 317 | iovecs: []const posix.iovec, |
| 318 | offset: usize, |
| 319 | ) os.PosixReadError!usize { |
| 280 | 320 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| 281 | 321 | suspend { |
| 282 | 322 | resume @handle(); |
| 283 | 323 | } |
| 284 | 324 | |
| 285 | | const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); |
| 286 | | defer loop.allocator.free(iovecs); |
| 287 | | |
| 288 | | for (data) |buf, i| { |
| 289 | | iovecs[i] = os.posix.iovec{ |
| 290 | | .iov_base = buf.ptr, |
| 291 | | .iov_len = buf.len, |
| 292 | | }; |
| 293 | | } |
| 294 | | |
| 295 | 325 | var req_node = RequestNode{ |
| 296 | 326 | .prev = null, |
| 297 | 327 | .next = null, |
| ... | ... | @@ -1339,3 +1369,55 @@ async fn testFsWatch(loop: *Loop) !void { |
| 1339 | 1369 | |
| 1340 | 1370 | // TODO test deleting the file and then re-adding it. we should get events for both |
| 1341 | 1371 | } |
| 1372 | |
| 1373 | pub const OutStream = struct { |
| 1374 | fd: os.FileHandle, |
| 1375 | stream: Stream, |
| 1376 | loop: *Loop, |
| 1377 | offset: usize, |
| 1378 | |
| 1379 | pub const Error = os.File.WriteError; |
| 1380 | pub const Stream = event.io.OutStream(Error); |
| 1381 | |
| 1382 | pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) OutStream { |
| 1383 | return OutStream{ |
| 1384 | .fd = fd, |
| 1385 | .loop = loop, |
| 1386 | .offset = offset, |
| 1387 | .stream = Stream{ .writeFn = writeFn }, |
| 1388 | }; |
| 1389 | } |
| 1390 | |
| 1391 | async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void { |
| 1392 | const self = @fieldParentPtr(OutStream, "stream", out_stream); |
| 1393 | const offset = self.offset; |
| 1394 | self.offset += bytes.len; |
| 1395 | return await (async pwritev(self.loop, self.fd, [][]const u8{bytes}, offset) catch unreachable); |
| 1396 | } |
| 1397 | }; |
| 1398 | |
| 1399 | pub const InStream = struct { |
| 1400 | fd: os.FileHandle, |
| 1401 | stream: Stream, |
| 1402 | loop: *Loop, |
| 1403 | offset: usize, |
| 1404 | |
| 1405 | pub const Error = PReadVError; // TODO make this not have OutOfMemory |
| 1406 | pub const Stream = event.io.InStream(Error); |
| 1407 | |
| 1408 | pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) InStream { |
| 1409 | return InStream{ |
| 1410 | .fd = fd, |
| 1411 | .loop = loop, |
| 1412 | .offset = offset, |
| 1413 | .stream = Stream{ .readFn = readFn }, |
| 1414 | }; |
| 1415 | } |
| 1416 | |
| 1417 | async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize { |
| 1418 | const self = @fieldParentPtr(InStream, "stream", in_stream); |
| 1419 | const amt = try await (async preadv(self.loop, self.fd, [][]u8{bytes}, self.offset) catch unreachable); |
| 1420 | self.offset += amt; |
| 1421 | return amt; |
| 1422 | } |
| 1423 | }; |