authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-06-17 22:03:56+12:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-17 13:00:00-04:00
logd5d0942a0dd5366e7e9a0843bf40878e6f0e1f2c
treeb6a216a35f94be01c1d45d9804b8a756d2f11cca
parent50c8a93a5e2313ffb4183894637ecbd7f4dc50fa

Small cleanup of fmt.zig

Use inferred enum literals and split the large test case up.

1 files changed, 254 insertions(+), 197 deletions(-)

std/fmt.zig+254-197
......@@ -13,7 +13,13 @@ pub const default_max_depth = 3;
1313/// Renders fmt string with args, calling output with slices of bytes.
1414/// If `output` returns an error, the error is returned from `format` and
1515/// `output` is not called again.
16pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
16pub fn format(
17 context: var,
18 comptime Errors: type,
19 output: fn (@typeOf(context), []const u8) Errors!void,
20 comptime fmt: []const u8,
21 args: ...,
22) Errors!void {
1723 const State = enum {
1824 Start,
1925 OpenBrace,
......@@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
2834
2935 inline for (fmt) |c, i| {
3036 switch (state) {
31 State.Start => switch (c) {
37 .Start => switch (c) {
3238 '{' => {
3339 if (start_index < i) {
3440 try output(context, fmt[start_index..i]);
......@@ -45,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
4551 },
4652 else => {},
4753 },
48 State.OpenBrace => switch (c) {
54 .OpenBrace => switch (c) {
4955 '{' => {
5056 state = State.Start;
5157 start_index = i;
......@@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
6167 state = State.FormatString;
6268 },
6369 },
64 State.CloseBrace => switch (c) {
70 .CloseBrace => switch (c) {
6571 '}' => {
6672 state = State.Start;
6773 start_index = i;
6874 },
6975 else => @compileError("Single '}' encountered in format string"),
7076 },
71 State.FormatString => switch (c) {
77 .FormatString => switch (c) {
7278 '}' => {
7379 const s = start_index + 1;
7480 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);
......@@ -78,7 +84,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
7884 },
7985 else => {},
8086 },
81 State.Pointer => switch (c) {
87 .Pointer => switch (c) {
8288 '}' => {
8389 try output(context, @typeName(@typeOf(args[next_arg]).Child));
8490 try output(context, "@");
......@@ -114,88 +120,93 @@ pub fn formatType(
114120) Errors!void {
115121 const T = @typeOf(value);
116122 switch (@typeInfo(T)) {
117 builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
123 .ComptimeInt, .Int, .Float => {
118124 return formatValue(value, fmt, context, Errors, output);
119125 },
120 builtin.TypeId.Void => {
126 .Void => {
121127 return output(context, "void");
122128 },
123 builtin.TypeId.Bool => {
129 .Bool => {
124130 return output(context, if (value) "true" else "false");
125131 },
126 builtin.TypeId.Optional => {
132 .Optional => {
127133 if (value) |payload| {
128134 return formatType(payload, fmt, context, Errors, output, max_depth);
129135 } else {
130136 return output(context, "null");
131137 }
132138 },
133 builtin.TypeId.ErrorUnion => {
139 .ErrorUnion => {
134140 if (value) |payload| {
135141 return formatType(payload, fmt, context, Errors, output, max_depth);
136142 } else |err| {
137143 return formatType(err, fmt, context, Errors, output, max_depth);
138144 }
139145 },
140 builtin.TypeId.ErrorSet => {
146 .ErrorSet => {
141147 try output(context, "error.");
142148 return output(context, @errorName(value));
143149 },
144 builtin.TypeId.Promise => {
150 .Promise => {
145151 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
146152 },
147 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
148 if (comptime std.meta.trait.hasFn("format")(T)) return value.format(fmt, context, Errors, output);
153 .Enum => {
154 if (comptime std.meta.trait.hasFn("format")(T)) {
155 return value.format(fmt, context, Errors, output);
156 }
149157
150158 try output(context, @typeName(T));
151 switch (comptime @typeId(T)) {
152 builtin.TypeId.Enum => {
153 try output(context, ".");
154 try formatType(@tagName(value), "", context, Errors, output, max_depth);
155 return;
156 },
157 builtin.TypeId.Struct => {
158 if (max_depth == 0) {
159 return output(context, "{ ... }");
160 }
161 comptime var field_i = 0;
162 inline while (field_i < @memberCount(T)) : (field_i += 1) {
163 if (field_i == 0) {
164 try output(context, "{ .");
165 } else {
166 try output(context, ", .");
167 }
168 try output(context, @memberName(T, field_i));
169 try output(context, " = ");
170 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);
171 }
172 try output(context, " }");
173 },
174 builtin.TypeId.Union => {
175 if (max_depth == 0) {
176 return output(context, "{ ... }");
177 }
178 const info = @typeInfo(T).Union;
179 if (info.tag_type) |UnionTagType| {
180 try output(context, "{ .");
181 try output(context, @tagName(UnionTagType(value)));
182 try output(context, " = ");
183 inline for (info.fields) |u_field| {
184 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
185 try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth - 1);
186 }
187 }
188 try output(context, " }");
189 } else {
190 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
159 try output(context, ".");
160 return formatType(@tagName(value), "", context, Errors, output, max_depth);
161 },
162 .Union => {
163 if (comptime std.meta.trait.hasFn("format")(T)) {
164 return value.format(fmt, context, Errors, output);
165 }
166
167 try output(context, @typeName(T));
168 if (max_depth == 0) {
169 return output(context, "{ ... }");
170 }
171 const info = @typeInfo(T).Union;
172 if (info.tag_type) |UnionTagType| {
173 try output(context, "{ .");
174 try output(context, @tagName(UnionTagType(value)));
175 try output(context, " = ");
176 inline for (info.fields) |u_field| {
177 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
178 try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth - 1);
191179 }
192 },
193 else => unreachable,
180 }
181 try output(context, " }");
182 } else {
183 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
194184 }
195 return;
196185 },
197 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
198 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
186 .Struct => {
187 if (comptime std.meta.trait.hasFn("format")(T)) {
188 return value.format(fmt, context, Errors, output);
189 }
190
191 try output(context, @typeName(T));
192 if (max_depth == 0) {
193 return output(context, "{ ... }");
194 }
195 comptime var field_i = 0;
196 inline while (field_i < @memberCount(T)) : (field_i += 1) {
197 if (field_i == 0) {
198 try output(context, "{ .");
199 } else {
200 try output(context, ", .");
201 }
202 try output(context, @memberName(T, field_i));
203 try output(context, " = ");
204 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);
205 }
206 try output(context, " }");
207 },
208 .Pointer => |ptr_info| switch (ptr_info.size) {
209 .One => switch (@typeInfo(ptr_info.child)) {
199210 builtin.TypeId.Array => |info| {
200211 if (info.child == u8) {
201212 return formatText(value, fmt, context, Errors, output);
......@@ -207,7 +218,7 @@ pub fn formatType(
207218 },
208219 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
209220 },
210 builtin.TypeInfo.Pointer.Size.Many => {
221 .Many => {
211222 if (ptr_info.child == u8) {
212223 if (fmt.len > 0 and fmt[0] == 's') {
213224 const len = mem.len(u8, value);
......@@ -216,7 +227,7 @@ pub fn formatType(
216227 }
217228 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
218229 },
219 builtin.TypeInfo.Pointer.Size.Slice => {
230 .Slice => {
220231 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
221232 return formatText(value, fmt, context, Errors, output);
222233 }
......@@ -225,17 +236,17 @@ pub fn formatType(
225236 }
226237 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
227238 },
228 builtin.TypeInfo.Pointer.Size.C => {
239 .C => {
229240 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
230241 },
231242 },
232 builtin.TypeId.Array => |info| {
243 .Array => |info| {
233244 if (info.child == u8) {
234245 return formatText(value, fmt, context, Errors, output);
235246 }
236247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
237248 },
238 builtin.TypeId.Fn => {
249 .Fn => {
239250 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
240251 },
241252 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
......@@ -249,24 +260,24 @@ fn formatValue(
249260 comptime Errors: type,
250261 output: fn (@typeOf(context), []const u8) Errors!void,
251262) Errors!void {
252 if (fmt.len > 0) {
253 if (fmt[0] == 'B') {
254 comptime var width: ?usize = null;
255 if (fmt.len > 1) {
256 if (fmt[1] == 'i') {
257 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
258 return formatBytes(value, width, 1024, context, Errors, output);
263 if (fmt.len > 0 and fmt[0] == 'B') {
264 comptime var width: ?usize = null;
265 if (fmt.len > 1) {
266 if (fmt[1] == 'i') {
267 if (fmt.len > 2) {
268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
259269 }
260 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
270 return formatBytes(value, width, 1024, context, Errors, output);
261271 }
262 return formatBytes(value, width, 1000, context, Errors, output);
272 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
263273 }
274 return formatBytes(value, width, 1000, context, Errors, output);
264275 }
265276
266277 const T = @typeOf(value);
267278 switch (@typeId(T)) {
268 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
269 builtin.TypeId.Int, builtin.TypeId.ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
279 .Float => return formatFloatValue(value, fmt, context, Errors, output),
280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
270281 else => comptime unreachable,
271282 }
272283}
......@@ -797,7 +808,7 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
797808 }
798809}
799810
800test "fmt.parseInt" {
811test "parseInt" {
801812 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
802813 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
803814 testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
......@@ -828,7 +839,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
828839 return x;
829840}
830841
831test "fmt.parseUnsigned" {
842test "parseUnsigned" {
832843 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
833844 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
834845 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
......@@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
913924 size.* += bytes.len;
914925}
915926
916test "buf print int" {
927test "bufPrintInt" {
917928 var buffer: [100]u8 = undefined;
918929 const buf = buffer[0..];
919930 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
......@@ -949,7 +960,7 @@ test "parse unsigned comptime" {
949960 }
950961}
951962
952test "fmt.format" {
963test "fmt.optional" {
953964 {
954965 const value: ?i32 = 1234;
955966 try testFmt("optional: 1234\n", "optional: {}\n", value);
......@@ -958,6 +969,9 @@ test "fmt.format" {
958969 const value: ?i32 = null;
959970 try testFmt("optional: null\n", "optional: {}\n", value);
960971 }
972}
973
974test "fmt.error" {
961975 {
962976 const value: anyerror!i32 = 1234;
963977 try testFmt("error union: 1234\n", "error union: {}\n", value);
......@@ -966,10 +980,16 @@ test "fmt.format" {
966980 const value: anyerror!i32 = error.InvalidChar;
967981 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
968982 }
983}
984
985test "fmt.int.small" {
969986 {
970987 const value: u3 = 0b101;
971988 try testFmt("u3: 5\n", "u3: {}\n", value);
972989 }
990}
991
992test "fmt.int.specifier" {
973993 {
974994 const value: u8 = 'a';
975995 try testFmt("u8: a\n", "u8: {c}\n", value);
......@@ -978,6 +998,9 @@ test "fmt.format" {
978998 const value: u8 = 0b1100;
979999 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
9801000 }
1001}
1002
1003test "fmt.buffer" {
9811004 {
9821005 var buf1: [32]u8 = undefined;
9831006 var context = BufPrintContext{ .remaining = buf1[0..] };
......@@ -995,6 +1018,9 @@ test "fmt.format" {
9951018 res = buf1[0 .. buf1.len - context.remaining.len];
9961019 testing.expect(mem.eql(u8, res, "1100"));
9971020 }
1021}
1022
1023test "fmt.array" {
9981024 {
9991025 const value: [3]u8 = "abc";
10001026 try testFmt("array: abc\n", "array: {}\n", value);
......@@ -1007,6 +1033,9 @@ test "fmt.format" {
10071033 &value,
10081034 );
10091035 }
1036}
1037
1038test "fmt.slice" {
10101039 {
10111040 const value: []const u8 = "abc";
10121041 try testFmt("slice: abc\n", "slice: {}\n", value);
......@@ -1015,6 +1044,12 @@ test "fmt.format" {
10151044 const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0];
10161045 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
10171046 }
1047
1048 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1049 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1050}
1051
1052test "fmt.pointer" {
10181053 {
10191054 const value = @intToPtr(*i32, 0xdeadbeef);
10201055 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
......@@ -1028,12 +1063,19 @@ test "fmt.format" {
10281063 const value = @intToPtr(fn () void, 0xdeadbeef);
10291064 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
10301065 }
1031 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1032 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1066}
1067
1068test "fmt.cstr" {
10331069 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
10341070 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
1071}
1072
1073test "fmt.filesize" {
10351074 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
10361075 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
1076}
1077
1078test "fmt.struct" {
10371079 {
10381080 const Struct = struct {
10391081 field: u8,
......@@ -1050,15 +1092,19 @@ test "fmt.format" {
10501092 const value = Struct{ .a = 0, .b = 1 };
10511093 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
10521094 }
1053 {
1054 const Enum = enum {
1055 One,
1056 Two,
1057 };
1058 const value = Enum.Two;
1059 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
1060 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1061 }
1095}
1096
1097test "fmt.enum" {
1098 const Enum = enum {
1099 One,
1100 Two,
1101 };
1102 const value = Enum.Two;
1103 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
1104 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1105}
1106
1107test "fmt.float.scientific" {
10621108 {
10631109 var buf1: [32]u8 = undefined;
10641110 const value: f32 = 1.34;
......@@ -1088,6 +1134,9 @@ test "fmt.format" {
10881134 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
10891135 }
10901136 }
1137}
1138
1139test "fmt.float.scientific.precision" {
10911140 {
10921141 var buf1: [32]u8 = undefined;
10931142 const value: f64 = 1.409706e-42;
......@@ -1114,6 +1163,9 @@ test "fmt.format" {
11141163 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
11151164 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
11161165 }
1166}
1167
1168test "fmt.float.special" {
11171169 {
11181170 var buf1: [32]u8 = undefined;
11191171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
......@@ -1136,6 +1188,9 @@ test "fmt.format" {
11361188 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
11371189 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
11381190 }
1191}
1192
1193test "fmt.float.decimal" {
11391194 {
11401195 var buf1: [64]u8 = undefined;
11411196 const value: f64 = 1.52314e+29;
......@@ -1216,7 +1271,9 @@ test "fmt.format" {
12161271 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
12171272 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
12181273 }
1219 // libc checks
1274}
1275
1276test "fmt.float.libc.sanity" {
12201277 {
12211278 var buf1: [32]u8 = undefined;
12221279 const value: f64 = f64(@bitCast(f32, u32(916964781)));
......@@ -1267,127 +1324,127 @@ test "fmt.format" {
12671324 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
12681325 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
12691326 }
1270 //custom type format
1271 {
1272 const Vec2 = struct {
1273 const SelfType = @This();
1274 x: f32,
1275 y: f32,
1276
1277 pub fn format(
1278 self: SelfType,
1279 comptime fmt: []const u8,
1280 context: var,
1281 comptime Errors: type,
1282 output: fn (@typeOf(context), []const u8) Errors!void,
1283 ) Errors!void {
1284 switch (fmt.len) {
1285 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1286 1 => switch (fmt[0]) {
1287 //point format
1288 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1289 //dimension format
1290 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1291 else => unreachable,
1292 },
1327}
1328
1329test "fmt.custom" {
1330 const Vec2 = struct {
1331 const SelfType = @This();
1332 x: f32,
1333 y: f32,
1334
1335 pub fn format(
1336 self: SelfType,
1337 comptime fmt: []const u8,
1338 context: var,
1339 comptime Errors: type,
1340 output: fn (@typeOf(context), []const u8) Errors!void,
1341 ) Errors!void {
1342 switch (fmt.len) {
1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1344 1 => switch (fmt[0]) {
1345 //point format
1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1347 //dimension format
1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
12931349 else => unreachable,
1294 }
1350 },
1351 else => unreachable,
12951352 }
1296 };
1353 }
1354 };
12971355
1298 var buf1: [32]u8 = undefined;
1299 var value = Vec2{
1300 .x = 10.2,
1301 .y = 2.22,
1302 };
1303 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1304 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
1356 var buf1: [32]u8 = undefined;
1357 var value = Vec2{
1358 .x = 10.2,
1359 .y = 2.22,
1360 };
1361 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1362 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
13051363
1306 // same thing but not passing a pointer
1307 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1308 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1309 }
1310 //struct format
1311 {
1312 const S = struct {
1313 a: u32,
1314 b: anyerror,
1315 };
1364 // same thing but not passing a pointer
1365 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1366 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1367}
13161368
1317 const inst = S{
1318 .a = 456,
1319 .b = error.Unused,
1320 };
1369test "fmt.struct" {
1370 const S = struct {
1371 a: u32,
1372 b: anyerror,
1373 };
13211374
1322 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1323 }
1324 //union format
1325 {
1326 const TU = union(enum) {
1327 float: f32,
1328 int: u32,
1329 };
1375 const inst = S{
1376 .a = 456,
1377 .b = error.Unused,
1378 };
13301379
1331 const UU = union {
1332 float: f32,
1333 int: u32,
1334 };
1380 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1381}
13351382
1336 const EU = extern union {
1337 float: f32,
1338 int: u32,
1339 };
1383test "fmt.union" {
1384 const TU = union(enum) {
1385 float: f32,
1386 int: u32,
1387 };
13401388
1341 const tu_inst = TU{ .int = 123 };
1342 const uu_inst = UU{ .int = 456 };
1343 const eu_inst = EU{ .float = 321.123 };
1389 const UU = union {
1390 float: f32,
1391 int: u32,
1392 };
13441393
1345 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
1394 const EU = extern union {
1395 float: f32,
1396 int: u32,
1397 };
13461398
1347 var buf: [100]u8 = undefined;
1348 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1349 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
1399 const tu_inst = TU{ .int = 123 };
1400 const uu_inst = UU{ .int = 456 };
1401 const eu_inst = EU{ .float = 321.123 };
13501402
1351 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1352 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1353 }
1354 //enum format
1355 {
1356 const E = enum {
1357 One,
1358 Two,
1359 Three,
1360 };
1403 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
13611404
1362 const inst = E.Two;
1405 var buf: [100]u8 = undefined;
1406 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1407 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
13631408
1364 try testFmt("E.Two", "{}", inst);
1365 }
1366 //self-referential struct format
1367 {
1368 const S = struct {
1369 const SelfType = @This();
1370 a: ?*SelfType,
1371 };
1409 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1410 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1411}
13721412
1373 var inst = S{
1374 .a = null,
1375 };
1376 inst.a = &inst;
1413test "fmt.enum" {
1414 const E = enum {
1415 One,
1416 Two,
1417 Three,
1418 };
13771419
1378 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
1379 }
1380 //print bytes as hex
1381 {
1382 const some_bytes = "\xCA\xFE\xBA\xBE";
1383 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1384 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1385 //Test Slices
1386 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
1387 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
1388 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1389 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
1390 }
1420 const inst = E.Two;
1421
1422 try testFmt("E.Two", "{}", inst);
1423}
1424
1425test "fmt.struct.self-referential" {
1426 const S = struct {
1427 const SelfType = @This();
1428 a: ?*SelfType,
1429 };
1430
1431 var inst = S{
1432 .a = null,
1433 };
1434 inst.a = &inst;
1435
1436 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
1437}
1438
1439test "fmt.bytes.hex" {
1440 const some_bytes = "\xCA\xFE\xBA\xBE";
1441 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1442 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1443 //Test Slices
1444 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
1445 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
1446 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1447 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
13911448}
13921449
13931450fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {