authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 08:28:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-07 22:43:52-07:00
log87f32bec2624784e06f5fbd5a9b99c5719154c30
treef4b3fd41246cc4a0c737395a718d23ed05aef1aa
parent49093a659f70cff36156600fc26f60bf1b9158ce

std.io.Reader: finish implementing the unit tests


2 files changed, 84 insertions(+), 16 deletions(-)

lib/std/ascii.zig+4
...@@ -10,6 +10,10 @@...@@ -10,6 +10,10 @@
1010
11const std = @import("std");11const std = @import("std");
1212
13pub const lowercase = "abcdefghijklmnopqrstuvwxyz";
14pub const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
15pub const letters = lowercase ++ uppercase;
16
13/// The C0 control codes of the ASCII encoding.17/// The C0 control codes of the ASCII encoding.
14///18///
15/// See also: https://en.wikipedia.org/wiki/C0_and_C1_control_codes and `isControl`19/// See also: https://en.wikipedia.org/wiki/C0_and_C1_control_codes and `isControl`
lib/std/io/Reader.zig+80-16
...@@ -445,7 +445,7 @@ pub fn toss(r: *Reader, n: usize) void {...@@ -445,7 +445,7 @@ pub fn toss(r: *Reader, n: usize) void {
445}445}
446446
447/// Equivalent to `toss(r.bufferedLen())`.447/// Equivalent to `toss(r.bufferedLen())`.
448pub fn tossAll(r: *Reader) void {448pub fn tossBuffered(r: *Reader) void {
449 r.seek = 0;449 r.seek = 0;
450 r.end = 0;450 r.end = 0;
451}451}
...@@ -557,7 +557,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {...@@ -557,7 +557,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
557/// See also:557/// See also:
558/// * `peek`558/// * `peek`
559/// * `readSliceShort`559/// * `readSliceShort`
560pub fn readSlice(r: *Reader, buffer: []u8) Error!void {560pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
561 const n = try readSliceShort(r, buffer);561 const n = try readSliceShort(r, buffer);
562 if (n != buffer.len) return error.EndOfStream;562 if (n != buffer.len) return error.EndOfStream;
563}563}
...@@ -571,7 +571,7 @@ pub fn readSlice(r: *Reader, buffer: []u8) Error!void {...@@ -571,7 +571,7 @@ pub fn readSlice(r: *Reader, buffer: []u8) Error!void {
571/// only if the stream reached the end.571/// only if the stream reached the end.
572///572///
573/// See also:573/// See also:
574/// * `readSlice`574/// * `readSliceAll`
575pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {575pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
576 const in_buffer = r.buffer[r.seek..r.end];576 const in_buffer = r.buffer[r.seek..r.end];
577 const copy_len = @min(buffer.len, in_buffer.len);577 const copy_len = @min(buffer.len, in_buffer.len);
...@@ -630,7 +630,7 @@ pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {...@@ -630,7 +630,7 @@ pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
630/// comptime-known and matches host endianness.630/// comptime-known and matches host endianness.
631///631///
632/// See also:632/// See also:
633/// * `readSlice`633/// * `readSliceAll`
634/// * `readSliceEndianAlloc`634/// * `readSliceEndianAlloc`
635pub inline fn readSliceEndian(635pub inline fn readSliceEndian(
636 r: *Reader,636 r: *Reader,
...@@ -638,7 +638,7 @@ pub inline fn readSliceEndian(...@@ -638,7 +638,7 @@ pub inline fn readSliceEndian(
638 buffer: []Elem,638 buffer: []Elem,
639 endian: std.builtin.Endian,639 endian: std.builtin.Endian,
640) Error!void {640) Error!void {
641 try readSlice(r, @ptrCast(buffer));641 try readSliceAll(r, @ptrCast(buffer));
642 if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem);642 if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem);
643}643}
644644
...@@ -655,15 +655,16 @@ pub inline fn readSliceEndianAlloc(...@@ -655,15 +655,16 @@ pub inline fn readSliceEndianAlloc(
655) ReadAllocError![]Elem {655) ReadAllocError![]Elem {
656 const dest = try allocator.alloc(Elem, len);656 const dest = try allocator.alloc(Elem, len);
657 errdefer allocator.free(dest);657 errdefer allocator.free(dest);
658 try readSlice(r, @ptrCast(dest));658 try readSliceAll(r, @ptrCast(dest));
659 if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem);659 if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem);
660 return dest;660 return dest;
661}661}
662662
663pub fn readSliceAlloc(r: *Reader, allocator: Allocator, len: usize) ReadAllocError![]u8 {663/// Shortcut for calling `readSliceAll` with a buffer provided by `allocator`.
664pub fn readAlloc(r: *Reader, allocator: Allocator, len: usize) ReadAllocError![]u8 {
664 const dest = try allocator.alloc(u8, len);665 const dest = try allocator.alloc(u8, len);
665 errdefer allocator.free(dest);666 errdefer allocator.free(dest);
666 try readSlice(r, dest);667 try readSliceAll(r, dest);
667 return dest;668 return dest;
668}669}
669670
...@@ -1092,6 +1093,7 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n:...@@ -1092,6 +1093,7 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n:
1092///1093///
1093/// See also:1094/// See also:
1094/// * `peekStruct`1095/// * `peekStruct`
1096/// * `takeStructEndian`
1095pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T {1097pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T {
1096 // Only extern and packed structs have defined in-memory layout.1098 // Only extern and packed structs have defined in-memory layout.
1097 comptime assert(@typeInfo(T).@"struct".layout != .auto);1099 comptime assert(@typeInfo(T).@"struct".layout != .auto);
...@@ -1104,6 +1106,7 @@ pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T {...@@ -1104,6 +1106,7 @@ pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T {
1104///1106///
1105/// See also:1107/// See also:
1106/// * `takeStruct`1108/// * `takeStruct`
1109/// * `peekStructEndian`
1107pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {1110pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {
1108 // Only extern and packed structs have defined in-memory layout.1111 // Only extern and packed structs have defined in-memory layout.
1109 comptime assert(@typeInfo(T).@"struct".layout != .auto);1112 comptime assert(@typeInfo(T).@"struct".layout != .auto);
...@@ -1114,6 +1117,10 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {...@@ -1114,6 +1117,10 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {
1114///1117///
1115/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`1118/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`
1116/// when `endian` is comptime-known and matches the host endianness.1119/// when `endian` is comptime-known and matches the host endianness.
1120///
1121/// See also:
1122/// * `takeStruct`
1123/// * `peekStructEndian`
1117pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {1124pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1118 var res = (try r.takeStruct(T)).*;1125 var res = (try r.takeStruct(T)).*;
1119 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);1126 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
...@@ -1124,6 +1131,10 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin...@@ -1124,6 +1131,10 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin
1124///1131///
1125/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`1132/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`
1126/// when `endian` is comptime-known and matches the host endianness.1133/// when `endian` is comptime-known and matches the host endianness.
1134///
1135/// See also:
1136/// * `takeStructEndian`
1137/// * `peekStruct`
1127pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {1138pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1128 var res = (try r.peekStruct(T)).*;1139 var res = (try r.peekStruct(T)).*;
1129 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);1140 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
...@@ -1489,25 +1500,47 @@ test takeInt {...@@ -1489,25 +1500,47 @@ test takeInt {
14891500
1490test takeVarInt {1501test takeVarInt {
1491 var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });1502 var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
1492 std.debug.print("{x}", .{r.buffer});
1493 try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3));1503 try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3));
1494 try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));1504 try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
1495}1505}
14961506
1497test takeStruct {1507test takeStruct {
1498 return error.Unimplemented;1508 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1509 const S = extern struct { a: u8, b: u16 };
1510 switch (native_endian) {
1511 .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStruct(S)).*),
1512 .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStruct(S)).*),
1513 }
1514 try testing.expectError(error.EndOfStream, r.takeStruct(S));
1499}1515}
15001516
1501test peekStruct {1517test peekStruct {
1502 return error.Unimplemented;1518 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1519 const S = extern struct { a: u8, b: u16 };
1520 switch (native_endian) {
1521 .little => {
1522 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*);
1523 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*);
1524 },
1525 .big => {
1526 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*);
1527 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*);
1528 },
1529 }
1503}1530}
15041531
1505test takeStructEndian {1532test takeStructEndian {
1506 return error.Unimplemented;1533 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1534 const S = extern struct { a: u8, b: u16 };
1535 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStructEndian(S, .big));
1536 try testing.expectError(error.EndOfStream, r.takeStructEndian(S, .little));
1507}1537}
15081538
1509test peekStructEndian {1539test peekStructEndian {
1510 return error.Unimplemented;1540 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1541 const S = extern struct { a: u8, b: u16 };
1542 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStructEndian(S, .big));
1543 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStructEndian(S, .little));
1511}1544}
15121545
1513test takeEnum {1546test takeEnum {
...@@ -1519,15 +1552,46 @@ test takeEnum {...@@ -1519,15 +1552,46 @@ test takeEnum {
1519}1552}
15201553
1521test takeLeb128 {1554test takeLeb128 {
1522 return error.Unimplemented;1555 var r: Reader = .fixed("\xc7\x9f\x7f\x80");
1556 try testing.expectEqual(-12345, try r.takeLeb128(i64));
1557 try testing.expectEqual(0x80, try r.peekByte());
1558 try testing.expectError(error.EndOfStream, r.takeLeb128(i64));
1523}1559}
15241560
1525test readSliceShort {1561test readSliceShort {
1526 return error.Unimplemented;1562 var r: Reader = .fixed("HelloFren");
1563 var buf: [5]u8 = undefined;
1564 try testing.expectEqual(5, try r.readSliceShort(&buf));
1565 try testing.expectEqualStrings("Hello", buf[0..5]);
1566 try testing.expectEqual(4, try r.readSliceShort(&buf));
1567 try testing.expectEqualStrings("Fren", buf[0..4]);
1568 try testing.expectEqual(0, try r.readSliceShort(&buf));
1527}1569}
15281570
1529test readVec {1571test readVec {
1530 return error.Unimplemented;1572 var r: Reader = .fixed(std.ascii.letters);
1573 var flat_buffer: [52]u8 = undefined;
1574 var bufs: [2][]u8 = .{
1575 flat_buffer[0..26],
1576 flat_buffer[26..],
1577 };
1578 // Short reads are possible with this function but not with fixed.
1579 try testing.expectEqual(26 * 2, try r.readVec(&bufs));
1580 try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
1581 try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);
1582}
1583
1584test readVecLimit {
1585 var r: Reader = .fixed(std.ascii.letters);
1586 var flat_buffer: [52]u8 = undefined;
1587 var bufs: [2][]u8 = .{
1588 flat_buffer[0..26],
1589 flat_buffer[26..],
1590 };
1591 // Short reads are possible with this function but not with fixed.
1592 try testing.expectEqual(50, try r.readVecLimit(&bufs, .limited(50)));
1593 try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
1594 try testing.expectEqualStrings(std.ascii.letters[26..50], bufs[1][0..24]);
1531}1595}
15321596
1533test "expected error.EndOfStream" {1597test "expected error.EndOfStream" {