Commit 93ac76594a

Andrew Kelley <andrew@ziglang.org>
2025-07-10 00:31:02
std: fmt.format to io.Writer.print
allows reverting format -> deprecatedFormat, plus I think this is a nicer place for the function.
1 parent 4d93545
lib/std/crypto/ml_kem.zig
@@ -1737,11 +1737,11 @@ test "NIST KAT test" {
         var f = sha2.Sha256.init(.{});
         const fw = f.writer();
         var g = NistDRBG.init(seed);
-        try std.fmt.deprecatedFormat(fw, "# {s}\n\n", .{mode.name});
+        try std.fmt.format(fw, "# {s}\n\n", .{mode.name});
         for (0..100) |i| {
             g.fill(&seed);
-            try std.fmt.deprecatedFormat(fw, "count = {}\n", .{i});
-            try std.fmt.deprecatedFormat(fw, "seed = {X}\n", .{&seed});
+            try std.fmt.format(fw, "count = {}\n", .{i});
+            try std.fmt.format(fw, "seed = {X}\n", .{&seed});
             var g2 = NistDRBG.init(seed);
 
             // This is not equivalent to g2.fill(kseed[:]). As the reference
@@ -1756,10 +1756,10 @@ test "NIST KAT test" {
             const e = kp.public_key.encaps(eseed);
             const ss2 = try kp.secret_key.decaps(&e.ciphertext);
             try testing.expectEqual(ss2, e.shared_secret);
-            try std.fmt.deprecatedFormat(fw, "pk = {X}\n", .{&kp.public_key.toBytes()});
-            try std.fmt.deprecatedFormat(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()});
-            try std.fmt.deprecatedFormat(fw, "ct = {X}\n", .{&e.ciphertext});
-            try std.fmt.deprecatedFormat(fw, "ss = {X}\n\n", .{&e.shared_secret});
+            try std.fmt.format(fw, "pk = {X}\n", .{&kp.public_key.toBytes()});
+            try std.fmt.format(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()});
+            try std.fmt.format(fw, "ct = {X}\n", .{&e.ciphertext});
+            try std.fmt.format(fw, "ss = {X}\n\n", .{&e.shared_secret});
         }
 
         var out: [32]u8 = undefined;
lib/std/io/DeprecatedWriter.zig
@@ -21,7 +21,7 @@ pub fn writeAll(self: Self, bytes: []const u8) anyerror!void {
 }
 
 pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void {
-    return std.fmt.deprecatedFormat(self, format, args);
+    return std.fmt.format(self, format, args);
 }
 
 pub fn writeByte(self: Self, byte: u8) anyerror!void {
lib/std/io/Writer.zig
@@ -519,8 +519,192 @@ pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) E
     while (index < bytes.len) index += try w.writePreserve(preserve_length, bytes[index..]);
 }
 
-pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void {
-    try std.fmt.format(w, format, args);
+/// Renders fmt string with args, calling `writer` with slices of bytes.
+/// If `writer` returns an error, the error is returned from `format` and
+/// `writer` is not called again.
+///
+/// The format string must be comptime-known and may contain placeholders following
+/// this format:
+/// `{[argument][specifier]:[fill][alignment][width].[precision]}`
+///
+/// Above, each word including its surrounding [ and ] is a parameter which you have to replace with something:
+///
+/// - *argument* is either the numeric index or the field name of the argument that should be inserted
+///   - when using a field name, you are required to enclose the field name (an identifier) in square
+///     brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...}
+/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
+/// - *fill* is a single byte which is used to pad formatted numbers.
+/// - *alignment* is one of the three bytes '<', '^', or '>' to make numbers
+///   left, center, or right-aligned, respectively.
+///   - Not all specifiers support alignment.
+///   - Alignment is not Unicode-aware; appropriate only when used with raw bytes or ASCII.
+/// - *width* is the total width of the field in bytes. This only applies to number formatting.
+/// - *precision* specifies how many decimals a formatted number should have.
+///
+/// Note that most of the parameters are optional and may be omitted. Also you
+/// can leave out separators like `:` and `.` when all parameters after the
+/// separator are omitted.
+///
+/// Only exception is the *fill* parameter. If a non-zero *fill* character is
+/// required at the same time as *width* is specified, one has to specify
+/// *alignment* as well, as otherwise the digit following `:` is interpreted as
+/// *width*, not *fill*.
+///
+/// The *specifier* has several options for types:
+/// - `x` and `X`: output numeric value in hexadecimal notation, or string in hexadecimal bytes
+/// - `s`:
+///   - for pointer-to-many and C pointers of u8, print as a C-string using zero-termination
+///   - for slices of u8, print the entire slice as a string without zero-termination
+/// - `t`:
+///   - for enums and tagged unions: prints the tag name
+///   - for error sets: prints the error name
+/// - `b64`: output string as standard base64
+/// - `e`: output floating point value in scientific notation
+/// - `d`: output numeric value in decimal notation
+/// - `b`: output integer value in binary notation
+/// - `o`: output integer value in octal notation
+/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
+/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
+/// - `D`: output nanoseconds as duration
+/// - `B`: output bytes in SI units (decimal)
+/// - `Bi`: output bytes in IEC units (binary)
+/// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value.
+/// - `!`: output error union value as either the unwrapped value, or the formatted error value; may be followed by a format specifier for the underlying value.
+/// - `*`: output the address of the value instead of the value itself.
+/// - `any`: output a value of any type using its default format.
+/// - `f`: delegates to a method on the type named "format" with the signature `fn (*Writer, args: anytype) Writer.Error!void`.
+///
+/// A user type may be a `struct`, `vector`, `union` or `enum` type.
+///
+/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
+pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {
+    const ArgsType = @TypeOf(args);
+    const args_type_info = @typeInfo(ArgsType);
+    if (args_type_info != .@"struct") {
+        @compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
+    }
+
+    const fields_info = args_type_info.@"struct".fields;
+    const max_format_args = @typeInfo(std.fmt.ArgSetType).int.bits;
+    if (fields_info.len > max_format_args) {
+        @compileError("32 arguments max are supported per format call");
+    }
+
+    @setEvalBranchQuota(fmt.len * 1000);
+    comptime var arg_state: std.fmt.ArgState = .{ .args_len = fields_info.len };
+    comptime var i = 0;
+    comptime var literal: []const u8 = "";
+    inline while (true) {
+        const start_index = i;
+
+        inline while (i < fmt.len) : (i += 1) {
+            switch (fmt[i]) {
+                '{', '}' => break,
+                else => {},
+            }
+        }
+
+        comptime var end_index = i;
+        comptime var unescape_brace = false;
+
+        // Handle {{ and }}, those are un-escaped as single braces
+        if (i + 1 < fmt.len and fmt[i + 1] == fmt[i]) {
+            unescape_brace = true;
+            // Make the first brace part of the literal...
+            end_index += 1;
+            // ...and skip both
+            i += 2;
+        }
+
+        literal = literal ++ fmt[start_index..end_index];
+
+        // We've already skipped the other brace, restart the loop
+        if (unescape_brace) continue;
+
+        // Write out the literal
+        if (literal.len != 0) {
+            try w.writeAll(literal);
+            literal = "";
+        }
+
+        if (i >= fmt.len) break;
+
+        if (fmt[i] == '}') {
+            @compileError("missing opening {");
+        }
+
+        // Get past the {
+        comptime assert(fmt[i] == '{');
+        i += 1;
+
+        const fmt_begin = i;
+        // Find the closing brace
+        inline while (i < fmt.len and fmt[i] != '}') : (i += 1) {}
+        const fmt_end = i;
+
+        if (i >= fmt.len) {
+            @compileError("missing closing }");
+        }
+
+        // Get past the }
+        comptime assert(fmt[i] == '}');
+        i += 1;
+
+        const placeholder_array = fmt[fmt_begin..fmt_end].*;
+        const placeholder = comptime std.fmt.Placeholder.parse(&placeholder_array);
+        const arg_pos = comptime switch (placeholder.arg) {
+            .none => null,
+            .number => |pos| pos,
+            .named => |arg_name| std.meta.fieldIndex(ArgsType, arg_name) orelse
+                @compileError("no argument with name '" ++ arg_name ++ "'"),
+        };
+
+        const width = switch (placeholder.width) {
+            .none => null,
+            .number => |v| v,
+            .named => |arg_name| blk: {
+                const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse
+                    @compileError("no argument with name '" ++ arg_name ++ "'");
+                _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
+                break :blk @field(args, arg_name);
+            },
+        };
+
+        const precision = switch (placeholder.precision) {
+            .none => null,
+            .number => |v| v,
+            .named => |arg_name| blk: {
+                const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse
+                    @compileError("no argument with name '" ++ arg_name ++ "'");
+                _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
+                break :blk @field(args, arg_name);
+            },
+        };
+
+        const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse
+            @compileError("too few arguments");
+
+        try w.printValue(
+            placeholder.specifier_arg,
+            .{
+                .fill = placeholder.fill,
+                .alignment = placeholder.alignment,
+                .width = width,
+                .precision = precision,
+            },
+            @field(args, fields_info[arg_to_print].name),
+            std.options.fmt_max_depth,
+        );
+    }
+
+    if (comptime arg_state.hasUnusedArgs()) {
+        const missing_count = arg_state.args_len - @popCount(arg_state.used_args);
+        switch (missing_count) {
+            0 => unreachable,
+            1 => @compileError("unused argument in '" ++ fmt ++ "'"),
+            else => @compileError(std.fmt.comptimePrint("{d}", .{missing_count}) ++ " unused arguments in '" ++ fmt ++ "'"),
+        }
+    }
 }
 
 /// Calls `drain` as many times as necessary such that `byte` is transferred.
lib/std/json/stringify.zig
@@ -689,7 +689,7 @@ fn outputUnicodeEscape(codepoint: u21, out_stream: anytype) !void {
         // by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point.
         try out_stream.writeAll("\\u");
         //try w.printInt("x", .{ .width = 4, .fill = '0' }, codepoint);
-        try std.fmt.deprecatedFormat(out_stream, "{x:0>4}", .{codepoint});
+        try std.fmt.format(out_stream, "{x:0>4}", .{codepoint});
     } else {
         assert(codepoint <= 0x10FFFF);
         // To escape an extended character that is not in the Basic Multilingual Plane,
@@ -698,10 +698,10 @@ fn outputUnicodeEscape(codepoint: u21, out_stream: anytype) !void {
         const low = @as(u16, @intCast(codepoint & 0x3FF)) + 0xDC00;
         try out_stream.writeAll("\\u");
         //try w.printInt("x", .{ .width = 4, .fill = '0' }, high);
-        try std.fmt.deprecatedFormat(out_stream, "{x:0>4}", .{high});
+        try std.fmt.format(out_stream, "{x:0>4}", .{high});
         try out_stream.writeAll("\\u");
         //try w.printInt("x", .{ .width = 4, .fill = '0' }, low);
-        try std.fmt.deprecatedFormat(out_stream, "{x:0>4}", .{low});
+        try std.fmt.format(out_stream, "{x:0>4}", .{low});
     }
 }
 
lib/std/os/uefi.zig
@@ -65,7 +65,7 @@ pub const Guid = extern struct {
         const time_mid = @byteSwap(self.time_mid);
         const time_high_and_version = @byteSwap(self.time_high_and_version);
 
-        return std.fmt.format(writer, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
+        return writer.print("{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
             std.mem.asBytes(&time_low),
             std.mem.asBytes(&time_mid),
             std.mem.asBytes(&time_high_and_version),
lib/std/zig/render.zig
@@ -2872,7 +2872,7 @@ fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void {
                     .success => |codepoint| {
                         if (codepoint <= 0x7f) {
                             const buf = [1]u8{@as(u8, @intCast(codepoint))};
-                            try std.fmt.deprecatedFormat(writer, "{f}", .{std.zig.fmtString(&buf)});
+                            try std.fmt.format(writer, "{f}", .{std.zig.fmtString(&buf)});
                         } else {
                             try writer.writeAll(escape_sequence);
                         }
@@ -2884,7 +2884,7 @@ fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void {
             },
             0x00...('\\' - 1), ('\\' + 1)...0x7f => {
                 const buf = [1]u8{byte};
-                try std.fmt.deprecatedFormat(writer, "{f}", .{std.zig.fmtString(&buf)});
+                try std.fmt.format(writer, "{f}", .{std.zig.fmtString(&buf)});
                 pos += 1;
             },
             0x80...0xff => {
lib/std/zon/stringify.zig
@@ -501,7 +501,7 @@ pub fn Serializer(Writer: type) type {
                     try self.int(val);
                 },
                 .float, .comptime_float => try self.float(val),
-                .bool, .null => try std.fmt.deprecatedFormat(self.writer, "{}", .{val}),
+                .bool, .null => try std.fmt.format(self.writer, "{}", .{val}),
                 .enum_literal => try self.ident(@tagName(val)),
                 .@"enum" => try self.ident(@tagName(val)),
                 .pointer => |pointer| {
@@ -616,7 +616,7 @@ pub fn Serializer(Writer: type) type {
         /// Serialize an integer.
         pub fn int(self: *Self, val: anytype) Writer.Error!void {
             //try self.writer.printInt(val, 10, .lower, .{});
-            try std.fmt.deprecatedFormat(self.writer, "{d}", .{val});
+            try std.fmt.format(self.writer, "{d}", .{val});
         }
 
         /// Serialize a float.
@@ -631,12 +631,12 @@ pub fn Serializer(Writer: type) type {
                 } else if (std.math.isNegativeZero(val)) {
                     return self.writer.writeAll("-0.0");
                 } else {
-                    try std.fmt.deprecatedFormat(self.writer, "{d}", .{val});
+                    try std.fmt.format(self.writer, "{d}", .{val});
                 },
                 .comptime_float => if (val == 0) {
                     return self.writer.writeAll("0");
                 } else {
-                    try std.fmt.deprecatedFormat(self.writer, "{d}", .{val});
+                    try std.fmt.format(self.writer, "{d}", .{val});
                 },
                 else => comptime unreachable,
             }
@@ -659,7 +659,7 @@ pub fn Serializer(Writer: type) type {
             var buf: [8]u8 = undefined;
             const len = std.unicode.utf8Encode(val, &buf) catch return error.InvalidCodepoint;
             const str = buf[0..len];
-            try std.fmt.deprecatedFormat(self.writer, "'{f}'", .{std.zig.fmtChar(str)});
+            try std.fmt.format(self.writer, "'{f}'", .{std.zig.fmtChar(str)});
         }
 
         /// Like `value`, but always serializes `val` as a tuple.
@@ -717,7 +717,7 @@ pub fn Serializer(Writer: type) type {
 
         /// Like `value`, but always serializes `val` as a string.
         pub fn string(self: *Self, val: []const u8) Writer.Error!void {
-            try std.fmt.deprecatedFormat(self.writer, "\"{f}\"", .{std.zig.fmtString(val)});
+            try std.fmt.format(self.writer, "\"{f}\"", .{std.zig.fmtString(val)});
         }
 
         /// Options for formatting multiline strings.
lib/std/fmt.zig
@@ -78,197 +78,10 @@ pub const Number = struct {
     };
 };
 
-/// Renders fmt string with args, calling `writer` with slices of bytes.
-/// If `writer` returns an error, the error is returned from `format` and
-/// `writer` is not called again.
-///
-/// The format string must be comptime-known and may contain placeholders following
-/// this format:
-/// `{[argument][specifier]:[fill][alignment][width].[precision]}`
-///
-/// Above, each word including its surrounding [ and ] is a parameter which you have to replace with something:
-///
-/// - *argument* is either the numeric index or the field name of the argument that should be inserted
-///   - when using a field name, you are required to enclose the field name (an identifier) in square
-///     brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...}
-/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
-/// - *fill* is a single byte which is used to pad formatted numbers.
-/// - *alignment* is one of the three bytes '<', '^', or '>' to make numbers
-///   left, center, or right-aligned, respectively.
-///   - Not all specifiers support alignment.
-///   - Alignment is not Unicode-aware; appropriate only when used with raw bytes or ASCII.
-/// - *width* is the total width of the field in bytes. This only applies to number formatting.
-/// - *precision* specifies how many decimals a formatted number should have.
-///
-/// Note that most of the parameters are optional and may be omitted. Also you
-/// can leave out separators like `:` and `.` when all parameters after the
-/// separator are omitted.
-///
-/// Only exception is the *fill* parameter. If a non-zero *fill* character is
-/// required at the same time as *width* is specified, one has to specify
-/// *alignment* as well, as otherwise the digit following `:` is interpreted as
-/// *width*, not *fill*.
-///
-/// The *specifier* has several options for types:
-/// - `x` and `X`: output numeric value in hexadecimal notation, or string in hexadecimal bytes
-/// - `s`:
-///   - for pointer-to-many and C pointers of u8, print as a C-string using zero-termination
-///   - for slices of u8, print the entire slice as a string without zero-termination
-/// - `t`:
-///   - for enums and tagged unions: prints the tag name
-///   - for error sets: prints the error name
-/// - `b64`: output string as standard base64
-/// - `e`: output floating point value in scientific notation
-/// - `d`: output numeric value in decimal notation
-/// - `b`: output integer value in binary notation
-/// - `o`: output integer value in octal notation
-/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
-/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
-/// - `D`: output nanoseconds as duration
-/// - `B`: output bytes in SI units (decimal)
-/// - `Bi`: output bytes in IEC units (binary)
-/// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value.
-/// - `!`: output error union value as either the unwrapped value, or the formatted error value; may be followed by a format specifier for the underlying value.
-/// - `*`: output the address of the value instead of the value itself.
-/// - `any`: output a value of any type using its default format.
-/// - `f`: delegates to a method on the type named "format" with the signature `fn (*Writer, args: anytype) Writer.Error!void`.
-///
-/// A user type may be a `struct`, `vector`, `union` or `enum` type.
-///
-/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
-pub fn format(w: *Writer, comptime fmt: []const u8, args: anytype) Writer.Error!void {
-    const ArgsType = @TypeOf(args);
-    const args_type_info = @typeInfo(ArgsType);
-    if (args_type_info != .@"struct") {
-        @compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
-    }
-
-    const fields_info = args_type_info.@"struct".fields;
-    if (fields_info.len > max_format_args) {
-        @compileError("32 arguments max are supported per format call");
-    }
-
-    @setEvalBranchQuota(fmt.len * 1000);
-    comptime var arg_state: ArgState = .{ .args_len = fields_info.len };
-    comptime var i = 0;
-    comptime var literal: []const u8 = "";
-    inline while (true) {
-        const start_index = i;
-
-        inline while (i < fmt.len) : (i += 1) {
-            switch (fmt[i]) {
-                '{', '}' => break,
-                else => {},
-            }
-        }
-
-        comptime var end_index = i;
-        comptime var unescape_brace = false;
-
-        // Handle {{ and }}, those are un-escaped as single braces
-        if (i + 1 < fmt.len and fmt[i + 1] == fmt[i]) {
-            unescape_brace = true;
-            // Make the first brace part of the literal...
-            end_index += 1;
-            // ...and skip both
-            i += 2;
-        }
-
-        literal = literal ++ fmt[start_index..end_index];
-
-        // We've already skipped the other brace, restart the loop
-        if (unescape_brace) continue;
-
-        // Write out the literal
-        if (literal.len != 0) {
-            try w.writeAll(literal);
-            literal = "";
-        }
-
-        if (i >= fmt.len) break;
-
-        if (fmt[i] == '}') {
-            @compileError("missing opening {");
-        }
-
-        // Get past the {
-        comptime assert(fmt[i] == '{');
-        i += 1;
-
-        const fmt_begin = i;
-        // Find the closing brace
-        inline while (i < fmt.len and fmt[i] != '}') : (i += 1) {}
-        const fmt_end = i;
-
-        if (i >= fmt.len) {
-            @compileError("missing closing }");
-        }
-
-        // Get past the }
-        comptime assert(fmt[i] == '}');
-        i += 1;
-
-        const placeholder_array = fmt[fmt_begin..fmt_end].*;
-        const placeholder = comptime Placeholder.parse(&placeholder_array);
-        const arg_pos = comptime switch (placeholder.arg) {
-            .none => null,
-            .number => |pos| pos,
-            .named => |arg_name| meta.fieldIndex(ArgsType, arg_name) orelse
-                @compileError("no argument with name '" ++ arg_name ++ "'"),
-        };
-
-        const width = switch (placeholder.width) {
-            .none => null,
-            .number => |v| v,
-            .named => |arg_name| blk: {
-                const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse
-                    @compileError("no argument with name '" ++ arg_name ++ "'");
-                _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
-                break :blk @field(args, arg_name);
-            },
-        };
-
-        const precision = switch (placeholder.precision) {
-            .none => null,
-            .number => |v| v,
-            .named => |arg_name| blk: {
-                const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse
-                    @compileError("no argument with name '" ++ arg_name ++ "'");
-                _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
-                break :blk @field(args, arg_name);
-            },
-        };
-
-        const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse
-            @compileError("too few arguments");
-
-        try w.printValue(
-            placeholder.specifier_arg,
-            .{
-                .fill = placeholder.fill,
-                .alignment = placeholder.alignment,
-                .width = width,
-                .precision = precision,
-            },
-            @field(args, fields_info[arg_to_print].name),
-            std.options.fmt_max_depth,
-        );
-    }
-
-    if (comptime arg_state.hasUnusedArgs()) {
-        const missing_count = arg_state.args_len - @popCount(arg_state.used_args);
-        switch (missing_count) {
-            0 => unreachable,
-            1 => @compileError("unused argument in '" ++ fmt ++ "'"),
-            else => @compileError(comptimePrint("{d}", .{missing_count}) ++ " unused arguments in '" ++ fmt ++ "'"),
-        }
-    }
-}
-
-/// Deprecated in favor of `format`.
-pub fn deprecatedFormat(writer: anytype, comptime fmt: []const u8, args: anytype) !void {
+/// Deprecated in favor of `Writer.print`.
+pub fn format(writer: anytype, comptime fmt: []const u8, args: anytype) !void {
     var adapter = writer.adaptToNewApi();
-    return format(&adapter.new_interface, fmt, args) catch |err| switch (err) {
+    return adapter.new_interface.print(fmt, args) catch |err| switch (err) {
         error.WriteFailed => return adapter.err.?,
     };
 }
@@ -418,7 +231,6 @@ pub const Parser = struct {
 };
 
 pub const ArgSetType = u32;
-const max_format_args = @typeInfo(ArgSetType).int.bits;
 
 pub const ArgState = struct {
     next_arg: usize = 0,
@@ -1524,8 +1336,8 @@ test "recursive format function" {
 
         pub fn format(self: R, writer: *Writer) Writer.Error!void {
             return switch (self) {
-                .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}),
-                .Branch => |b| std.fmt.format(writer, "Branch({f}, {f})", .{ b.left, b.right }),
+                .Leaf => |n| writer.print("Leaf({})", .{n}),
+                .Branch => |b| writer.print("Branch({f}, {f})", .{ b.left, b.right }),
             };
         }
     };
src/link/tapi/parse.zig
@@ -83,15 +83,15 @@ pub const Node = struct {
 
         pub fn format(self: *const Doc, writer: *std.io.Writer) std.io.Writer.Error!void {
             if (self.directive) |id| {
-                try std.fmt.format(writer, "{{ ", .{});
+                try writer.print("{{ ", .{});
                 const directive = self.base.tree.getRaw(id, id);
-                try std.fmt.format(writer, ".directive = {s}, ", .{directive});
+                try writer.print(".directive = {s}, ", .{directive});
             }
             if (self.value) |node| {
-                try std.fmt.format(writer, "{}", .{node});
+                try writer.print("{}", .{node});
             }
             if (self.directive != null) {
-                try std.fmt.format(writer, " }}", .{});
+                try writer.print(" }}", .{});
             }
         }
     };