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;...@@ -13,7 +13,13 @@ pub const default_max_depth = 3;
13/// Renders fmt string with args, calling output with slices of bytes.13/// Renders fmt string with args, calling output with slices of bytes.
14/// If `output` returns an error, the error is returned from `format` and14/// If `output` returns an error, the error is returned from `format` and
15/// `output` is not called again.15/// `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 {
17 const State = enum {23 const State = enum {
18 Start,24 Start,
19 OpenBrace,25 OpenBrace,
...@@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),...@@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
2834
29 inline for (fmt) |c, i| {35 inline for (fmt) |c, i| {
30 switch (state) {36 switch (state) {
31 State.Start => switch (c) {37 .Start => switch (c) {
32 '{' => {38 '{' => {
33 if (start_index < i) {39 if (start_index < i) {
34 try output(context, fmt[start_index..i]);40 try output(context, fmt[start_index..i]);
...@@ -45,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),...@@ -45,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
45 },51 },
46 else => {},52 else => {},
47 },53 },
48 State.OpenBrace => switch (c) {54 .OpenBrace => switch (c) {
49 '{' => {55 '{' => {
50 state = State.Start;56 state = State.Start;
51 start_index = i;57 start_index = i;
...@@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),...@@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
61 state = State.FormatString;67 state = State.FormatString;
62 },68 },
63 },69 },
64 State.CloseBrace => switch (c) {70 .CloseBrace => switch (c) {
65 '}' => {71 '}' => {
66 state = State.Start;72 state = State.Start;
67 start_index = i;73 start_index = i;
68 },74 },
69 else => @compileError("Single '}' encountered in format string"),75 else => @compileError("Single '}' encountered in format string"),
70 },76 },
71 State.FormatString => switch (c) {77 .FormatString => switch (c) {
72 '}' => {78 '}' => {
73 const s = start_index + 1;79 const s = start_index + 1;
74 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);80 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),...@@ -78,7 +84,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
78 },84 },
79 else => {},85 else => {},
80 },86 },
81 State.Pointer => switch (c) {87 .Pointer => switch (c) {
82 '}' => {88 '}' => {
83 try output(context, @typeName(@typeOf(args[next_arg]).Child));89 try output(context, @typeName(@typeOf(args[next_arg]).Child));
84 try output(context, "@");90 try output(context, "@");
...@@ -114,88 +120,93 @@ pub fn formatType(...@@ -114,88 +120,93 @@ pub fn formatType(
114) Errors!void {120) Errors!void {
115 const T = @typeOf(value);121 const T = @typeOf(value);
116 switch (@typeInfo(T)) {122 switch (@typeInfo(T)) {
117 builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {123 .ComptimeInt, .Int, .Float => {
118 return formatValue(value, fmt, context, Errors, output);124 return formatValue(value, fmt, context, Errors, output);
119 },125 },
120 builtin.TypeId.Void => {126 .Void => {
121 return output(context, "void");127 return output(context, "void");
122 },128 },
123 builtin.TypeId.Bool => {129 .Bool => {
124 return output(context, if (value) "true" else "false");130 return output(context, if (value) "true" else "false");
125 },131 },
126 builtin.TypeId.Optional => {132 .Optional => {
127 if (value) |payload| {133 if (value) |payload| {
128 return formatType(payload, fmt, context, Errors, output, max_depth);134 return formatType(payload, fmt, context, Errors, output, max_depth);
129 } else {135 } else {
130 return output(context, "null");136 return output(context, "null");
131 }137 }
132 },138 },
133 builtin.TypeId.ErrorUnion => {139 .ErrorUnion => {
134 if (value) |payload| {140 if (value) |payload| {
135 return formatType(payload, fmt, context, Errors, output, max_depth);141 return formatType(payload, fmt, context, Errors, output, max_depth);
136 } else |err| {142 } else |err| {
137 return formatType(err, fmt, context, Errors, output, max_depth);143 return formatType(err, fmt, context, Errors, output, max_depth);
138 }144 }
139 },145 },
140 builtin.TypeId.ErrorSet => {146 .ErrorSet => {
141 try output(context, "error.");147 try output(context, "error.");
142 return output(context, @errorName(value));148 return output(context, @errorName(value));
143 },149 },
144 builtin.TypeId.Promise => {150 .Promise => {
145 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));151 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
146 },152 },
147 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {153 .Enum => {
148 if (comptime std.meta.trait.hasFn("format")(T)) return value.format(fmt, context, Errors, output);154 if (comptime std.meta.trait.hasFn("format")(T)) {
155 return value.format(fmt, context, Errors, output);
156 }
149157
150 try output(context, @typeName(T));158 try output(context, @typeName(T));
151 switch (comptime @typeId(T)) {159 try output(context, ".");
152 builtin.TypeId.Enum => {160 return formatType(@tagName(value), "", context, Errors, output, max_depth);
153 try output(context, ".");161 },
154 try formatType(@tagName(value), "", context, Errors, output, max_depth);162 .Union => {
155 return;163 if (comptime std.meta.trait.hasFn("format")(T)) {
156 },164 return value.format(fmt, context, Errors, output);
157 builtin.TypeId.Struct => {165 }
158 if (max_depth == 0) {166
159 return output(context, "{ ... }");167 try output(context, @typeName(T));
160 }168 if (max_depth == 0) {
161 comptime var field_i = 0;169 return output(context, "{ ... }");
162 inline while (field_i < @memberCount(T)) : (field_i += 1) {170 }
163 if (field_i == 0) {171 const info = @typeInfo(T).Union;
164 try output(context, "{ .");172 if (info.tag_type) |UnionTagType| {
165 } else {173 try output(context, "{ .");
166 try output(context, ", .");174 try output(context, @tagName(UnionTagType(value)));
167 }175 try output(context, " = ");
168 try output(context, @memberName(T, field_i));176 inline for (info.fields) |u_field| {
169 try output(context, " = ");177 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
170 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);178 try formatType(@field(value, u_field.name), "", 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));
191 }179 }
192 },180 }
193 else => unreachable,181 try output(context, " }");
182 } else {
183 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
194 }184 }
195 return;
196 },185 },
197 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {186 .Struct => {
198 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {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)) {
199 builtin.TypeId.Array => |info| {210 builtin.TypeId.Array => |info| {
200 if (info.child == u8) {211 if (info.child == u8) {
201 return formatText(value, fmt, context, Errors, output);212 return formatText(value, fmt, context, Errors, output);
...@@ -207,7 +218,7 @@ pub fn formatType(...@@ -207,7 +218,7 @@ pub fn formatType(
207 },218 },
208 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),219 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
209 },220 },
210 builtin.TypeInfo.Pointer.Size.Many => {221 .Many => {
211 if (ptr_info.child == u8) {222 if (ptr_info.child == u8) {
212 if (fmt.len > 0 and fmt[0] == 's') {223 if (fmt.len > 0 and fmt[0] == 's') {
213 const len = mem.len(u8, value);224 const len = mem.len(u8, value);
...@@ -216,7 +227,7 @@ pub fn formatType(...@@ -216,7 +227,7 @@ pub fn formatType(
216 }227 }
217 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));228 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
218 },229 },
219 builtin.TypeInfo.Pointer.Size.Slice => {230 .Slice => {
220 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {231 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
221 return formatText(value, fmt, context, Errors, output);232 return formatText(value, fmt, context, Errors, output);
222 }233 }
...@@ -225,17 +236,17 @@ pub fn formatType(...@@ -225,17 +236,17 @@ pub fn formatType(
225 }236 }
226 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));237 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
227 },238 },
228 builtin.TypeInfo.Pointer.Size.C => {239 .C => {
229 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));240 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
230 },241 },
231 },242 },
232 builtin.TypeId.Array => |info| {243 .Array => |info| {
233 if (info.child == u8) {244 if (info.child == u8) {
234 return formatText(value, fmt, context, Errors, output);245 return formatText(value, fmt, context, Errors, output);
235 }246 }
236 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
237 },248 },
238 builtin.TypeId.Fn => {249 .Fn => {
239 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));250 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
240 },251 },
241 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),252 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
...@@ -249,24 +260,24 @@ fn formatValue(...@@ -249,24 +260,24 @@ fn formatValue(
249 comptime Errors: type,260 comptime Errors: type,
250 output: fn (@typeOf(context), []const u8) Errors!void,261 output: fn (@typeOf(context), []const u8) Errors!void,
251) Errors!void {262) Errors!void {
252 if (fmt.len > 0) {263 if (fmt.len > 0 and fmt[0] == 'B') {
253 if (fmt[0] == 'B') {264 comptime var width: ?usize = null;
254 comptime var width: ?usize = null;265 if (fmt.len > 1) {
255 if (fmt.len > 1) {266 if (fmt[1] == 'i') {
256 if (fmt[1] == 'i') {267 if (fmt.len > 2) {
257 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
258 return formatBytes(value, width, 1024, context, Errors, output);
259 }269 }
260 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);270 return formatBytes(value, width, 1024, context, Errors, output);
261 }271 }
262 return formatBytes(value, width, 1000, context, Errors, output);272 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
263 }273 }
274 return formatBytes(value, width, 1000, context, Errors, output);
264 }275 }
265276
266 const T = @typeOf(value);277 const T = @typeOf(value);
267 switch (@typeId(T)) {278 switch (@typeId(T)) {
268 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),279 .Float => return formatFloatValue(value, fmt, context, Errors, output),
269 builtin.TypeId.Int, builtin.TypeId.ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
270 else => comptime unreachable,281 else => comptime unreachable,
271 }282 }
272}283}
...@@ -797,7 +808,7 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {...@@ -797,7 +808,7 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
797 }808 }
798}809}
799810
800test "fmt.parseInt" {811test "parseInt" {
801 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);812 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
802 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);813 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
803 testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);814 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...@@ -828,7 +839,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
828 return x;839 return x;
829}840}
830841
831test "fmt.parseUnsigned" {842test "parseUnsigned" {
832 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);843 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
833 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);844 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
834 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));845 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
...@@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {...@@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
913 size.* += bytes.len;924 size.* += bytes.len;
914}925}
915926
916test "buf print int" {927test "bufPrintInt" {
917 var buffer: [100]u8 = undefined;928 var buffer: [100]u8 = undefined;
918 const buf = buffer[0..];929 const buf = buffer[0..];
919 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));930 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
...@@ -949,7 +960,7 @@ test "parse unsigned comptime" {...@@ -949,7 +960,7 @@ test "parse unsigned comptime" {
949 }960 }
950}961}
951962
952test "fmt.format" {963test "fmt.optional" {
953 {964 {
954 const value: ?i32 = 1234;965 const value: ?i32 = 1234;
955 try testFmt("optional: 1234\n", "optional: {}\n", value);966 try testFmt("optional: 1234\n", "optional: {}\n", value);
...@@ -958,6 +969,9 @@ test "fmt.format" {...@@ -958,6 +969,9 @@ test "fmt.format" {
958 const value: ?i32 = null;969 const value: ?i32 = null;
959 try testFmt("optional: null\n", "optional: {}\n", value);970 try testFmt("optional: null\n", "optional: {}\n", value);
960 }971 }
972}
973
974test "fmt.error" {
961 {975 {
962 const value: anyerror!i32 = 1234;976 const value: anyerror!i32 = 1234;
963 try testFmt("error union: 1234\n", "error union: {}\n", value);977 try testFmt("error union: 1234\n", "error union: {}\n", value);
...@@ -966,10 +980,16 @@ test "fmt.format" {...@@ -966,10 +980,16 @@ test "fmt.format" {
966 const value: anyerror!i32 = error.InvalidChar;980 const value: anyerror!i32 = error.InvalidChar;
967 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);981 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
968 }982 }
983}
984
985test "fmt.int.small" {
969 {986 {
970 const value: u3 = 0b101;987 const value: u3 = 0b101;
971 try testFmt("u3: 5\n", "u3: {}\n", value);988 try testFmt("u3: 5\n", "u3: {}\n", value);
972 }989 }
990}
991
992test "fmt.int.specifier" {
973 {993 {
974 const value: u8 = 'a';994 const value: u8 = 'a';
975 try testFmt("u8: a\n", "u8: {c}\n", value);995 try testFmt("u8: a\n", "u8: {c}\n", value);
...@@ -978,6 +998,9 @@ test "fmt.format" {...@@ -978,6 +998,9 @@ test "fmt.format" {
978 const value: u8 = 0b1100;998 const value: u8 = 0b1100;
979 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);999 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
980 }1000 }
1001}
1002
1003test "fmt.buffer" {
981 {1004 {
982 var buf1: [32]u8 = undefined;1005 var buf1: [32]u8 = undefined;
983 var context = BufPrintContext{ .remaining = buf1[0..] };1006 var context = BufPrintContext{ .remaining = buf1[0..] };
...@@ -995,6 +1018,9 @@ test "fmt.format" {...@@ -995,6 +1018,9 @@ test "fmt.format" {
995 res = buf1[0 .. buf1.len - context.remaining.len];1018 res = buf1[0 .. buf1.len - context.remaining.len];
996 testing.expect(mem.eql(u8, res, "1100"));1019 testing.expect(mem.eql(u8, res, "1100"));
997 }1020 }
1021}
1022
1023test "fmt.array" {
998 {1024 {
999 const value: [3]u8 = "abc";1025 const value: [3]u8 = "abc";
1000 try testFmt("array: abc\n", "array: {}\n", value);1026 try testFmt("array: abc\n", "array: {}\n", value);
...@@ -1007,6 +1033,9 @@ test "fmt.format" {...@@ -1007,6 +1033,9 @@ test "fmt.format" {
1007 &value,1033 &value,
1008 );1034 );
1009 }1035 }
1036}
1037
1038test "fmt.slice" {
1010 {1039 {
1011 const value: []const u8 = "abc";1040 const value: []const u8 = "abc";
1012 try testFmt("slice: abc\n", "slice: {}\n", value);1041 try testFmt("slice: abc\n", "slice: {}\n", value);
...@@ -1015,6 +1044,12 @@ test "fmt.format" {...@@ -1015,6 +1044,12 @@ test "fmt.format" {
1015 const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0];1044 const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0];
1016 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);1045 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
1017 }1046 }
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" {
1018 {1053 {
1019 const value = @intToPtr(*i32, 0xdeadbeef);1054 const value = @intToPtr(*i32, 0xdeadbeef);
1020 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);1055 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
...@@ -1028,12 +1063,19 @@ test "fmt.format" {...@@ -1028,12 +1063,19 @@ test "fmt.format" {
1028 const value = @intToPtr(fn () void, 0xdeadbeef);1063 const value = @intToPtr(fn () void, 0xdeadbeef);
1029 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);1064 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
1030 }1065 }
1031 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");1066}
1032 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");1067
1068test "fmt.cstr" {
1033 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");1069 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
1034 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");1070 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
1071}
1072
1073test "fmt.filesize" {
1035 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));1074 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1036 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));1075 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
1076}
1077
1078test "fmt.struct" {
1037 {1079 {
1038 const Struct = struct {1080 const Struct = struct {
1039 field: u8,1081 field: u8,
...@@ -1050,15 +1092,19 @@ test "fmt.format" {...@@ -1050,15 +1092,19 @@ test "fmt.format" {
1050 const value = Struct{ .a = 0, .b = 1 };1092 const value = Struct{ .a = 0, .b = 1 };
1051 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);1093 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
1052 }1094 }
1053 {1095}
1054 const Enum = enum {1096
1055 One,1097test "fmt.enum" {
1056 Two,1098 const Enum = enum {
1057 };1099 One,
1058 const value = Enum.Two;1100 Two,
1059 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);1101 };
1060 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);1102 const value = Enum.Two;
1061 }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" {
1062 {1108 {
1063 var buf1: [32]u8 = undefined;1109 var buf1: [32]u8 = undefined;
1064 const value: f32 = 1.34;1110 const value: f32 = 1.34;
...@@ -1088,6 +1134,9 @@ test "fmt.format" {...@@ -1088,6 +1134,9 @@ test "fmt.format" {
1088 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));1134 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
1089 }1135 }
1090 }1136 }
1137}
1138
1139test "fmt.float.scientific.precision" {
1091 {1140 {
1092 var buf1: [32]u8 = undefined;1141 var buf1: [32]u8 = undefined;
1093 const value: f64 = 1.409706e-42;1142 const value: f64 = 1.409706e-42;
...@@ -1114,6 +1163,9 @@ test "fmt.format" {...@@ -1114,6 +1163,9 @@ test "fmt.format" {
1114 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);1163 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1115 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));1164 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
1116 }1165 }
1166}
1167
1168test "fmt.float.special" {
1117 {1169 {
1118 var buf1: [32]u8 = undefined;1170 var buf1: [32]u8 = undefined;
1119 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);1171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
...@@ -1136,6 +1188,9 @@ test "fmt.format" {...@@ -1136,6 +1188,9 @@ test "fmt.format" {
1136 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);1188 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
1137 testing.expect(mem.eql(u8, result, "f64: -inf\n"));1189 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
1138 }1190 }
1191}
1192
1193test "fmt.float.decimal" {
1139 {1194 {
1140 var buf1: [64]u8 = undefined;1195 var buf1: [64]u8 = undefined;
1141 const value: f64 = 1.52314e+29;1196 const value: f64 = 1.52314e+29;
...@@ -1216,7 +1271,9 @@ test "fmt.format" {...@@ -1216,7 +1271,9 @@ test "fmt.format" {
1216 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1271 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1217 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));1272 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1218 }1273 }
1219 // libc checks1274}
1275
1276test "fmt.float.libc.sanity" {
1220 {1277 {
1221 var buf1: [32]u8 = undefined;1278 var buf1: [32]u8 = undefined;
1222 const value: f64 = f64(@bitCast(f32, u32(916964781)));1279 const value: f64 = f64(@bitCast(f32, u32(916964781)));
...@@ -1267,127 +1324,127 @@ test "fmt.format" {...@@ -1267,127 +1324,127 @@ test "fmt.format" {
1267 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1324 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1268 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));1325 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1269 }1326 }
1270 //custom type format1327}
1271 {1328
1272 const Vec2 = struct {1329test "fmt.custom" {
1273 const SelfType = @This();1330 const Vec2 = struct {
1274 x: f32,1331 const SelfType = @This();
1275 y: f32,1332 x: f32,
12761333 y: f32,
1277 pub fn format(1334
1278 self: SelfType,1335 pub fn format(
1279 comptime fmt: []const u8,1336 self: SelfType,
1280 context: var,1337 comptime fmt: []const u8,
1281 comptime Errors: type,1338 context: var,
1282 output: fn (@typeOf(context), []const u8) Errors!void,1339 comptime Errors: type,
1283 ) Errors!void {1340 output: fn (@typeOf(context), []const u8) Errors!void,
1284 switch (fmt.len) {1341 ) Errors!void {
1285 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1342 switch (fmt.len) {
1286 1 => switch (fmt[0]) {1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1287 //point format1344 1 => switch (fmt[0]) {
1288 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1345 //point format
1289 //dimension format1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1290 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),1347 //dimension format
1291 else => unreachable,1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1292 },
1293 else => unreachable,1349 else => unreachable,
1294 }1350 },
1351 else => unreachable,
1295 }1352 }
1296 };1353 }
1354 };
12971355
1298 var buf1: [32]u8 = undefined;1356 var buf1: [32]u8 = undefined;
1299 var value = Vec2{1357 var value = Vec2{
1300 .x = 10.2,1358 .x = 10.2,
1301 .y = 2.22,1359 .y = 2.22,
1302 };1360 };
1303 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);1361 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1304 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);1362 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
13051363
1306 // same thing but not passing a pointer1364 // same thing but not passing a pointer
1307 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);1365 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1308 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);1366 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1309 }1367}
1310 //struct format
1311 {
1312 const S = struct {
1313 a: u32,
1314 b: anyerror,
1315 };
13161368
1317 const inst = S{1369test "fmt.struct" {
1318 .a = 456,1370 const S = struct {
1319 .b = error.Unused,1371 a: u32,
1320 };1372 b: anyerror,
1373 };
13211374
1322 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);1375 const inst = S{
1323 }1376 .a = 456,
1324 //union format1377 .b = error.Unused,
1325 {1378 };
1326 const TU = union(enum) {
1327 float: f32,
1328 int: u32,
1329 };
13301379
1331 const UU = union {1380 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1332 float: f32,1381}
1333 int: u32,
1334 };
13351382
1336 const EU = extern union {1383test "fmt.union" {
1337 float: f32,1384 const TU = union(enum) {
1338 int: u32,1385 float: f32,
1339 };1386 int: u32,
1387 };
13401388
1341 const tu_inst = TU{ .int = 123 };1389 const UU = union {
1342 const uu_inst = UU{ .int = 456 };1390 float: f32,
1343 const eu_inst = EU{ .float = 321.123 };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;1399 const tu_inst = TU{ .int = 123 };
1348 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);1400 const uu_inst = UU{ .int = 456 };
1349 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));1401 const eu_inst = EU{ .float = 321.123 };
13501402
1351 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);1403 try testFmt("TU{ .int = 123 }", "{}", tu_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 };
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);1409 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1365 }1410 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1366 //self-referential struct format1411}
1367 {
1368 const S = struct {
1369 const SelfType = @This();
1370 a: ?*SelfType,
1371 };
13721412
1373 var inst = S{1413test "fmt.enum" {
1374 .a = null,1414 const E = enum {
1375 };1415 One,
1376 inst.a = &inst;1416 Two,
1417 Three,
1418 };
13771419
1378 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);1420 const inst = E.Two;
1379 }1421
1380 //print bytes as hex1422 try testFmt("E.Two", "{}", inst);
1381 {1423}
1382 const some_bytes = "\xCA\xFE\xBA\xBE";1424
1383 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);1425test "fmt.struct.self-referential" {
1384 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);1426 const S = struct {
1385 //Test Slices1427 const SelfType = @This();
1386 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);1428 a: ?*SelfType,
1387 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);1429 };
1388 const bytes_with_zeros = "\x00\x0E\xBA\xBE";1430
1389 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);1431 var inst = S{
1390 }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);
1391}1448}
13921449
1393fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {1450fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {