authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-06-30 10:15:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-07 22:43:51-07:00
log1d763c8b29360a5f3b52747231876b54db1c7ba0
treec8092a1dc9675797310567ee61c9f20e0dfc906a
parent7eae26d60895dc62fa62f6562a4eeecb8685aae5

std: formatted printing no longer prints type names

for structs, enums, and unions. auto untagged unions are no longer printed as pointers; instead they are printed as "{ ... }". extern and packed untagged unions have each field printed, similar to what gdb does. also fix bugs in delimiter based reading

4 files changed, 177 insertions(+), 128 deletions(-)

lib/std/fmt.zig+26-31
...@@ -996,7 +996,7 @@ test "slice" {...@@ -996,7 +996,7 @@ test "slice" {
996 x: u8,996 x: u8,
997 };997 };
998 const struct_slice: []const S1 = &[_]S1{ S1{ .x = 8 }, S1{ .x = 42 } };998 const struct_slice: []const S1 = &[_]S1{ S1{ .x = 8 }, S1{ .x = 42 } };
999 try expectFmt("slice: { fmt.test.slice.S1{ .x = 8 }, fmt.test.slice.S1{ .x = 42 } }", "slice: {any}", .{struct_slice});999 try expectFmt("slice: { .{ .x = 8 }, .{ .x = 42 } }", "slice: {any}", .{struct_slice});
1000 }1000 }
1001 {1001 {
1002 const S2 = struct {1002 const S2 = struct {
...@@ -1007,7 +1007,7 @@ test "slice" {...@@ -1007,7 +1007,7 @@ test "slice" {
1007 }1007 }
1008 };1008 };
1009 const struct_slice: []const S2 = &[_]S2{ S2{ .x = 8 }, S2{ .x = 42 } };1009 const struct_slice: []const S2 = &[_]S2{ S2{ .x = 8 }, S2{ .x = 42 } };
1010 try expectFmt("slice: { fmt.test.slice.S2{ .x = 8 }, fmt.test.slice.S2{ .x = 42 } }", "slice: {any}", .{struct_slice});1010 try expectFmt("slice: { .{ .x = 8 }, .{ .x = 42 } }", "slice: {any}", .{struct_slice});
1011 }1011 }
1012}1012}
10131013
...@@ -1047,8 +1047,8 @@ test "struct" {...@@ -1047,8 +1047,8 @@ test "struct" {
1047 field: u8,1047 field: u8,
1048 };1048 };
1049 const value = Struct{ .field = 42 };1049 const value = Struct{ .field = 42 };
1050 try expectFmt("struct: fmt.test.struct.Struct{ .field = 42 }\n", "struct: {}\n", .{value});1050 try expectFmt("struct: .{ .field = 42 }\n", "struct: {}\n", .{value});
1051 try expectFmt("struct: fmt.test.struct.Struct{ .field = 42 }\n", "struct: {}\n", .{&value});1051 try expectFmt("struct: .{ .field = 42 }\n", "struct: {}\n", .{&value});
1052 }1052 }
1053 {1053 {
1054 const Struct = struct {1054 const Struct = struct {
...@@ -1056,7 +1056,7 @@ test "struct" {...@@ -1056,7 +1056,7 @@ test "struct" {
1056 b: u1,1056 b: u1,
1057 };1057 };
1058 const value = Struct{ .a = 0, .b = 1 };1058 const value = Struct{ .a = 0, .b = 1 };
1059 try expectFmt("struct: fmt.test.struct.Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});1059 try expectFmt("struct: .{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
1060 }1060 }
10611061
1062 const S = struct {1062 const S = struct {
...@@ -1069,11 +1069,11 @@ test "struct" {...@@ -1069,11 +1069,11 @@ test "struct" {
1069 .b = error.Unused,1069 .b = error.Unused,
1070 };1070 };
10711071
1072 try expectFmt("fmt.test.struct.S{ .a = 456, .b = error.Unused }", "{}", .{inst});1072 try expectFmt(".{ .a = 456, .b = error.Unused }", "{}", .{inst});
1073 // Tuples1073 // Tuples
1074 try expectFmt("{ }", "{}", .{.{}});1074 try expectFmt(".{ }", "{}", .{.{}});
1075 try expectFmt("{ -1 }", "{}", .{.{-1}});1075 try expectFmt(".{ -1 }", "{}", .{.{-1}});
1076 try expectFmt("{ -1, 42, 25000 }", "{}", .{.{ -1, 42, 0.25e5 }});1076 try expectFmt(".{ -1, 42, 25000 }", "{}", .{.{ -1, 42, 0.25e5 }});
1077}1077}
10781078
1079test "enum" {1079test "enum" {
...@@ -1082,15 +1082,15 @@ test "enum" {...@@ -1082,15 +1082,15 @@ test "enum" {
1082 Two,1082 Two,
1083 };1083 };
1084 const value = Enum.Two;1084 const value = Enum.Two;
1085 try expectFmt("enum: fmt.test.enum.Enum.Two\n", "enum: {}\n", .{value});1085 try expectFmt("enum: .Two\n", "enum: {}\n", .{value});
1086 try expectFmt("enum: fmt.test.enum.Enum.Two\n", "enum: {}\n", .{&value});1086 try expectFmt("enum: .Two\n", "enum: {}\n", .{&value});
1087 try expectFmt("enum: fmt.test.enum.Enum.One\n", "enum: {}\n", .{Enum.One});1087 try expectFmt("enum: .One\n", "enum: {}\n", .{Enum.One});
1088 try expectFmt("enum: fmt.test.enum.Enum.Two\n", "enum: {}\n", .{Enum.Two});1088 try expectFmt("enum: .Two\n", "enum: {}\n", .{Enum.Two});
10891089
1090 // test very large enum to verify ct branch quota is large enough1090 // test very large enum to verify ct branch quota is large enough
1091 // TODO: https://github.com/ziglang/zig/issues/156091091 // TODO: https://github.com/ziglang/zig/issues/15609
1092 if (!((builtin.cpu.arch == .wasm32) and builtin.mode == .Debug)) {1092 if (!((builtin.cpu.arch == .wasm32) and builtin.mode == .Debug)) {
1093 try expectFmt("enum: os.windows.win32error.Win32Error.INVALID_FUNCTION\n", "enum: {}\n", .{std.os.windows.Win32Error.INVALID_FUNCTION});1093 try expectFmt("enum: .INVALID_FUNCTION\n", "enum: {}\n", .{std.os.windows.Win32Error.INVALID_FUNCTION});
1094 }1094 }
10951095
1096 const E = enum {1096 const E = enum {
...@@ -1101,7 +1101,7 @@ test "enum" {...@@ -1101,7 +1101,7 @@ test "enum" {
11011101
1102 const inst = E.Two;1102 const inst = E.Two;
11031103
1104 try expectFmt("fmt.test.enum.E.Two", "{}", .{inst});1104 try expectFmt(".Two", "{}", .{inst});
1105}1105}
11061106
1107test "non-exhaustive enum" {1107test "non-exhaustive enum" {
...@@ -1110,9 +1110,9 @@ test "non-exhaustive enum" {...@@ -1110,9 +1110,9 @@ test "non-exhaustive enum" {
1110 Two = 0xbeef,1110 Two = 0xbeef,
1111 _,1111 _,
1112 };1112 };
1113 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {}\n", .{Enum.One});1113 try expectFmt("enum: .One\n", "enum: {}\n", .{Enum.One});
1114 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {}\n", .{Enum.Two});1114 try expectFmt("enum: .Two\n", "enum: {}\n", .{Enum.Two});
1115 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(4660)\n", "enum: {}\n", .{@as(Enum, @enumFromInt(0x1234))});1115 try expectFmt("enum: @enumFromInt(4660)\n", "enum: {}\n", .{@as(Enum, @enumFromInt(0x1234))});
1116 try expectFmt("enum: f\n", "enum: {x}\n", .{Enum.One});1116 try expectFmt("enum: f\n", "enum: {x}\n", .{Enum.One});
1117 try expectFmt("enum: beef\n", "enum: {x}\n", .{Enum.Two});1117 try expectFmt("enum: beef\n", "enum: {x}\n", .{Enum.Two});
1118 try expectFmt("enum: BEEF\n", "enum: {X}\n", .{Enum.Two});1118 try expectFmt("enum: BEEF\n", "enum: {X}\n", .{Enum.Two});
...@@ -1291,18 +1291,13 @@ test "union" {...@@ -1291,18 +1291,13 @@ test "union" {
1291 int: u32,1291 int: u32,
1292 };1292 };
12931293
1294 const tu_inst = TU{ .int = 123 };1294 const tu_inst: TU = .{ .int = 123 };
1295 const uu_inst = UU{ .int = 456 };1295 const uu_inst: UU = .{ .int = 456 };
1296 const eu_inst = EU{ .float = 321.123 };1296 const eu_inst: EU = .{ .float = 321.123 };
12971297
1298 try expectFmt("fmt.test.union.TU{ .int = 123 }", "{}", .{tu_inst});1298 try expectFmt(".{ .int = 123 }", "{}", .{tu_inst});
12991299 try expectFmt(".{ ... }", "{}", .{uu_inst});
1300 var buf: [100]u8 = undefined;1300 try expectFmt(".{ .float = 321.123, .int = 1134596030 }", "{}", .{eu_inst});
1301 const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
1302 try std.testing.expectEqualStrings("fmt.test.union.UU@", uu_result[0..18]);
1303
1304 const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
1305 try std.testing.expectEqualStrings("fmt.test.union.EU@", eu_result[0..18]);
1306}1301}
13071302
1308test "struct.self-referential" {1303test "struct.self-referential" {
...@@ -1316,7 +1311,7 @@ test "struct.self-referential" {...@@ -1316,7 +1311,7 @@ test "struct.self-referential" {
1316 };1311 };
1317 inst.a = &inst;1312 inst.a = &inst;
13181313
1319 try expectFmt("fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ ... } } } }", "{}", .{inst});1314 try expectFmt(".{ .a = .{ .a = .{ .a = .{ ... } } } }", "{}", .{inst});
1320}1315}
13211316
1322test "struct.zero-size" {1317test "struct.zero-size" {
...@@ -1331,7 +1326,7 @@ test "struct.zero-size" {...@@ -1331,7 +1326,7 @@ test "struct.zero-size" {
1331 const a = A{};1326 const a = A{};
1332 const b = B{ .a = a, .c = 0 };1327 const b = B{ .a = a, .c = 0 };
13331328
1334 try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b});1329 try expectFmt(".{ .a = .{ }, .c = 0 }", "{}", .{b});
1335}1330}
13361331
1337/// Encodes a sequence of bytes as hexadecimal digits.1332/// Encodes a sequence of bytes as hexadecimal digits.
lib/std/io/Reader.zig+108-38
...@@ -36,7 +36,10 @@ pub const VTable = struct {...@@ -36,7 +36,10 @@ pub const VTable = struct {
36 /// sizes combined with short reads (returning a value less than `limit`)36 /// sizes combined with short reads (returning a value less than `limit`)
37 /// in order to minimize complexity.37 /// in order to minimize complexity.
38 ///38 ///
39 /// This function is always called when `buffer` is empty.39 /// Although this function is usually called when `buffer` is empty, it is
40 /// also called when it needs to be filled more due to the API user
41 /// requesting contiguous memory. In either case, the existing buffer data
42 /// should be ignored; new data written to `w`.
40 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,43 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,
4144
42 /// Consumes bytes from the internally tracked stream position without45 /// Consumes bytes from the internally tracked stream position without
...@@ -194,7 +197,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {...@@ -194,7 +197,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
194/// Consumes the stream until the end, ignoring all the data, returning the197/// Consumes the stream until the end, ignoring all the data, returning the
195/// number of bytes discarded.198/// number of bytes discarded.
196pub fn discardRemaining(r: *Reader) ShortError!usize {199pub fn discardRemaining(r: *Reader) ShortError!usize {
197 var offset: usize = r.end;200 var offset: usize = r.end - r.seek;
198 r.seek = 0;201 r.seek = 0;
199 r.end = 0;202 r.end = 0;
200 while (true) {203 while (true) {
...@@ -693,6 +696,17 @@ pub fn takeSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel...@@ -693,6 +696,17 @@ pub fn takeSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel
693 return result;696 return result;
694}697}
695698
699/// Returns a slice of the next bytes of buffered data from the stream until
700/// `sentinel` is found, without advancing the seek position.
701///
702/// Returned slice has a sentinel; end of stream does not count as a delimiter.
703///
704/// Invalidates previously returned values from `peek`.
705///
706/// See also:
707/// * `takeSentinel`
708/// * `peekDelimiterExclusive`
709/// * `peekDelimiterInclusive`
696pub fn peekSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel]u8 {710pub fn peekSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel]u8 {
697 const result = try r.peekDelimiterInclusive(sentinel);711 const result = try r.peekDelimiterInclusive(sentinel);
698 return result[0 .. result.len - 1 :sentinel];712 return result[0 .. result.len - 1 :sentinel];
...@@ -733,27 +747,37 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -733,27 +747,37 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
733 @branchHint(.likely);747 @branchHint(.likely);
734 return buffer[seek .. end + 1];748 return buffer[seek .. end + 1];
735 }749 }
736 if (seek > 0) {750 while (r.buffer.len - r.end != 0) {
737 const remainder = buffer[seek..];751 const end_cap = r.buffer[r.end..];
738 @memmove(buffer[0..remainder.len], remainder);752 var writer: Writer = .fixed(end_cap);
739 r.end = remainder.len;753 const n = r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
740 r.seek = 0;754 error.WriteFailed => unreachable,
755 else => |e| return e,
756 };
757 r.end += n;
758 if (std.mem.indexOfScalarPos(u8, end_cap[0..n], 0, delimiter)) |end| {
759 return r.buffer[seek .. r.end - n + end + 1];
760 }
741 }761 }
742 var writer: Writer = .{762 var i: usize = 0;
743 .buffer = r.buffer,763 while (seek - i != 0) {
744 .vtable = &.{ .drain = Writer.fixedDrain },764 const begin_cap = r.buffer[i..seek];
745 };765 var writer: Writer = .fixed(begin_cap);
746 while (r.end < r.buffer.len) {766 const n = r.vtable.stream(r, &writer, .limited(begin_cap.len)) catch |err| switch (err) {
747 writer.end = r.end;
748 const n = r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
749 error.WriteFailed => unreachable,767 error.WriteFailed => unreachable,
750 else => |e| return e,768 else => |e| return e,
751 };769 };
752 const prev_end = r.end;770 i += n;
753 r.end = prev_end + n;771 if (std.mem.indexOfScalarPos(u8, r.buffer[0..seek], i, delimiter)) |end| {
754 if (std.mem.indexOfScalarPos(u8, r.buffer[0..r.end], prev_end, delimiter)) |end| {772 std.mem.rotate(u8, r.buffer, seek);
755 return r.buffer[0 .. end + 1];773 r.seek = 0;
774 r.end += i;
775 return r.buffer[0 .. seek + end + 1];
756 }776 }
777 } else if (i != 0) {
778 std.mem.rotate(u8, r.buffer, seek);
779 r.seek = 0;
780 r.end += i;
757 }781 }
758 return error.StreamTooLong;782 return error.StreamTooLong;
759}783}
...@@ -778,9 +802,10 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -778,9 +802,10 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
778pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {802pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
779 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {803 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
780 error.EndOfStream => {804 error.EndOfStream => {
781 if (r.end == 0) return error.EndOfStream;805 const remaining = r.buffer[r.seek..r.end];
782 r.toss(r.end);806 if (remaining.len == 0) return error.EndOfStream;
783 return r.buffer[0..r.end];807 r.toss(remaining.len);
808 return remaining;
784 },809 },
785 else => |e| return e,810 else => |e| return e,
786 };811 };
...@@ -808,8 +833,10 @@ pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -808,8 +833,10 @@ pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
808pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {833pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
809 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {834 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
810 error.EndOfStream => {835 error.EndOfStream => {
811 if (r.end == 0) return error.EndOfStream;836 const remaining = r.buffer[r.seek..r.end];
812 return r.buffer[0..r.end];837 if (remaining.len == 0) return error.EndOfStream;
838 r.toss(remaining.len);
839 return remaining;
813 },840 },
814 else => |e| return e,841 else => |e| return e,
815 };842 };
...@@ -1219,27 +1246,38 @@ test fixed {...@@ -1219,27 +1246,38 @@ test fixed {
1219}1246}
12201247
1221test peek {1248test peek {
1222 return error.Unimplemented;1249 var r: Reader = .fixed("abc");
1250 try testing.expectEqualStrings("ab", try r.peek(2));
1251 try testing.expectEqualStrings("a", try r.peek(1));
1223}1252}
12241253
1225test peekGreedy {1254test peekGreedy {
1226 return error.Unimplemented;1255 var r: Reader = .fixed("abc");
1256 try testing.expectEqualStrings("abc", try r.peekGreedy(1));
1227}1257}
12281258
1229test toss {1259test toss {
1230 return error.Unimplemented;1260 var r: Reader = .fixed("abc");
1261 r.toss(1);
1262 try testing.expectEqualStrings("bc", r.buffered());
1231}1263}
12321264
1233test take {1265test take {
1234 return error.Unimplemented;1266 var r: Reader = .fixed("abc");
1267 try testing.expectEqualStrings("ab", try r.take(2));
1268 try testing.expectEqualStrings("c", try r.take(1));
1235}1269}
12361270
1237test takeArray {1271test takeArray {
1238 return error.Unimplemented;1272 var r: Reader = .fixed("abc");
1273 try testing.expectEqualStrings("ab", try r.takeArray(2));
1274 try testing.expectEqualStrings("c", try r.takeArray(1));
1239}1275}
12401276
1241test peekArray {1277test peekArray {
1242 return error.Unimplemented;1278 var r: Reader = .fixed("abc");
1279 try testing.expectEqualStrings("ab", try r.peekArray(2));
1280 try testing.expectEqualStrings("a", try r.peekArray(1));
1243}1281}
12441282
1245test discardAll {1283test discardAll {
...@@ -1251,35 +1289,63 @@ test discardAll {...@@ -1251,35 +1289,63 @@ test discardAll {
1251}1289}
12521290
1253test discardRemaining {1291test discardRemaining {
1254 return error.Unimplemented;1292 var r: Reader = .fixed("foobar");
1293 r.toss(1);
1294 try testing.expectEqual(5, try r.discardRemaining());
1295 try testing.expectEqual(0, try r.discardRemaining());
1255}1296}
12561297
1257test stream {1298test stream {
1258 return error.Unimplemented;1299 var out_buffer: [10]u8 = undefined;
1300 var r: Reader = .fixed("foobar");
1301 var w: Writer = .fixed(&out_buffer);
1302 // Short streams are possible with this function but not with fixed.
1303 try testing.expectEqual(2, try r.stream(&w, .limited(2)));
1304 try testing.expectEqualStrings("fo", w.buffered());
1305 try testing.expectEqual(4, try r.stream(&w, .unlimited));
1306 try testing.expectEqualStrings("foobar", w.buffered());
1259}1307}
12601308
1261test takeSentinel {1309test takeSentinel {
1262 return error.Unimplemented;1310 var r: Reader = .fixed("ab\nc");
1311 try testing.expectEqualStrings("ab", try r.takeSentinel('\n'));
1312 try testing.expectError(error.EndOfStream, r.takeSentinel('\n'));
1313 try testing.expectEqualStrings("c", try r.peek(1));
1263}1314}
12641315
1265test peekSentinel {1316test peekSentinel {
1266 return error.Unimplemented;1317 var r: Reader = .fixed("ab\nc");
1318 try testing.expectEqualStrings("ab", try r.peekSentinel('\n'));
1319 try testing.expectEqualStrings("ab", try r.peekSentinel('\n'));
1267}1320}
12681321
1269test takeDelimiterInclusive {1322test takeDelimiterInclusive {
1270 return error.Unimplemented;1323 var r: Reader = .fixed("ab\nc");
1324 try testing.expectEqualStrings("ab\n", try r.takeDelimiterInclusive('\n'));
1325 try testing.expectError(error.EndOfStream, r.takeDelimiterInclusive('\n'));
1271}1326}
12721327
1273test peekDelimiterInclusive {1328test peekDelimiterInclusive {
1274 return error.Unimplemented;1329 var r: Reader = .fixed("ab\nc");
1330 try testing.expectEqualStrings("ab\n", try r.peekDelimiterInclusive('\n'));
1331 try testing.expectEqualStrings("ab\n", try r.peekDelimiterInclusive('\n'));
1332 r.toss(3);
1333 try testing.expectError(error.EndOfStream, r.peekDelimiterInclusive('\n'));
1275}1334}
12761335
1277test takeDelimiterExclusive {1336test takeDelimiterExclusive {
1278 return error.Unimplemented;1337 var r: Reader = .fixed("ab\nc");
1338 try testing.expectEqualStrings("ab", try r.takeDelimiterExclusive('\n'));
1339 try testing.expectEqualStrings("c", try r.takeDelimiterExclusive('\n'));
1340 try testing.expectError(error.EndOfStream, r.takeDelimiterExclusive('\n'));
1279}1341}
12801342
1281test peekDelimiterExclusive {1343test peekDelimiterExclusive {
1282 return error.Unimplemented;1344 var r: Reader = .fixed("ab\nc");
1345 try testing.expectEqualStrings("ab", try r.peekDelimiterExclusive('\n'));
1346 try testing.expectEqualStrings("ab", try r.peekDelimiterExclusive('\n'));
1347 r.toss(3);
1348 try testing.expectEqualStrings("c", try r.peekDelimiterExclusive('\n'));
1283}1349}
12841350
1285test readDelimiter {1351test readDelimiter {
...@@ -1339,7 +1405,11 @@ test peekStructEndian {...@@ -1339,7 +1405,11 @@ test peekStructEndian {
1339}1405}
13401406
1341test takeEnum {1407test takeEnum {
1342 return error.Unimplemented;1408 var r: Reader = .fixed(&.{ 2, 0, 1 });
1409 const E1 = enum(u8) { a, b, c };
1410 const E2 = enum(u16) { _ };
1411 try testing.expectEqual(E1.c, try r.takeEnum(E1, .little));
1412 try testing.expectEqual(@as(E2, @enumFromInt(0x0001)), try r.takeEnum(E2, .big));
1343}1413}
13441414
1345test takeLeb128 {1415test takeLeb128 {
lib/std/io/Writer.zig+34-26
...@@ -866,35 +866,31 @@ pub fn printValue(...@@ -866,35 +866,31 @@ pub fn printValue(
866 }866 }
867 const enum_info = @typeInfo(T).@"enum";867 const enum_info = @typeInfo(T).@"enum";
868 if (enum_info.is_exhaustive) {868 if (enum_info.is_exhaustive) {
869 var vecs: [3][]const u8 = .{ @typeName(T), ".", @tagName(value) };869 var vecs: [2][]const u8 = .{ ".", @tagName(value) };
870 try w.writeVecAll(&vecs);870 try w.writeVecAll(&vecs);
871 return;871 return;
872 }872 }
873 try w.writeAll(@typeName(T));873 if (std.enums.tagName(T, value)) |tag_name| {
874 @setEvalBranchQuota(3 * enum_info.fields.len);874 var vecs: [2][]const u8 = .{ ".", tag_name };
875 inline for (enum_info.fields) |field| {875 try w.writeVecAll(&vecs);
876 if (@intFromEnum(value) == field.value) {876 return;
877 try w.writeAll(".");
878 try w.writeAll(@tagName(value));
879 return;
880 }
881 }877 }
882 try w.writeByte('(');878 try w.writeAll("@enumFromInt(");
883 try w.printValue(ANY, options, @intFromEnum(value), max_depth);879 try w.printValue(ANY, options, @intFromEnum(value), max_depth);
884 try w.writeByte(')');880 try w.writeByte(')');
881 return;
885 },882 },
886 .@"union" => |info| {883 .@"union" => |info| {
887 if (!is_any) {884 if (!is_any) {
888 if (fmt.len != 0) invalidFmtError(fmt, value);885 if (fmt.len != 0) invalidFmtError(fmt, value);
889 return printValue(w, ANY, options, value, max_depth);886 return printValue(w, ANY, options, value, max_depth);
890 }887 }
891 try w.writeAll(@typeName(T));
892 if (max_depth == 0) {888 if (max_depth == 0) {
893 try w.writeAll("{ ... }");889 try w.writeAll(".{ ... }");
894 return;890 return;
895 }891 }
896 if (info.tag_type) |UnionTagType| {892 if (info.tag_type) |UnionTagType| {
897 try w.writeAll("{ .");893 try w.writeAll(".{ .");
898 try w.writeAll(@tagName(@as(UnionTagType, value)));894 try w.writeAll(@tagName(@as(UnionTagType, value)));
899 try w.writeAll(" = ");895 try w.writeAll(" = ");
900 inline for (info.fields) |u_field| {896 inline for (info.fields) |u_field| {
...@@ -903,9 +899,22 @@ pub fn printValue(...@@ -903,9 +899,22 @@ pub fn printValue(
903 }899 }
904 }900 }
905 try w.writeAll(" }");901 try w.writeAll(" }");
906 } else {902 } else switch (info.layout) {
907 try w.writeByte('@');903 .auto => {
908 try w.printIntOptions(@intFromPtr(&value), 16, .lower, options);904 return w.writeAll(".{ ... }");
905 },
906 .@"extern", .@"packed" => {
907 if (info.fields.len == 0) return w.writeAll(".{}");
908 try w.writeAll(".{ ");
909 inline for (info.fields) |field| {
910 try w.writeByte('.');
911 try w.writeAll(field.name);
912 try w.writeAll(" = ");
913 try w.printValue(ANY, options, @field(value, field.name), max_depth - 1);
914 (try w.writableArray(2)).* = ", ".*;
915 }
916 w.buffer[w.end - 2 ..][0..2].* = " }".*;
917 },
909 }918 }
910 },919 },
911 .@"struct" => |info| {920 .@"struct" => |info| {
...@@ -916,10 +925,10 @@ pub fn printValue(...@@ -916,10 +925,10 @@ pub fn printValue(
916 if (info.is_tuple) {925 if (info.is_tuple) {
917 // Skip the type and field names when formatting tuples.926 // Skip the type and field names when formatting tuples.
918 if (max_depth == 0) {927 if (max_depth == 0) {
919 try w.writeAll("{ ... }");928 try w.writeAll(".{ ... }");
920 return;929 return;
921 }930 }
922 try w.writeAll("{");931 try w.writeAll(".{");
923 inline for (info.fields, 0..) |f, i| {932 inline for (info.fields, 0..) |f, i| {
924 if (i == 0) {933 if (i == 0) {
925 try w.writeAll(" ");934 try w.writeAll(" ");
...@@ -931,12 +940,11 @@ pub fn printValue(...@@ -931,12 +940,11 @@ pub fn printValue(
931 try w.writeAll(" }");940 try w.writeAll(" }");
932 return;941 return;
933 }942 }
934 try w.writeAll(@typeName(T));
935 if (max_depth == 0) {943 if (max_depth == 0) {
936 try w.writeAll("{ ... }");944 try w.writeAll(".{ ... }");
937 return;945 return;
938 }946 }
939 try w.writeAll("{");947 try w.writeAll(".{");
940 inline for (info.fields, 0..) |f, i| {948 inline for (info.fields, 0..) |f, i| {
941 if (i == 0) {949 if (i == 0) {
942 try w.writeAll(" .");950 try w.writeAll(" .");
...@@ -1550,7 +1558,7 @@ fn writeMultipleOf7Leb128(w: *Writer, value: anytype) Error!void {...@@ -1550,7 +1558,7 @@ fn writeMultipleOf7Leb128(w: *Writer, value: anytype) Error!void {
1550 }1558 }
1551}1559}
15521560
1553test "formatValue max_depth" {1561test "printValue max_depth" {
1554 const Vec2 = struct {1562 const Vec2 = struct {
1555 const SelfType = @This();1563 const SelfType = @This();
1556 x: f32,1564 x: f32,
...@@ -1595,19 +1603,19 @@ test "formatValue max_depth" {...@@ -1595,19 +1603,19 @@ test "formatValue max_depth" {
1595 var buf: [1000]u8 = undefined;1603 var buf: [1000]u8 = undefined;
1596 var w: Writer = .fixed(&buf);1604 var w: Writer = .fixed(&buf);
1597 try w.printValue("", .{}, inst, 0);1605 try w.printValue("", .{}, inst, 0);
1598 try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ ... }", w.buffered());1606 try testing.expectEqualStrings(".{ ... }", w.buffered());
15991607
1600 w = .fixed(&buf);1608 w = .fixed(&buf);
1601 try w.printValue("", .{}, inst, 1);1609 try w.printValue("", .{}, inst, 1);
1602 try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered());1610 try testing.expectEqualStrings(".{ .a = .{ ... }, .tu = .{ ... }, .e = .Two, .vec = .{ ... } }", w.buffered());
16031611
1604 w = .fixed(&buf);1612 w = .fixed(&buf);
1605 try w.printValue("", .{}, inst, 2);1613 try w.printValue("", .{}, inst, 2);
1606 try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered());1614 try testing.expectEqualStrings(".{ .a = .{ .a = .{ ... }, .tu = .{ ... }, .e = .Two, .vec = .{ ... } }, .tu = .{ .ptr = .{ ... } }, .e = .Two, .vec = .{ .x = 10.2, .y = 2.22 } }", w.buffered());
16071615
1608 w = .fixed(&buf);1616 w = .fixed(&buf);
1609 try w.printValue("", .{}, inst, 3);1617 try w.printValue("", .{}, inst, 3);
1610 try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered());1618 try testing.expectEqualStrings(".{ .a = .{ .a = .{ .a = .{ ... }, .tu = .{ ... }, .e = .Two, .vec = .{ ... } }, .tu = .{ .ptr = .{ ... } }, .e = .Two, .vec = .{ .x = 10.2, .y = 2.22 } }, .tu = .{ .ptr = .{ .ptr = .{ ... } } }, .e = .Two, .vec = .{ .x = 10.2, .y = 2.22 } }", w.buffered());
16111619
1612 const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 };1620 const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 };
1613 w = .fixed(&buf);1621 w = .fixed(&buf);
lib/std/net/test.zig+9-33
...@@ -5,7 +5,6 @@ const mem = std.mem;...@@ -5,7 +5,6 @@ const mem = std.mem;
5const testing = std.testing;5const testing = std.testing;
66
7test "parse and render IP addresses at comptime" {7test "parse and render IP addresses at comptime" {
8 if (builtin.os.tag == .wasi) return error.SkipZigTest;
9 comptime {8 comptime {
10 const ipv6addr = net.Address.parseIp("::1", 0) catch unreachable;9 const ipv6addr = net.Address.parseIp("::1", 0) catch unreachable;
11 try std.testing.expectFmt("[::1]:0", "{f}", .{ipv6addr});10 try std.testing.expectFmt("[::1]:0", "{f}", .{ipv6addr});
...@@ -21,42 +20,23 @@ test "parse and render IP addresses at comptime" {...@@ -21,42 +20,23 @@ test "parse and render IP addresses at comptime" {
21}20}
2221
23test "format IPv6 address with no zero runs" {22test "format IPv6 address with no zero runs" {
24 if (builtin.os.tag == .wasi) return error.SkipZigTest;
25 const addr = try std.net.Address.parseIp6("2001:db8:1:2:3:4:5:6", 0);23 const addr = try std.net.Address.parseIp6("2001:db8:1:2:3:4:5:6", 0);
26 try std.testing.expectFmt("[2001:db8:1:2:3:4:5:6]:0", "{f}", .{addr});24 try std.testing.expectFmt("[2001:db8:1:2:3:4:5:6]:0", "{f}", .{addr});
27}25}
2826
29test "parse IPv6 addresses and check compressed form" {27test "parse IPv6 addresses and check compressed form" {
30 if (builtin.os.tag == .wasi) return error.SkipZigTest;28 try std.testing.expectFmt("[2001:db8::1:0:0:2]:0", "{f}", .{
3129 try std.net.Address.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0),
32 const alloc = testing.allocator;30 });
3331 try std.testing.expectFmt("[2001:db8::1:2]:0", "{f}", .{
34 // 1) Parse an IPv6 address that should compress to [2001:db8::1:0:0:2]:032 try std.net.Address.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0),
35 const addr1 = try std.net.Address.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0);33 });
3634 try std.testing.expectFmt("[2001:db8:1:0:1::2]:0", "{f}", .{
37 // 2) Parse an IPv6 address that should compress to [2001:db8::1:2]:035 try std.net.Address.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0),
38 const addr2 = try std.net.Address.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0);36 });
39
40 // 3) Parse an IPv6 address that should compress to [2001:db8:1:0:1::2]:0
41 const addr3 = try std.net.Address.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0);
42
43 // Print each address in Zig's default "[ipv6]:port" form.
44 const printed1 = try std.fmt.allocPrint(alloc, "{any}", .{addr1});
45 defer testing.allocator.free(printed1);
46 const printed2 = try std.fmt.allocPrint(alloc, "{any}", .{addr2});
47 defer testing.allocator.free(printed2);
48 const printed3 = try std.fmt.allocPrint(alloc, "{any}", .{addr3});
49 defer testing.allocator.free(printed3);
50
51 // Check the exact compressed forms we expect.
52 try std.testing.expectEqualStrings("[2001:db8::1:0:0:2]:0", printed1);
53 try std.testing.expectEqualStrings("[2001:db8::1:2]:0", printed2);
54 try std.testing.expectEqualStrings("[2001:db8:1:0:1::2]:0", printed3);
55}37}
5638
57test "parse IPv6 address, check raw bytes" {39test "parse IPv6 address, check raw bytes" {
58 if (builtin.os.tag == .wasi) return error.SkipZigTest;
59
60 const expected_raw: [16]u8 = .{40 const expected_raw: [16]u8 = .{
61 0x20, 0x01, 0x0d, 0xb8, // 2001:db841 0x20, 0x01, 0x0d, 0xb8, // 2001:db8
62 0x00, 0x00, 0x00, 0x00, // :0000:000042 0x00, 0x00, 0x00, 0x00, // :0000:0000
...@@ -71,8 +51,6 @@ test "parse IPv6 address, check raw bytes" {...@@ -71,8 +51,6 @@ test "parse IPv6 address, check raw bytes" {
71}51}
7252
73test "parse and render IPv6 addresses" {53test "parse and render IPv6 addresses" {
74 if (builtin.os.tag == .wasi) return error.SkipZigTest;
75
76 var buffer: [100]u8 = undefined;54 var buffer: [100]u8 = undefined;
77 const ips = [_][]const u8{55 const ips = [_][]const u8{
78 "FF01:0:0:0:0:0:0:FB",56 "FF01:0:0:0:0:0:0:FB",
...@@ -137,8 +115,6 @@ test "invalid but parseable IPv6 scope ids" {...@@ -137,8 +115,6 @@ test "invalid but parseable IPv6 scope ids" {
137}115}
138116
139test "parse and render IPv4 addresses" {117test "parse and render IPv4 addresses" {
140 if (builtin.os.tag == .wasi) return error.SkipZigTest;
141
142 var buffer: [18]u8 = undefined;118 var buffer: [18]u8 = undefined;
143 for ([_][]const u8{119 for ([_][]const u8{
144 "0.0.0.0",120 "0.0.0.0",