| ... | ... | @@ -969,6 +969,14 @@ pub const Reader = struct { |
| 969 | 969 | }; |
| 970 | 970 | } |
| 971 | 971 | |
| 972 | pub fn initMode(file: File, buffer: []u8, init_mode: Reader.Mode) Reader { |
| 973 | return .{ |
| 974 | .file = file, |
| 975 | .interface = initInterface(buffer), |
| 976 | .mode = init_mode, |
| 977 | }; |
| 978 | } |
| 979 | |
| 972 | 980 | pub fn getSize(r: *Reader) GetEndPosError!u64 { |
| 973 | 981 | return r.size orelse { |
| 974 | 982 | if (r.size_err) |err| return err; |
| ... | ... | @@ -1038,7 +1046,7 @@ pub const Reader = struct { |
| 1038 | 1046 | fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { |
| 1039 | 1047 | const r: *Reader = @fieldParentPtr("interface", io_reader); |
| 1040 | 1048 | switch (r.mode) { |
| 1041 | | .positional, .streaming => return w.writeFile(r, limit, &.{}, 0) catch |write_err| switch (write_err) { |
| 1049 | .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) { |
| 1042 | 1050 | error.ReadFailed => return error.ReadFailed, |
| 1043 | 1051 | error.WriteFailed => return error.WriteFailed, |
| 1044 | 1052 | error.Unimplemented => { |
| ... | ... | @@ -1056,7 +1064,7 @@ pub const Reader = struct { |
| 1056 | 1064 | return n; |
| 1057 | 1065 | } |
| 1058 | 1066 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; |
| 1059 | | const dest = w.writableVectorPosix(&iovecs_buffer, limit); |
| 1067 | const dest = try w.writableVectorPosix(&iovecs_buffer, limit); |
| 1060 | 1068 | assert(dest[0].len > 0); |
| 1061 | 1069 | const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { |
| 1062 | 1070 | error.Unseekable => { |
| ... | ... | @@ -1089,9 +1097,10 @@ pub const Reader = struct { |
| 1089 | 1097 | return n; |
| 1090 | 1098 | } |
| 1091 | 1099 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; |
| 1092 | | const dest = w.writableVectorPosix(&iovecs_buffer, limit); |
| 1100 | const dest = try w.writableVectorPosix(&iovecs_buffer, limit); |
| 1093 | 1101 | assert(dest[0].len > 0); |
| 1094 | | const n = posix.pread(r.file.handle, dest) catch |err| { |
| 1102 | // TODO also add buffer at the end |
| 1103 | const n = posix.readv(r.file.handle, dest) catch |err| { |
| 1095 | 1104 | r.err = err; |
| 1096 | 1105 | return error.ReadFailed; |
| 1097 | 1106 | }; |
| ... | ... | @@ -1296,33 +1305,70 @@ pub const Writer = struct { |
| 1296 | 1305 | pub fn drain(io_writer: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 1297 | 1306 | const w: *Writer = @fieldParentPtr("interface", io_writer); |
| 1298 | 1307 | const handle = w.file.handle; |
| 1299 | | if (true) @panic("update to check for buffered data"); |
| 1308 | const buffered = io_writer.buffered(); |
| 1300 | 1309 | var splat_buffer: [256]u8 = undefined; |
| 1301 | 1310 | if (is_windows) { |
| 1302 | | if (data.len == 1 and splat == 0) return 0; |
| 1303 | | return windows.WriteFile(handle, data[0], null); |
| 1311 | var i: usize = 0; |
| 1312 | while (i < buffered.len) { |
| 1313 | const n = windows.WriteFile(handle, buffered[i..], null) catch |err| { |
| 1314 | w.err = err; |
| 1315 | w.pos += i; |
| 1316 | _ = io_writer.consume(i); |
| 1317 | return error.WriteFailed; |
| 1318 | }; |
| 1319 | i += n; |
| 1320 | if (data.len > 0 and buffered.len - i < n) { |
| 1321 | w.pos += i; |
| 1322 | return io_writer.consume(i); |
| 1323 | } |
| 1324 | } |
| 1325 | if (i != 0 or data.len == 0 or (data.len == 1 and splat == 0)) { |
| 1326 | w.pos += i; |
| 1327 | return io_writer.consume(i); |
| 1328 | } |
| 1329 | const n = windows.WriteFile(handle, data[0], null) catch |err| { |
| 1330 | w.err = err; |
| 1331 | return 0; |
| 1332 | }; |
| 1333 | w.pos += n; |
| 1334 | return n; |
| 1335 | } |
| 1336 | if (data.len == 0) { |
| 1337 | var i: usize = 0; |
| 1338 | while (i < buffered.len) { |
| 1339 | i += std.posix.write(handle, buffered) catch |err| { |
| 1340 | w.err = err; |
| 1341 | w.pos += i; |
| 1342 | _ = io_writer.consume(i); |
| 1343 | return error.WriteFailed; |
| 1344 | }; |
| 1345 | } |
| 1346 | w.pos += i; |
| 1347 | return io_writer.consumeAll(); |
| 1304 | 1348 | } |
| 1305 | 1349 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 1306 | | var len: usize = @min(iovecs.len, data.len); |
| 1307 | | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 1308 | | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. |
| 1309 | | .len = d.len, |
| 1310 | | }; |
| 1350 | var len: usize = 0; |
| 1351 | if (buffered.len > 0) { |
| 1352 | iovecs[len] = .{ .base = buffered.ptr, .len = buffered.len }; |
| 1353 | len += 1; |
| 1354 | } |
| 1355 | for (data) |d| { |
| 1356 | if (d.len == 0) continue; |
| 1357 | if (iovecs.len - len == 0) break; |
| 1358 | iovecs[len] = .{ .base = d.ptr, .len = d.len }; |
| 1359 | len += 1; |
| 1360 | } |
| 1311 | 1361 | switch (splat) { |
| 1312 | | 0 => return std.posix.writev(handle, iovecs[0 .. len - 1]) catch |err| { |
| 1313 | | w.err = err; |
| 1314 | | return error.WriteFailed; |
| 1315 | | }, |
| 1316 | | 1 => return std.posix.writev(handle, iovecs[0..len]) catch |err| { |
| 1317 | | w.err = err; |
| 1318 | | return error.WriteFailed; |
| 1362 | 0 => if (data[data.len - 1].len != 0) { |
| 1363 | len -= 1; |
| 1319 | 1364 | }, |
| 1320 | | else => { |
| 1321 | | const pattern = data[data.len - 1]; |
| 1322 | | if (pattern.len == 1) { |
| 1365 | 1 => {}, |
| 1366 | else => switch (data[data.len - 1].len) { |
| 1367 | 0 => {}, |
| 1368 | 1 => { |
| 1323 | 1369 | const memset_len = @min(splat_buffer.len, splat); |
| 1324 | 1370 | const buf = splat_buffer[0..memset_len]; |
| 1325 | | @memset(buf, pattern[0]); |
| 1371 | @memset(buf, data[data.len - 1][0]); |
| 1326 | 1372 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 1327 | 1373 | var remaining_splat = splat - buf.len; |
| 1328 | 1374 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| ... | ... | @@ -1338,13 +1384,20 @@ pub const Writer = struct { |
| 1338 | 1384 | w.err = err; |
| 1339 | 1385 | return error.WriteFailed; |
| 1340 | 1386 | }; |
| 1341 | | } |
| 1387 | }, |
| 1388 | else => for (0..splat - 1) |_| { |
| 1389 | if (iovecs.len - len == 0) break; |
| 1390 | iovecs[len] = .{ .base = data[data.len - 1].ptr, .len = data[data.len - 1].len }; |
| 1391 | len += 1; |
| 1392 | }, |
| 1342 | 1393 | }, |
| 1343 | 1394 | } |
| 1344 | | return std.posix.writev(handle, iovecs[0..len]) catch |err| { |
| 1395 | const n = std.posix.writev(handle, iovecs[0..len]) catch |err| { |
| 1345 | 1396 | w.err = err; |
| 1346 | 1397 | return error.WriteFailed; |
| 1347 | 1398 | }; |
| 1399 | w.pos += n; |
| 1400 | return io_writer.consume(n); |
| 1348 | 1401 | } |
| 1349 | 1402 | |
| 1350 | 1403 | pub fn sendFile( |