authorgravatar for benjamin.feng@glassdoor.comBenjamin Feng <benjamin.feng@glassdoor.com> 2020-02-29 12:02:33-06:00
committergravatar for benjamin.feng@glassdoor.comBenjamin Feng <benjamin.feng@glassdoor.com> 2020-03-12 09:06:10-05:00
loge1e9ff9546d0898764ff9c9383e57d0fa4e9bd0e
treeed7bba4c0f9a018cd698ab193597652ca69be8b5
parent278b9ec1aaabb8bcfbbf9c964012dc5bd2ad154a

Get formatIntBuf working


1 files changed, 608 insertions(+), 619 deletions(-)

lib/std/fmtstream.zig+608-619
......@@ -972,20 +972,9 @@ fn formatIntUnsigned(
972972}
973973
974974pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
975 var context = FormatIntBuf{
976 .out_buf = out_buf,
977 .index = 0,
978 };
979 formatInt(value, base, uppercase, options, &context, error{}, formatIntCallback) catch unreachable;
980 return context.index;
981}
982const FormatIntBuf = struct {
983 out_buf: []u8,
984 index: usize,
985};
986fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
987 mem.copy(u8, context.out_buf[context.index..], bytes);
988 context.index += bytes.len;
975 var fbs = std.io.fixedBufferStream(out_buf);
976 formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;
977 return fbs.pos;
989978}
990979
991980pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
......@@ -1085,48 +1074,48 @@ fn digitToChar(digit: u8, uppercase: bool) u8 {
10851074 };
10861075}
10871076
1088const BufPrintContext = struct {
1089 remaining: []u8,
1090};
1091
1092fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
1093 if (context.remaining.len < bytes.len) {
1094 mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
1095 return error.BufferTooSmall;
1096 }
1097 mem.copy(u8, context.remaining, bytes);
1098 context.remaining = context.remaining[bytes.len..];
1099}
1100
1101pub const BufPrintError = error{
1102 /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
1103 BufferTooSmall,
1104};
1105pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
1106 var context = BufPrintContext{ .remaining = buf };
1107 try format(&context, BufPrintError, bufPrintWrite, fmt, args);
1108 return buf[0 .. buf.len - context.remaining.len];
1109}
1110
1111pub const AllocPrintError = error{OutOfMemory};
1112
1113pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
1114 var size: usize = 0;
1115 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
1116 const buf = try allocator.alloc(u8, size);
1117 return bufPrint(buf, fmt, args) catch |err| switch (err) {
1118 error.BufferTooSmall => unreachable, // we just counted the size above
1119 };
1120}
1121
1122fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
1123 size.* += bytes.len;
1124}
1125
1126pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
1127 const result = try allocPrint(allocator, fmt ++ "\x00", args);
1128 return result[0 .. result.len - 1 :0];
1129}
1077// const BufPrintContext = struct {
1078// remaining: []u8,
1079// };
1080
1081// fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
1082// if (context.remaining.len < bytes.len) {
1083// mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
1084// return error.BufferTooSmall;
1085// }
1086// mem.copy(u8, context.remaining, bytes);
1087// context.remaining = context.remaining[bytes.len..];
1088// }
1089
1090// pub const BufPrintError = error{
1091// /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
1092// BufferTooSmall,
1093// };
1094// pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
1095// var context = BufPrintContext{ .remaining = buf };
1096// try format(&context, BufPrintError, bufPrintWrite, fmt, args);
1097// return buf[0 .. buf.len - context.remaining.len];
1098// }
1099
1100// pub const AllocPrintError = error{OutOfMemory};
1101
1102// pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
1103// var size: usize = 0;
1104// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
1105// const buf = try allocator.alloc(u8, size);
1106// return bufPrint(buf, fmt, args) catch |err| switch (err) {
1107// error.BufferTooSmall => unreachable, // we just counted the size above
1108// };
1109// }
1110
1111// fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
1112// size.* += bytes.len;
1113// }
1114
1115// pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
1116// const result = try allocPrint(allocator, fmt ++ "\x00", args);
1117// return result[0 .. result.len - 1 :0];
1118// }
11301119
11311120test "bufPrintInt" {
11321121 var buffer: [100]u8 = undefined;
......@@ -1153,566 +1142,566 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options:
11531142 return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
11541143}
11551144
1156test "parse u64 digit too big" {
1157 _ = parseUnsigned(u64, "123a", 10) catch |err| {
1158 if (err == error.InvalidCharacter) return;
1159 unreachable;
1160 };
1161 unreachable;
1162}
1163
1164test "parse unsigned comptime" {
1165 comptime {
1166 std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
1167 }
1168}
1169
1170test "optional" {
1171 {
1172 const value: ?i32 = 1234;
1173 try testFmt("optional: 1234\n", "optional: {}\n", .{value});
1174 }
1175 {
1176 const value: ?i32 = null;
1177 try testFmt("optional: null\n", "optional: {}\n", .{value});
1178 }
1179}
1180
1181test "error" {
1182 {
1183 const value: anyerror!i32 = 1234;
1184 try testFmt("error union: 1234\n", "error union: {}\n", .{value});
1185 }
1186 {
1187 const value: anyerror!i32 = error.InvalidChar;
1188 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
1189 }
1190}
1191
1192test "int.small" {
1193 {
1194 const value: u3 = 0b101;
1195 try testFmt("u3: 5\n", "u3: {}\n", .{value});
1196 }
1197}
1198
1199test "int.specifier" {
1200 {
1201 const value: u8 = 'a';
1202 try testFmt("u8: a\n", "u8: {c}\n", .{value});
1203 }
1204 {
1205 const value: u8 = 0b1100;
1206 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
1207 }
1208}
1209
1210test "int.padded" {
1211 try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
1212 try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
1213}
1214
1215test "buffer" {
1216 {
1217 var buf1: [32]u8 = undefined;
1218 var context = BufPrintContext{ .remaining = buf1[0..] };
1219 try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1220 var res = buf1[0 .. buf1.len - context.remaining.len];
1221 std.testing.expect(mem.eql(u8, res, "1234"));
1222
1223 context = BufPrintContext{ .remaining = buf1[0..] };
1224 try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1225 res = buf1[0 .. buf1.len - context.remaining.len];
1226 std.testing.expect(mem.eql(u8, res, "a"));
1227
1228 context = BufPrintContext{ .remaining = buf1[0..] };
1229 try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1230 res = buf1[0 .. buf1.len - context.remaining.len];
1231 std.testing.expect(mem.eql(u8, res, "1100"));
1232 }
1233}
1234
1235test "array" {
1236 {
1237 const value: [3]u8 = "abc".*;
1238 try testFmt("array: abc\n", "array: {}\n", .{value});
1239 try testFmt("array: abc\n", "array: {}\n", .{&value});
1240
1241 var buf: [100]u8 = undefined;
1242 try testFmt(
1243 try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
1244 "array: {*}\n",
1245 .{&value},
1246 );
1247 }
1248}
1249
1250test "slice" {
1251 {
1252 const value: []const u8 = "abc";
1253 try testFmt("slice: abc\n", "slice: {}\n", .{value});
1254 }
1255 {
1256 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
1257 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
1258 }
1259
1260 try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
1261 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
1262}
1263
1264test "pointer" {
1265 {
1266 const value = @intToPtr(*align(1) i32, 0xdeadbeef);
1267 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
1268 try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
1269 }
1270 {
1271 const value = @intToPtr(fn () void, 0xdeadbeef);
1272 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
1273 }
1274 {
1275 const value = @intToPtr(fn () void, 0xdeadbeef);
1276 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
1277 }
1278}
1279
1280test "cstr" {
1281 try testFmt(
1282 "cstr: Test C\n",
1283 "cstr: {s}\n",
1284 .{@ptrCast([*c]const u8, "Test C")},
1285 );
1286 try testFmt(
1287 "cstr: Test C \n",
1288 "cstr: {s:10}\n",
1289 .{@ptrCast([*c]const u8, "Test C")},
1290 );
1291}
1292
1293test "filesize" {
1294 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
1295 try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
1296}
1297
1298test "struct" {
1299 {
1300 const Struct = struct {
1301 field: u8,
1302 };
1303 const value = Struct{ .field = 42 };
1304 try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
1305 try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
1306 }
1307 {
1308 const Struct = struct {
1309 a: u0,
1310 b: u1,
1311 };
1312 const value = Struct{ .a = 0, .b = 1 };
1313 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
1314 }
1315}
1316
1317test "enum" {
1318 const Enum = enum {
1319 One,
1320 Two,
1321 };
1322 const value = Enum.Two;
1323 try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
1324 try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
1325}
1326
1327test "non-exhaustive enum" {
1328 const Enum = enum(u16) {
1329 One = 0x000f,
1330 Two = 0xbeef,
1331 _,
1332 };
1333 try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
1334 try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
1335 try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
1336 try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
1337 try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
1338 try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
1339}
1340
1341test "float.scientific" {
1342 try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
1343 try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
1344 try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
1345 try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
1346}
1347
1348test "float.scientific.precision" {
1349 try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
1350 try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
1351 try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
1352 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1353 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1354 try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
1355}
1356
1357test "float.special" {
1358 try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
1359 // negative nan is not defined by IEE 754,
1360 // and ARM thus normalizes it to positive nan
1361 if (builtin.arch != builtin.Arch.arm) {
1362 try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
1363 }
1364 try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
1365 try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
1366}
1367
1368test "float.decimal" {
1369 try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
1370 try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
1371 try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
1372 try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
1373 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1374 // -11.12339... is rounded back up to -11.1234
1375 try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
1376 try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
1377 try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
1378 try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
1379 try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
1380 try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
1381 try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
1382 try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
1383 try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
1384 try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
1385}
1386
1387test "float.libc.sanity" {
1388 try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
1389 try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
1390 try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
1391 try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
1392 try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
1393
1394 // libc differences
1395 //
1396 // This is 0.015625 exactly according to gdb. We thus round down,
1397 // however glibc rounds up for some reason. This occurs for all
1398 // floats of the form x.yyyy25 on a precision point.
1399 try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
1400 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1401 // also rounds to 630 so I'm inclined to believe libc is not
1402 // optimal here.
1403 try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
1404}
1405
1406test "custom" {
1407 const Vec2 = struct {
1408 const SelfType = @This();
1409 x: f32,
1410 y: f32,
1411
1412 pub fn format(
1413 self: SelfType,
1414 comptime fmt: []const u8,
1415 options: FormatOptions,
1416 context: var,
1417 comptime Errors: type,
1418 comptime output: fn (@TypeOf(context), []const u8) !void,
1419 ) !void {
1420 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1421 return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
1422 } else if (comptime std.mem.eql(u8, fmt, "d")) {
1423 return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
1424 } else {
1425 @compileError("Unknown format character: '" ++ fmt ++ "'");
1426 }
1427 }
1428 };
1429
1430 var buf1: [32]u8 = undefined;
1431 var value = Vec2{
1432 .x = 10.2,
1433 .y = 2.22,
1434 };
1435 try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
1436 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
1437
1438 // same thing but not passing a pointer
1439 try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
1440 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
1441}
1442
1443test "struct" {
1444 const S = struct {
1445 a: u32,
1446 b: anyerror,
1447 };
1448
1449 const inst = S{
1450 .a = 456,
1451 .b = error.Unused,
1452 };
1453
1454 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
1455}
1456
1457test "union" {
1458 const TU = union(enum) {
1459 float: f32,
1460 int: u32,
1461 };
1462
1463 const UU = union {
1464 float: f32,
1465 int: u32,
1466 };
1467
1468 const EU = extern union {
1469 float: f32,
1470 int: u32,
1471 };
1472
1473 const tu_inst = TU{ .int = 123 };
1474 const uu_inst = UU{ .int = 456 };
1475 const eu_inst = EU{ .float = 321.123 };
1476
1477 try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
1478
1479 var buf: [100]u8 = undefined;
1480 const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
1481 std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
1482
1483 const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
1484 std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1485}
1486
1487test "enum" {
1488 const E = enum {
1489 One,
1490 Two,
1491 Three,
1492 };
1493
1494 const inst = E.Two;
1495
1496 try testFmt("E.Two", "{}", .{inst});
1497}
1498
1499test "struct.self-referential" {
1500 const S = struct {
1501 const SelfType = @This();
1502 a: ?*SelfType,
1503 };
1504
1505 var inst = S{
1506 .a = null,
1507 };
1508 inst.a = &inst;
1509
1510 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
1511}
1512
1513test "struct.zero-size" {
1514 const A = struct {
1515 fn foo() void {}
1516 };
1517 const B = struct {
1518 a: A,
1519 c: i32,
1520 };
1521
1522 const a = A{};
1523 const b = B{ .a = a, .c = 0 };
1524
1525 try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
1526}
1527
1528test "bytes.hex" {
1529 const some_bytes = "\xCA\xFE\xBA\xBE";
1530 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
1531 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
1532 //Test Slices
1533 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
1534 try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
1535 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1536 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
1537}
1538
1539fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
1540 var buf: [100]u8 = undefined;
1541 const result = try bufPrint(buf[0..], template, args);
1542 if (mem.eql(u8, result, expected)) return;
1543
1544 std.debug.warn("\n====== expected this output: =========\n", .{});
1545 std.debug.warn("{}", .{expected});
1546 std.debug.warn("\n======== instead found this: =========\n", .{});
1547 std.debug.warn("{}", .{result});
1548 std.debug.warn("\n======================================\n", .{});
1549 return error.TestFailed;
1550}
1551
1552pub fn trim(buf: []const u8) []const u8 {
1553 var start: usize = 0;
1554 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
1555
1556 var end: usize = buf.len;
1557 while (true) {
1558 if (end > start) {
1559 const new_end = end - 1;
1560 if (isWhiteSpace(buf[new_end])) {
1561 end = new_end;
1562 continue;
1563 }
1564 }
1565 break;
1566 }
1567 return buf[start..end];
1568}
1569
1570test "trim" {
1571 std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
1572 std.testing.expect(mem.eql(u8, "", trim(" ")));
1573 std.testing.expect(mem.eql(u8, "", trim("")));
1574 std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
1575 std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
1576}
1577
1578pub fn isWhiteSpace(byte: u8) bool {
1579 return switch (byte) {
1580 ' ', '\t', '\n', '\r' => true,
1581 else => false,
1582 };
1583}
1584
1585pub fn hexToBytes(out: []u8, input: []const u8) !void {
1586 if (out.len * 2 < input.len)
1587 return error.InvalidLength;
1588
1589 var in_i: usize = 0;
1590 while (in_i != input.len) : (in_i += 2) {
1591 const hi = try charToDigit(input[in_i], 16);
1592 const lo = try charToDigit(input[in_i + 1], 16);
1593 out[in_i / 2] = (hi << 4) | lo;
1594 }
1595}
1596
1597test "hexToBytes" {
1598 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1599 var pb: [32]u8 = undefined;
1600 try hexToBytes(pb[0..], test_hex_str);
1601 try testFmt(test_hex_str, "{X}", .{pb});
1602}
1603
1604test "formatIntValue with comptime_int" {
1605 const value: comptime_int = 123456789123456789;
1606
1607 var buf = std.ArrayList(u8).init(std.testing.allocator);
1608 defer buf.deinit();
1609 try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
1610 std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
1611}
1612
1613test "formatType max_depth" {
1614 const Vec2 = struct {
1615 const SelfType = @This();
1616 x: f32,
1617 y: f32,
1618
1619 pub fn format(
1620 self: SelfType,
1621 comptime fmt: []const u8,
1622 options: FormatOptions,
1623 context: var,
1624 comptime Errors: type,
1625 comptime output: fn (@TypeOf(context), []const u8) !void,
1626 ) !void {
1627 if (fmt.len == 0) {
1628 return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
1629 } else {
1630 @compileError("Unknown format string: '" ++ fmt ++ "'");
1631 }
1632 }
1633 };
1634 const E = enum {
1635 One,
1636 Two,
1637 Three,
1638 };
1639 const TU = union(enum) {
1640 const SelfType = @This();
1641 float: f32,
1642 int: u32,
1643 ptr: ?*SelfType,
1644 };
1645 const S = struct {
1646 const SelfType = @This();
1647 a: ?*SelfType,
1648 tu: TU,
1649 e: E,
1650 vec: Vec2,
1651 };
1652
1653 var inst = S{
1654 .a = null,
1655 .tu = TU{ .ptr = null },
1656 .e = E.Two,
1657 .vec = Vec2{ .x = 10.2, .y = 2.22 },
1658 };
1659 inst.a = &inst;
1660 inst.tu.ptr = &inst.tu;
1661
1662 var buf0 = std.ArrayList(u8).init(std.testing.allocator);
1663 defer buf0.deinit();
1664 try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
1665 std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
1666
1667 var buf1 = std.ArrayList(u8).init(std.testing.allocator);
1668 defer buf1.deinit();
1669 try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
1670 std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
1671
1672 var buf2 = std.ArrayList(u8).init(std.testing.allocator);
1673 defer buf2.deinit();
1674 try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
1675 std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
1676
1677 var buf3 = std.ArrayList(u8).init(std.testing.allocator);
1678 defer buf3.deinit();
1679 try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
1680 std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
1681}
1682
1683test "positional" {
1684 try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
1685 try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
1686 try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
1687 try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
1688 try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
1689}
1690
1691test "positional with specifier" {
1692 try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
1693}
1694
1695test "positional/alignment/width/precision" {
1696 try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
1697}
1698
1699test "vector" {
1700 // https://github.com/ziglang/zig/issues/3317
1701 if (builtin.arch == .mipsel) return error.SkipZigTest;
1702
1703 const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
1704 const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
1705 const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
1706
1707 try testFmt("{ true, false, true, false }", "{}", .{vbool});
1708 try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
1709 try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
1710 try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
1711 try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
1712 try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
1713 try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
1714}
1715
1716test "enum-literal" {
1717 try testFmt(".hello_world", "{}", .{.hello_world});
1718}
1145// test "parse u64 digit too big" {
1146// _ = parseUnsigned(u64, "123a", 10) catch |err| {
1147// if (err == error.InvalidCharacter) return;
1148// unreachable;
1149// };
1150// unreachable;
1151// }
1152
1153// test "parse unsigned comptime" {
1154// comptime {
1155// std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
1156// }
1157// }
1158
1159// test "optional" {
1160// {
1161// const value: ?i32 = 1234;
1162// try testFmt("optional: 1234\n", "optional: {}\n", .{value});
1163// }
1164// {
1165// const value: ?i32 = null;
1166// try testFmt("optional: null\n", "optional: {}\n", .{value});
1167// }
1168// }
1169
1170// test "error" {
1171// {
1172// const value: anyerror!i32 = 1234;
1173// try testFmt("error union: 1234\n", "error union: {}\n", .{value});
1174// }
1175// {
1176// const value: anyerror!i32 = error.InvalidChar;
1177// try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
1178// }
1179// }
1180
1181// test "int.small" {
1182// {
1183// const value: u3 = 0b101;
1184// try testFmt("u3: 5\n", "u3: {}\n", .{value});
1185// }
1186// }
1187
1188// test "int.specifier" {
1189// {
1190// const value: u8 = 'a';
1191// try testFmt("u8: a\n", "u8: {c}\n", .{value});
1192// }
1193// {
1194// const value: u8 = 0b1100;
1195// try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
1196// }
1197// }
1198
1199// test "int.padded" {
1200// try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
1201// try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
1202// }
1203
1204// test "buffer" {
1205// {
1206// var buf1: [32]u8 = undefined;
1207// var context = BufPrintContext{ .remaining = buf1[0..] };
1208// try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1209// var res = buf1[0 .. buf1.len - context.remaining.len];
1210// std.testing.expect(mem.eql(u8, res, "1234"));
1211
1212// context = BufPrintContext{ .remaining = buf1[0..] };
1213// try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1214// res = buf1[0 .. buf1.len - context.remaining.len];
1215// std.testing.expect(mem.eql(u8, res, "a"));
1216
1217// context = BufPrintContext{ .remaining = buf1[0..] };
1218// try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1219// res = buf1[0 .. buf1.len - context.remaining.len];
1220// std.testing.expect(mem.eql(u8, res, "1100"));
1221// }
1222// }
1223
1224// test "array" {
1225// {
1226// const value: [3]u8 = "abc".*;
1227// try testFmt("array: abc\n", "array: {}\n", .{value});
1228// try testFmt("array: abc\n", "array: {}\n", .{&value});
1229
1230// var buf: [100]u8 = undefined;
1231// try testFmt(
1232// try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
1233// "array: {*}\n",
1234// .{&value},
1235// );
1236// }
1237// }
1238
1239// test "slice" {
1240// {
1241// const value: []const u8 = "abc";
1242// try testFmt("slice: abc\n", "slice: {}\n", .{value});
1243// }
1244// {
1245// const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
1246// try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
1247// }
1248
1249// try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
1250// try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
1251// }
1252
1253// test "pointer" {
1254// {
1255// const value = @intToPtr(*align(1) i32, 0xdeadbeef);
1256// try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
1257// try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
1258// }
1259// {
1260// const value = @intToPtr(fn () void, 0xdeadbeef);
1261// try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
1262// }
1263// {
1264// const value = @intToPtr(fn () void, 0xdeadbeef);
1265// try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
1266// }
1267// }
1268
1269// test "cstr" {
1270// try testFmt(
1271// "cstr: Test C\n",
1272// "cstr: {s}\n",
1273// .{@ptrCast([*c]const u8, "Test C")},
1274// );
1275// try testFmt(
1276// "cstr: Test C \n",
1277// "cstr: {s:10}\n",
1278// .{@ptrCast([*c]const u8, "Test C")},
1279// );
1280// }
1281
1282// test "filesize" {
1283// try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
1284// try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
1285// }
1286
1287// test "struct" {
1288// {
1289// const Struct = struct {
1290// field: u8,
1291// };
1292// const value = Struct{ .field = 42 };
1293// try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
1294// try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
1295// }
1296// {
1297// const Struct = struct {
1298// a: u0,
1299// b: u1,
1300// };
1301// const value = Struct{ .a = 0, .b = 1 };
1302// try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
1303// }
1304// }
1305
1306// test "enum" {
1307// const Enum = enum {
1308// One,
1309// Two,
1310// };
1311// const value = Enum.Two;
1312// try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
1313// try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
1314// }
1315
1316// test "non-exhaustive enum" {
1317// const Enum = enum(u16) {
1318// One = 0x000f,
1319// Two = 0xbeef,
1320// _,
1321// };
1322// try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
1323// try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
1324// try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
1325// try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
1326// try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
1327// try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
1328// }
1329
1330// test "float.scientific" {
1331// try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
1332// try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
1333// try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
1334// try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
1335// }
1336
1337// test "float.scientific.precision" {
1338// try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
1339// try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
1340// try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
1341// // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1342// // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1343// try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
1344// }
1345
1346// test "float.special" {
1347// try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
1348// // negative nan is not defined by IEE 754,
1349// // and ARM thus normalizes it to positive nan
1350// if (builtin.arch != builtin.Arch.arm) {
1351// try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
1352// }
1353// try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
1354// try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
1355// }
1356
1357// test "float.decimal" {
1358// try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
1359// try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
1360// try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
1361// try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
1362// // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1363// // -11.12339... is rounded back up to -11.1234
1364// try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
1365// try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
1366// try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
1367// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
1368// try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
1369// try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
1370// try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
1371// try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
1372// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
1373// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
1374// }
1375
1376// test "float.libc.sanity" {
1377// try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
1378// try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
1379// try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
1380// try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
1381// try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
1382
1383// // libc differences
1384// //
1385// // This is 0.015625 exactly according to gdb. We thus round down,
1386// // however glibc rounds up for some reason. This occurs for all
1387// // floats of the form x.yyyy25 on a precision point.
1388// try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
1389// // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1390// // also rounds to 630 so I'm inclined to believe libc is not
1391// // optimal here.
1392// try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
1393// }
1394
1395// test "custom" {
1396// const Vec2 = struct {
1397// const SelfType = @This();
1398// x: f32,
1399// y: f32,
1400
1401// pub fn format(
1402// self: SelfType,
1403// comptime fmt: []const u8,
1404// options: FormatOptions,
1405// context: var,
1406// comptime Errors: type,
1407// comptime output: fn (@TypeOf(context), []const u8) !void,
1408// ) !void {
1409// if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1410// return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
1411// } else if (comptime std.mem.eql(u8, fmt, "d")) {
1412// return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
1413// } else {
1414// @compileError("Unknown format character: '" ++ fmt ++ "'");
1415// }
1416// }
1417// };
1418
1419// var buf1: [32]u8 = undefined;
1420// var value = Vec2{
1421// .x = 10.2,
1422// .y = 2.22,
1423// };
1424// try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
1425// try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
1426
1427// // same thing but not passing a pointer
1428// try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
1429// try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
1430// }
1431
1432// test "struct" {
1433// const S = struct {
1434// a: u32,
1435// b: anyerror,
1436// };
1437
1438// const inst = S{
1439// .a = 456,
1440// .b = error.Unused,
1441// };
1442
1443// try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
1444// }
1445
1446// test "union" {
1447// const TU = union(enum) {
1448// float: f32,
1449// int: u32,
1450// };
1451
1452// const UU = union {
1453// float: f32,
1454// int: u32,
1455// };
1456
1457// const EU = extern union {
1458// float: f32,
1459// int: u32,
1460// };
1461
1462// const tu_inst = TU{ .int = 123 };
1463// const uu_inst = UU{ .int = 456 };
1464// const eu_inst = EU{ .float = 321.123 };
1465
1466// try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
1467
1468// var buf: [100]u8 = undefined;
1469// const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
1470// std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
1471
1472// const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
1473// std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1474// }
1475
1476// test "enum" {
1477// const E = enum {
1478// One,
1479// Two,
1480// Three,
1481// };
1482
1483// const inst = E.Two;
1484
1485// try testFmt("E.Two", "{}", .{inst});
1486// }
1487
1488// test "struct.self-referential" {
1489// const S = struct {
1490// const SelfType = @This();
1491// a: ?*SelfType,
1492// };
1493
1494// var inst = S{
1495// .a = null,
1496// };
1497// inst.a = &inst;
1498
1499// try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
1500// }
1501
1502// test "struct.zero-size" {
1503// const A = struct {
1504// fn foo() void {}
1505// };
1506// const B = struct {
1507// a: A,
1508// c: i32,
1509// };
1510
1511// const a = A{};
1512// const b = B{ .a = a, .c = 0 };
1513
1514// try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
1515// }
1516
1517// test "bytes.hex" {
1518// const some_bytes = "\xCA\xFE\xBA\xBE";
1519// try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
1520// try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
1521// //Test Slices
1522// try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
1523// try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
1524// const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1525// try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
1526// }
1527
1528// fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
1529// var buf: [100]u8 = undefined;
1530// const result = try bufPrint(buf[0..], template, args);
1531// if (mem.eql(u8, result, expected)) return;
1532
1533// std.debug.warn("\n====== expected this output: =========\n", .{});
1534// std.debug.warn("{}", .{expected});
1535// std.debug.warn("\n======== instead found this: =========\n", .{});
1536// std.debug.warn("{}", .{result});
1537// std.debug.warn("\n======================================\n", .{});
1538// return error.TestFailed;
1539// }
1540
1541// pub fn trim(buf: []const u8) []const u8 {
1542// var start: usize = 0;
1543// while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
1544
1545// var end: usize = buf.len;
1546// while (true) {
1547// if (end > start) {
1548// const new_end = end - 1;
1549// if (isWhiteSpace(buf[new_end])) {
1550// end = new_end;
1551// continue;
1552// }
1553// }
1554// break;
1555// }
1556// return buf[start..end];
1557// }
1558
1559// test "trim" {
1560// std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
1561// std.testing.expect(mem.eql(u8, "", trim(" ")));
1562// std.testing.expect(mem.eql(u8, "", trim("")));
1563// std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
1564// std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
1565// }
1566
1567// pub fn isWhiteSpace(byte: u8) bool {
1568// return switch (byte) {
1569// ' ', '\t', '\n', '\r' => true,
1570// else => false,
1571// };
1572// }
1573
1574// pub fn hexToBytes(out: []u8, input: []const u8) !void {
1575// if (out.len * 2 < input.len)
1576// return error.InvalidLength;
1577
1578// var in_i: usize = 0;
1579// while (in_i != input.len) : (in_i += 2) {
1580// const hi = try charToDigit(input[in_i], 16);
1581// const lo = try charToDigit(input[in_i + 1], 16);
1582// out[in_i / 2] = (hi << 4) | lo;
1583// }
1584// }
1585
1586// test "hexToBytes" {
1587// const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1588// var pb: [32]u8 = undefined;
1589// try hexToBytes(pb[0..], test_hex_str);
1590// try testFmt(test_hex_str, "{X}", .{pb});
1591// }
1592
1593// test "formatIntValue with comptime_int" {
1594// const value: comptime_int = 123456789123456789;
1595
1596// var buf = std.ArrayList(u8).init(std.testing.allocator);
1597// defer buf.deinit();
1598// try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
1599// std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
1600// }
1601
1602// test "formatType max_depth" {
1603// const Vec2 = struct {
1604// const SelfType = @This();
1605// x: f32,
1606// y: f32,
1607
1608// pub fn format(
1609// self: SelfType,
1610// comptime fmt: []const u8,
1611// options: FormatOptions,
1612// context: var,
1613// comptime Errors: type,
1614// comptime output: fn (@TypeOf(context), []const u8) !void,
1615// ) !void {
1616// if (fmt.len == 0) {
1617// return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
1618// } else {
1619// @compileError("Unknown format string: '" ++ fmt ++ "'");
1620// }
1621// }
1622// };
1623// const E = enum {
1624// One,
1625// Two,
1626// Three,
1627// };
1628// const TU = union(enum) {
1629// const SelfType = @This();
1630// float: f32,
1631// int: u32,
1632// ptr: ?*SelfType,
1633// };
1634// const S = struct {
1635// const SelfType = @This();
1636// a: ?*SelfType,
1637// tu: TU,
1638// e: E,
1639// vec: Vec2,
1640// };
1641
1642// var inst = S{
1643// .a = null,
1644// .tu = TU{ .ptr = null },
1645// .e = E.Two,
1646// .vec = Vec2{ .x = 10.2, .y = 2.22 },
1647// };
1648// inst.a = &inst;
1649// inst.tu.ptr = &inst.tu;
1650
1651// var buf0 = std.ArrayList(u8).init(std.testing.allocator);
1652// defer buf0.deinit();
1653// try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
1654// std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
1655
1656// var buf1 = std.ArrayList(u8).init(std.testing.allocator);
1657// defer buf1.deinit();
1658// try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
1659// std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
1660
1661// var buf2 = std.ArrayList(u8).init(std.testing.allocator);
1662// defer buf2.deinit();
1663// try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
1664// std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
1665
1666// var buf3 = std.ArrayList(u8).init(std.testing.allocator);
1667// defer buf3.deinit();
1668// try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
1669// std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
1670// }
1671
1672// test "positional" {
1673// try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
1674// try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
1675// try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
1676// try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
1677// try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
1678// }
1679
1680// test "positional with specifier" {
1681// try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
1682// }
1683
1684// test "positional/alignment/width/precision" {
1685// try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
1686// }
1687
1688// test "vector" {
1689// // https://github.com/ziglang/zig/issues/3317
1690// if (builtin.arch == .mipsel) return error.SkipZigTest;
1691
1692// const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
1693// const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
1694// const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
1695
1696// try testFmt("{ true, false, true, false }", "{}", .{vbool});
1697// try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
1698// try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
1699// try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
1700// try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
1701// try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
1702// try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
1703// }
1704
1705// test "enum-literal" {
1706// try testFmt(".hello_world", "{}", .{.hello_world});
1707// }