| ... | ... | @@ -54,11 +54,7 @@ const extras = @import("extras"); |
| 54 | 54 | /// A user type may be a `struct`, `vector`, `union` or `enum` type. |
| 55 | 55 | /// |
| 56 | 56 | /// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`. |
| 57 | | pub fn format( |
| 58 | | writer: anytype, |
| 59 | | comptime fmt: []const u8, |
| 60 | | args: anytype, |
| 61 | | ) !void { |
| 57 | pub fn format(writer: anytype, comptime fmt: []const u8, args: anytype) !void { |
| 62 | 58 | const ArgsType = @TypeOf(args); |
| 63 | 59 | const args_type_info = @typeInfo(ArgsType); |
| 64 | 60 | if (args_type_info != .@"struct") { |
| ... | ... | @@ -134,16 +130,14 @@ pub fn format( |
| 134 | 130 | const arg_pos = comptime switch (placeholder.arg) { |
| 135 | 131 | .none => null, |
| 136 | 132 | .number => |pos| pos, |
| 137 | | .named => |arg_name| std.meta.fieldIndex(ArgsType, arg_name) orelse |
| 138 | | @compileError("no argument with name '" ++ arg_name ++ "'"), |
| 133 | .named => |arg_name| std.meta.fieldIndex(ArgsType, arg_name) orelse @compileError("no argument with name '" ++ arg_name ++ "'"), |
| 139 | 134 | }; |
| 140 | 135 | |
| 141 | 136 | const width = switch (placeholder.width) { |
| 142 | 137 | .none => null, |
| 143 | 138 | .number => |v| v, |
| 144 | 139 | .named => |arg_name| blk: { |
| 145 | | const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse |
| 146 | | @compileError("no argument with name '" ++ arg_name ++ "'"); |
| 140 | const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse @compileError("no argument with name '" ++ arg_name ++ "'"); |
| 147 | 141 | _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments"); |
| 148 | 142 | break :blk @field(args, arg_name); |
| 149 | 143 | }, |
| ... | ... | @@ -153,8 +147,7 @@ pub fn format( |
| 153 | 147 | .none => null, |
| 154 | 148 | .number => |v| v, |
| 155 | 149 | .named => |arg_name| blk: { |
| 156 | | const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse |
| 157 | | @compileError("no argument with name '" ++ arg_name ++ "'"); |
| 150 | const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse @compileError("no argument with name '" ++ arg_name ++ "'"); |
| 158 | 151 | _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments"); |
| 159 | 152 | break :blk @field(args, arg_name); |
| 160 | 153 | }, |
| ... | ... | @@ -165,7 +158,7 @@ pub fn format( |
| 165 | 158 | try formatType( |
| 166 | 159 | @field(args, fields_info[arg_to_print].name), |
| 167 | 160 | placeholder.specifier_arg, |
| 168 | | FormatOptions{ |
| 161 | .{ |
| 169 | 162 | .fill = placeholder.fill, |
| 170 | 163 | .alignment = placeholder.alignment, |
| 171 | 164 | .width = width, |
| ... | ... | @@ -244,8 +237,7 @@ pub const Placeholder = struct { |
| 244 | 237 | }; |
| 245 | 238 | |
| 246 | 239 | // Parse the positional argument number |
| 247 | | const arg = comptime parser.specifier() catch |err| |
| 248 | | @compileError(@errorName(err)); |
| 240 | const arg = comptime parser.specifier() catch |err| @compileError(@errorName(err)); |
| 249 | 241 | |
| 250 | 242 | // Parse the format specifier |
| 251 | 243 | const specifier_arg = comptime parser.until(':'); |
| ... | ... | @@ -291,8 +283,7 @@ pub const Placeholder = struct { |
| 291 | 283 | } |
| 292 | 284 | |
| 293 | 285 | // Parse the width parameter |
| 294 | | const width = comptime parser.specifier() catch |err| |
| 295 | | @compileError(@errorName(err)); |
| 286 | const width = comptime parser.specifier() catch |err| @compileError(@errorName(err)); |
| 296 | 287 | |
| 297 | 288 | // Skip the dot, if present |
| 298 | 289 | if (comptime parser.char()) |ch| { |
| ... | ... | @@ -302,8 +293,7 @@ pub const Placeholder = struct { |
| 302 | 293 | } |
| 303 | 294 | |
| 304 | 295 | // Parse the precision parameter |
| 305 | | const precision = comptime parser.specifier() catch |err| |
| 306 | | @compileError(@errorName(err)); |
| 296 | const precision = comptime parser.specifier() catch |err| @compileError(@errorName(err)); |
| 307 | 297 | |
| 308 | 298 | if (comptime parser.char()) |ch| { |
| 309 | 299 | @compileError("extraneous trailing character '" ++ std.unicode.utf8EncodeComptime(ch) ++ "'"); |
| ... | ... | @@ -450,8 +440,7 @@ fn formatType(value: anytype, comptime fmt: []const u8, options: FormatOptions, |
| 450 | 440 | return formatBuf(if (value) "true" else "false", options, writer); |
| 451 | 441 | }, |
| 452 | 442 | .optional => { |
| 453 | | if (actual_fmt.len == 0 or actual_fmt[0] != '?') |
| 454 | | @compileError("cannot format optional without a specifier (i.e. {?} or {any})"); |
| 443 | if (actual_fmt.len == 0 or actual_fmt[0] != '?') @compileError("cannot format optional without a specifier (i.e. {?} or {any})"); |
| 455 | 444 | const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt); |
| 456 | 445 | if (value) |payload| { |
| 457 | 446 | return formatType(payload, remaining_fmt, options, writer, max_depth); |
| ... | ... | @@ -460,8 +449,7 @@ fn formatType(value: anytype, comptime fmt: []const u8, options: FormatOptions, |
| 460 | 449 | } |
| 461 | 450 | }, |
| 462 | 451 | .error_union => { |
| 463 | | if (actual_fmt.len == 0 or actual_fmt[0] != '!') |
| 464 | | @compileError("cannot format error union without a specifier (i.e. {!} or {any})"); |
| 452 | if (actual_fmt.len == 0 or actual_fmt[0] != '!') @compileError("cannot format error union without a specifier (i.e. {!} or {any})"); |
| 465 | 453 | const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt); |
| 466 | 454 | if (value) |payload| { |
| 467 | 455 | return formatType(payload, remaining_fmt, options, writer, max_depth); |
| ... | ... | @@ -571,8 +559,9 @@ fn formatType(value: anytype, comptime fmt: []const u8, options: FormatOptions, |
| 571 | 559 | invalidFmtError(fmt, value); |
| 572 | 560 | }, |
| 573 | 561 | .slice => { |
| 574 | | if (actual_fmt.len == 0) |
| 562 | if (actual_fmt.len == 0) { |
| 575 | 563 | @compileError("cannot format slice without a specifier (i.e. {s} or {any})"); |
| 564 | } |
| 576 | 565 | if (max_depth == 0) { |
| 577 | 566 | return writer.writeAll("{ ... }"); |
| 578 | 567 | } |
| ... | ... | @@ -590,8 +579,9 @@ fn formatType(value: anytype, comptime fmt: []const u8, options: FormatOptions, |
| 590 | 579 | }, |
| 591 | 580 | }, |
| 592 | 581 | .array => |info| { |
| 593 | | if (actual_fmt.len == 0) |
| 582 | if (actual_fmt.len == 0) { |
| 594 | 583 | @compileError("cannot format array without a specifier (i.e. {s} or {any})"); |
| 584 | } |
| 595 | 585 | if (max_depth == 0) { |
| 596 | 586 | return writer.writeAll("{ ... }"); |
| 597 | 587 | } |
| ... | ... | @@ -700,13 +690,7 @@ fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @TypeO |
| 700 | 690 | @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier"); |
| 701 | 691 | } |
| 702 | 692 | |
| 703 | | pub fn formatInt( |
| 704 | | value: anytype, |
| 705 | | base: u8, |
| 706 | | case: Case, |
| 707 | | options: FormatOptions, |
| 708 | | writer: anytype, |
| 709 | | ) !void { |
| 693 | pub fn formatInt(value: anytype, base: u8, case: Case, options: FormatOptions, writer: anytype) !void { |
| 710 | 694 | std.debug.assert(base >= 2); |
| 711 | 695 | |
| 712 | 696 | const int_value = if (@TypeOf(value) == comptime_int) blk: { |
| ... | ... | @@ -768,12 +752,7 @@ pub fn formatInt( |
| 768 | 752 | return formatBuf(buf[index..], options, writer); |
| 769 | 753 | } |
| 770 | 754 | |
| 771 | | fn formatValue( |
| 772 | | value: anytype, |
| 773 | | comptime fmt: []const u8, |
| 774 | | options: FormatOptions, |
| 775 | | writer: anytype, |
| 776 | | ) !void { |
| 755 | fn formatValue(value: anytype, comptime fmt: []const u8, options: FormatOptions, writer: anytype) !void { |
| 777 | 756 | const T = @TypeOf(value); |
| 778 | 757 | switch (@typeInfo(T)) { |
| 779 | 758 | // .float, .comptime_float => return formatFloatValue(value, fmt, options, writer), |
| ... | ... | @@ -788,18 +767,13 @@ fn invalidFmtError(comptime fmt: []const u8, value: anytype) void { |
| 788 | 767 | @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); |
| 789 | 768 | } |
| 790 | 769 | |
| 791 | | fn formatBuf( |
| 792 | | buf: []const u8, |
| 793 | | options: FormatOptions, |
| 794 | | writer: anytype, |
| 795 | | ) !void { |
| 770 | fn formatBuf(buf: []const u8, options: FormatOptions, writer: anytype) !void { |
| 796 | 771 | if (options.width) |min_width| { |
| 797 | 772 | // In case of error assume the buffer content is ASCII-encoded |
| 798 | 773 | const width = std.unicode.utf8CountCodepoints(buf) catch buf.len; |
| 799 | 774 | const padding = if (width < min_width) min_width - width else 0; |
| 800 | 775 | |
| 801 | | if (padding == 0) |
| 802 | | return writer.writeAll(buf); |
| 776 | if (padding == 0) return writer.writeAll(buf); |
| 803 | 777 | |
| 804 | 778 | var fill_buffer: [4]u8 = undefined; |
| 805 | 779 | const fill_utf8 = if (std.unicode.utf8Encode(options.fill, &fill_buffer)) |len| |
| ... | ... | @@ -863,14 +837,14 @@ const digits2_alphabet = blk: { |
| 863 | 837 | }; |
| 864 | 838 | |
| 865 | 839 | /// Converts values in the range [0, 100) to a base 10 string. |
| 866 | | fn digits2(value: u8) [2]u8 { |
| 840 | pub fn digits2(value: u8) [2]u8 { |
| 867 | 841 | return digits2_alphabet[value * 2 ..][0..2].*; |
| 868 | 842 | } |
| 869 | 843 | |
| 870 | | fn digitToChar(digit: u8, case: Case) u8 { |
| 844 | pub fn digitToChar(digit: u8, case: Case) u8 { |
| 871 | 845 | return switch (digit) { |
| 872 | 846 | 0...9 => digit + '0', |
| 873 | | 10...35 => digit + ((if (case == .upper) @as(u8, 'A') else @as(u8, 'a')) - 10), |
| 847 | 10...35 => digit + (if (case == .upper) @as(u8, 'A') else @as(u8, 'a')) - 10, |
| 874 | 848 | else => unreachable, |
| 875 | 849 | }; |
| 876 | 850 | } |