| ... | @@ -27,6 +27,8 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), | ... | @@ -27,6 +27,8 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), |
| 27 | Character, | 27 | Character, |
| 28 | Buf, | 28 | Buf, |
| 29 | BufWidth, | 29 | BufWidth, |
| | 30 | Bytes, |
| | 31 | BytesWidth, |
| 30 | }; | 32 | }; |
| 31 | | 33 | |
| 32 | comptime var start_index = 0; | 34 | comptime var start_index = 0; |
| ... | @@ -95,6 +97,10 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), | ... | @@ -95,6 +97,10 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), |
| 95 | '.' => { | 97 | '.' => { |
| 96 | state = State.Float; | 98 | state = State.Float; |
| 97 | }, | 99 | }, |
| | 100 | 'B' => { |
| | 101 | width = 0; |
| | 102 | state = State.Bytes; |
| | 103 | }, |
| 98 | else => @compileError("Unknown format character: " ++ []u8{c}), | 104 | else => @compileError("Unknown format character: " ++ []u8{c}), |
| 99 | }, | 105 | }, |
| 100 | State.Buf => switch (c) { | 106 | State.Buf => switch (c) { |
| ... | @@ -206,6 +212,30 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), | ... | @@ -206,6 +212,30 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), |
| 206 | }, | 212 | }, |
| 207 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), | 213 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), |
| 208 | }, | 214 | }, |
| | 215 | State.Bytes => switch (c) { |
| | 216 | '}' => { |
| | 217 | try formatBytes(args[next_arg], 0, context, Errors, output); |
| | 218 | next_arg += 1; |
| | 219 | state = State.Start; |
| | 220 | start_index = i + 1; |
| | 221 | }, |
| | 222 | '0' ... '9' => { |
| | 223 | width_start = i; |
| | 224 | state = State.BytesWidth; |
| | 225 | }, |
| | 226 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), |
| | 227 | }, |
| | 228 | State.BytesWidth => switch (c) { |
| | 229 | '}' => { |
| | 230 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); |
| | 231 | try formatBytes(args[next_arg], width, context, Errors, output); |
| | 232 | next_arg += 1; |
| | 233 | state = State.Start; |
| | 234 | start_index = i + 1; |
| | 235 | }, |
| | 236 | '0' ... '9' => {}, |
| | 237 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), |
| | 238 | }, |
| 209 | } | 239 | } |
| 210 | } | 240 | } |
| 211 | comptime { | 241 | comptime { |
| ... | @@ -520,6 +550,25 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com | ... | @@ -520,6 +550,25 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com |
| 520 | } | 550 | } |
| 521 | } | 551 | } |
| 522 | | 552 | |
| | 553 | pub fn formatBytes(value: var, width: ?usize, |
| | 554 | context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void |
| | 555 | { |
| | 556 | if (value == 0) { |
| | 557 | return output(context, "0B"); |
| | 558 | } |
| | 559 | |
| | 560 | const mags = " KMGTPEZY"; |
| | 561 | const magnitude = math.min(math.log2(value) / 10, mags.len - 1); |
| | 562 | const new_value = f64(value) / math.pow(f64, 1024, f64(magnitude)); |
| | 563 | const suffix = mags[magnitude]; |
| | 564 | |
| | 565 | try formatFloatDecimal(new_value, width, context, Errors, output); |
| | 566 | |
| | 567 | if (suffix != ' ') { |
| | 568 | try output(context, (&suffix)[0..1]); |
| | 569 | } |
| | 570 | return output(context, "B"); |
| | 571 | } |
| 523 | | 572 | |
| 524 | pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, | 573 | pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, |
| 525 | context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void | 574 | context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void |
| ... | @@ -767,6 +816,12 @@ test "fmt.format" { | ... | @@ -767,6 +816,12 @@ test "fmt.format" { |
| 767 | const result = try bufPrint(buf1[0..], "u3: {}\n", value); | 816 | const result = try bufPrint(buf1[0..], "u3: {}\n", value); |
| 768 | assert(mem.eql(u8, result, "u3: 5\n")); | 817 | assert(mem.eql(u8, result, "u3: 5\n")); |
| 769 | } | 818 | } |
| | 819 | { |
| | 820 | var buf1: [32]u8 = undefined; |
| | 821 | const value: usize = 63 * 1024 * 1024; |
| | 822 | const result = try bufPrint(buf1[0..], "file size: {B}\n", value); |
| | 823 | assert(mem.eql(u8, result, "file size: 63MB\n")); |
| | 824 | } |
| 770 | { | 825 | { |
| 771 | // Dummy field because of https://github.com/zig-lang/zig/issues/557. | 826 | // Dummy field because of https://github.com/zig-lang/zig/issues/557. |
| 772 | const Struct = struct { | 827 | const Struct = struct { |