| ... | ... | @@ -557,8 +557,8 @@ pub fn formatIntValue( |
| 557 | 557 | @compileError("Cannot escape character with more than 8 bits"); |
| 558 | 558 | } |
| 559 | 559 | } else if (comptime std.mem.eql(u8, fmt, "u")) { |
| 560 | | if (@TypeOf(int_value).bit_count <= 32) { |
| 561 | | return formatUtf8Codepoint(@as(u32, int_value), options, context, Errors, output); |
| 560 | if (@typeInfo(@TypeOf(int_value)).Int.bits <= 21) { |
| 561 | return formatUnicodeCodepoint(@as(u21, int_value), options, writer); |
| 562 | 562 | } else { |
| 563 | 563 | @compileError("Cannot print integer that is larger than 32 bits as an UTF-8 sequence"); |
| 564 | 564 | } |
| ... | ... | @@ -648,16 +648,22 @@ pub fn formatAsciiChar( |
| 648 | 648 | return writer.writeAll(@as(*const [1]u8, &c)); |
| 649 | 649 | } |
| 650 | 650 | |
| 651 | | pub fn formatUtf8Codepoint( |
| 652 | | c: u32, |
| 651 | pub fn formatUnicodeCodepoint( |
| 652 | c: u21, |
| 653 | 653 | options: FormatOptions, |
| 654 | | context: anytype, |
| 655 | | comptime Errors: type, |
| 656 | | output: fn (@TypeOf(context), []const u8) Errors!void, |
| 657 | | ) Errors!void { |
| 654 | writer: anytype, |
| 655 | ) !void { |
| 658 | 656 | var buf: [4]u8 = undefined; |
| 659 | | const len = std.unicode.utf8Encode(c, buf[0..]) catch unreachable; |
| 660 | | return output(context, @as(*const [4]u8, &buf)[0..len]); |
| 657 | // In case of error output the replacement char U+FFFD |
| 658 | const len = std.unicode.utf8Encode(@truncate(u21, c), &buf) catch |err| switch (err) { |
| 659 | error.Utf8CannotEncodeSurrogateHalf => { |
| 660 | return writer.writeAll(&[_]u8{ 0xef, 0xbf, 0xbd }); |
| 661 | }, |
| 662 | error.CodepointTooLarge => { |
| 663 | return writer.writeAll(&[_]u8{ 0xef, 0xbf, 0xbd }); |
| 664 | }, |
| 665 | }; |
| 666 | return writer.writeAll(buf[0..len]); |
| 661 | 667 | } |
| 662 | 668 | |
| 663 | 669 | pub fn formatBuf( |
| ... | ... | @@ -1409,9 +1415,17 @@ test "int.specifier" { |
| 1409 | 1415 | try testFmt("UTF-8: a\n", "UTF-8: {u}\n", .{value}); |
| 1410 | 1416 | } |
| 1411 | 1417 | { |
| 1412 | | const value: u32 = 0x1F310; |
| 1418 | const value: u21 = 0x1F310; |
| 1413 | 1419 | try testFmt("UTF-8: 🌐\n", "UTF-8: {u}\n", .{value}); |
| 1414 | 1420 | } |
| 1421 | { |
| 1422 | const value: u21 = 0xD800; |
| 1423 | try testFmt("UTF-8: �\n", "UTF-8: {u}\n", .{value}); |
| 1424 | } |
| 1425 | { |
| 1426 | const value: u21 = 0x110001; |
| 1427 | try testFmt("UTF-8: �\n", "UTF-8: {u}\n", .{value}); |
| 1428 | } |
| 1415 | 1429 | } |
| 1416 | 1430 | |
| 1417 | 1431 | test "int.padded" { |