| ... | @@ -969,6 +969,14 @@ pub const Reader = struct { | ... | @@ -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 | pub fn getSize(r: *Reader) GetEndPosError!u64 { | 980 | pub fn getSize(r: *Reader) GetEndPosError!u64 { |
| 973 | return r.size orelse { | 981 | return r.size orelse { |
| 974 | if (r.size_err) |err| return err; | 982 | if (r.size_err) |err| return err; |
| ... | @@ -1038,7 +1046,7 @@ pub const Reader = struct { | ... | @@ -1038,7 +1046,7 @@ pub const Reader = struct { |
| 1038 | fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { | 1046 | fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { |
| 1039 | const r: *Reader = @fieldParentPtr("interface", io_reader); | 1047 | const r: *Reader = @fieldParentPtr("interface", io_reader); |
| 1040 | switch (r.mode) { | 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 | error.ReadFailed => return error.ReadFailed, | 1050 | error.ReadFailed => return error.ReadFailed, |
| 1043 | error.WriteFailed => return error.WriteFailed, | 1051 | error.WriteFailed => return error.WriteFailed, |
| 1044 | error.Unimplemented => { | 1052 | error.Unimplemented => { |
| ... | @@ -1056,7 +1064,7 @@ pub const Reader = struct { | ... | @@ -1056,7 +1064,7 @@ pub const Reader = struct { |
| 1056 | return n; | 1064 | return n; |
| 1057 | } | 1065 | } |
| 1058 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; | 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 | assert(dest[0].len > 0); | 1068 | assert(dest[0].len > 0); |
| 1061 | const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { | 1069 | const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { |
| 1062 | error.Unseekable => { | 1070 | error.Unseekable => { |
| ... | @@ -1089,9 +1097,10 @@ pub const Reader = struct { | ... | @@ -1089,9 +1097,10 @@ pub const Reader = struct { |
| 1089 | return n; | 1097 | return n; |
| 1090 | } | 1098 | } |
| 1091 | var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; | 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 | assert(dest[0].len > 0); | 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 | r.err = err; | 1104 | r.err = err; |
| 1096 | return error.ReadFailed; | 1105 | return error.ReadFailed; |
| 1097 | }; | 1106 | }; |
| ... | @@ -1296,33 +1305,70 @@ pub const Writer = struct { | ... | @@ -1296,33 +1305,70 @@ pub const Writer = struct { |
| 1296 | pub fn drain(io_writer: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { | 1305 | pub fn drain(io_writer: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 1297 | const w: *Writer = @fieldParentPtr("interface", io_writer); | 1306 | const w: *Writer = @fieldParentPtr("interface", io_writer); |
| 1298 | const handle = w.file.handle; | 1307 | const handle = w.file.handle; |
| 1299 | if (true) @panic("update to check for buffered data"); | 1308 | const buffered = io_writer.buffered(); |
| 1300 | var splat_buffer: [256]u8 = undefined; | 1309 | var splat_buffer: [256]u8 = undefined; |
| 1301 | if (is_windows) { | 1310 | if (is_windows) { |
| 1302 | if (data.len == 1 and splat == 0) return 0; | 1311 | var i: usize = 0; |
| 1303 | return windows.WriteFile(handle, data[0], null); | 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 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; | 1349 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 1306 | var len: usize = @min(iovecs.len, data.len); | 1350 | var len: usize = 0; |
| 1307 | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ | 1351 | if (buffered.len > 0) { |
| 1308 | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. | 1352 | iovecs[len] = .{ .base = buffered.ptr, .len = buffered.len }; |
| 1309 | .len = d.len, | 1353 | len += 1; |
| 1310 | }; | 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 | switch (splat) { | 1361 | switch (splat) { |
| 1312 | 0 => return std.posix.writev(handle, iovecs[0 .. len - 1]) catch |err| { | 1362 | 0 => if (data[data.len - 1].len != 0) { |
| 1313 | w.err = err; | 1363 | len -= 1; |
| 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; | | |
| 1319 | }, | 1364 | }, |
| 1320 | else => { | 1365 | 1 => {}, |
| 1321 | const pattern = data[data.len - 1]; | 1366 | else => switch (data[data.len - 1].len) { |
| 1322 | if (pattern.len == 1) { | 1367 | 0 => {}, |
| | 1368 | 1 => { |
| 1323 | const memset_len = @min(splat_buffer.len, splat); | 1369 | const memset_len = @min(splat_buffer.len, splat); |
| 1324 | const buf = splat_buffer[0..memset_len]; | 1370 | const buf = splat_buffer[0..memset_len]; |
| 1325 | @memset(buf, pattern[0]); | 1371 | @memset(buf, data[data.len - 1][0]); |
| 1326 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; | 1372 | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 1327 | var remaining_splat = splat - buf.len; | 1373 | var remaining_splat = splat - buf.len; |
| 1328 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { | 1374 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| ... | @@ -1338,13 +1384,20 @@ pub const Writer = struct { | ... | @@ -1338,13 +1384,20 @@ pub const Writer = struct { |
| 1338 | w.err = err; | 1384 | w.err = err; |
| 1339 | return error.WriteFailed; | 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 | w.err = err; | 1396 | w.err = err; |
| 1346 | return error.WriteFailed; | 1397 | return error.WriteFailed; |
| 1347 | }; | 1398 | }; |
| | 1399 | w.pos += n; |
| | 1400 | return io_writer.consume(n); |
| 1348 | } | 1401 | } |
| 1349 | | 1402 | |
| 1350 | pub fn sendFile( | 1403 | pub fn sendFile( |