authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-11 10:56:24+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-07-11 10:56:24+02:00
logb60e9f2e85e1ca42d80d8822783dbbaed55e0526
tree32f17f4e8f8b940c0b0ab75e9d915d304dc4b69d
parenteb375525366ba51c3f626cf9b27d97fc81e2c938
parente25541549852c8dcf4acbcc1a3f3d7ef4bcef9d7
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24394 from ziglang/fixes

buffering fixes

4 files changed, 29 insertions(+), 14 deletions(-)

lib/std/Io/Reader.zig+9
...@@ -840,6 +840,9 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -840,6 +840,9 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
840/// Returns number of bytes streamed, which may be zero, or error.EndOfStream840/// Returns number of bytes streamed, which may be zero, or error.EndOfStream
841/// if the delimiter was not found.841/// if the delimiter was not found.
842///842///
843/// Asserts buffer capacity of at least one. This function performs better with
844/// larger buffers.
845///
843/// See also:846/// See also:
844/// * `streamDelimiterEnding`847/// * `streamDelimiterEnding`
845/// * `streamDelimiterLimit`848/// * `streamDelimiterLimit`
...@@ -858,6 +861,9 @@ pub fn streamDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize...@@ -858,6 +861,9 @@ pub fn streamDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize
858/// Returns number of bytes streamed, which may be zero. End of stream can be861/// Returns number of bytes streamed, which may be zero. End of stream can be
859/// detected by checking if the next byte in the stream is the delimiter.862/// detected by checking if the next byte in the stream is the delimiter.
860///863///
864/// Asserts buffer capacity of at least one. This function performs better with
865/// larger buffers.
866///
861/// See also:867/// See also:
862/// * `streamDelimiter`868/// * `streamDelimiter`
863/// * `streamDelimiterLimit`869/// * `streamDelimiterLimit`
...@@ -884,6 +890,9 @@ pub const StreamDelimiterLimitError = error{...@@ -884,6 +890,9 @@ pub const StreamDelimiterLimitError = error{
884///890///
885/// Returns number of bytes streamed, which may be zero. End of stream can be891/// Returns number of bytes streamed, which may be zero. End of stream can be
886/// detected by checking if the next byte in the stream is the delimiter.892/// detected by checking if the next byte in the stream is the delimiter.
893///
894/// Asserts buffer capacity of at least one. This function performs better with
895/// larger buffers.
887pub fn streamDelimiterLimit(896pub fn streamDelimiterLimit(
888 r: *Reader,897 r: *Reader,
889 w: *Writer,898 w: *Writer,
lib/std/Io/Writer.zig+5
...@@ -572,6 +572,10 @@ pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) E...@@ -572,6 +572,10 @@ pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) E
572/// A user type may be a `struct`, `vector`, `union` or `enum` type.572/// A user type may be a `struct`, `vector`, `union` or `enum` type.
573///573///
574/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.574/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
575///
576/// Asserts `buffer` capacity of at least 2 if a union is printed. This
577/// requirement could be lifted by adjusting the code, but if you trigger that
578/// assertion it is a clue that you should probably be using a buffer.
575pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {579pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {
576 const ArgsType = @TypeOf(args);580 const ArgsType = @TypeOf(args);
577 const args_type_info = @typeInfo(ArgsType);581 const args_type_info = @typeInfo(ArgsType);
...@@ -942,6 +946,7 @@ pub fn printAddress(w: *Writer, value: anytype) Error!void {...@@ -942,6 +946,7 @@ pub fn printAddress(w: *Writer, value: anytype) Error!void {
942 @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");946 @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
943}947}
944948
949/// Asserts `buffer` capacity of at least 2 if `value` is a union.
945pub fn printValue(950pub fn printValue(
946 w: *Writer,951 w: *Writer,
947 comptime fmt: []const u8,952 comptime fmt: []const u8,
lib/std/debug.zig+7-3
...@@ -219,10 +219,14 @@ pub fn unlockStderrWriter() void {...@@ -219,10 +219,14 @@ pub fn unlockStderrWriter() void {
219 std.Progress.unlockStderrWriter();219 std.Progress.unlockStderrWriter();
220}220}
221221
222/// Print to stderr, unbuffered, and silently returning on failure. Intended222/// Print to stderr, silently returning on failure. Intended for use in "printf
223/// for use in "printf debugging". Use `std.log` functions for proper logging.223/// debugging". Use `std.log` functions for proper logging.
224///
225/// Uses a 64-byte buffer for formatted printing which is flushed before this
226/// function returns.
224pub fn print(comptime fmt: []const u8, args: anytype) void {227pub fn print(comptime fmt: []const u8, args: anytype) void {
225 const bw = lockStderrWriter(&.{});228 var buffer: [64]u8 = undefined;
229 const bw = lockStderrWriter(&buffer);
226 defer unlockStderrWriter();230 defer unlockStderrWriter();
227 nosuspend bw.print(fmt, args) catch return;231 nosuspend bw.print(fmt, args) catch return;
228}232}
lib/std/log.zig+8-11
...@@ -137,8 +137,11 @@ pub fn defaultLogEnabled(comptime message_level: Level) bool {...@@ -137,8 +137,11 @@ pub fn defaultLogEnabled(comptime message_level: Level) bool {
137 return comptime logEnabled(message_level, default_log_scope);137 return comptime logEnabled(message_level, default_log_scope);
138}138}
139139
140/// The default implementation for the log function, custom log functions may140/// The default implementation for the log function. Custom log functions may
141/// forward log messages to this function.141/// forward log messages to this function.
142///
143/// Uses a 64-byte buffer for formatted printing which is flushed before this
144/// function returns.
142pub fn defaultLog(145pub fn defaultLog(
143 comptime message_level: Level,146 comptime message_level: Level,
144 comptime scope: @Type(.enum_literal),147 comptime scope: @Type(.enum_literal),
...@@ -147,16 +150,10 @@ pub fn defaultLog(...@@ -147,16 +150,10 @@ pub fn defaultLog(
147) void {150) void {
148 const level_txt = comptime message_level.asText();151 const level_txt = comptime message_level.asText();
149 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";152 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
150 const stderr = std.fs.File.stderr().deprecatedWriter();153 var buffer: [64]u8 = undefined;
151 var bw = std.io.bufferedWriter(stderr);154 const stderr = std.debug.lockStderrWriter(&buffer);
152 const writer = bw.writer();155 defer std.debug.unlockStderrWriter();
153156 nosuspend stderr.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
154 std.debug.lockStdErr();
155 defer std.debug.unlockStdErr();
156 nosuspend {
157 writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
158 bw.flush() catch return;
159 }
160}157}
161158
162/// Returns a scoped logging namespace that logs all messages using the scope159/// Returns a scoped logging namespace that logs all messages using the scope