eliminate all uses of std.io.Writer.count except for CBE

This commit is contained in:
Andrew Kelley 2025-07-08 17:33:02 -07:00
parent d345a10054
commit bc2cf0c173
8 changed files with 81 additions and 94 deletions

View file

@ -1603,10 +1603,10 @@ test "manage resources correctly" {
// self-hosted debug info is still too buggy
if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
var writer: std.io.Writer = .discarding(&.{});
var discarding: std.io.Writer.Discarding = .init(&.{});
var di = try SelfInfo.open(testing.allocator);
defer di.deinit();
try printSourceAtAddress(&di, &writer, showMyTrace(), io.tty.detectConfig(.stderr()));
try printSourceAtAddress(&di, &discarding.writer, showMyTrace(), io.tty.detectConfig(.stderr()));
}
noinline fn showMyTrace() usize {

View file

@ -772,11 +772,11 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
/// Count the characters needed for format.
pub fn count(comptime fmt: []const u8, args: anytype) usize {
var trash_buffer: [64]u8 = undefined;
var w: Writer = .discarding(&trash_buffer);
w.print(fmt, args) catch |err| switch (err) {
var dw: Writer.Discarding = .init(&trash_buffer);
dw.writer.print(fmt, args) catch |err| switch (err) {
error.WriteFailed => unreachable,
};
return w.count;
return @intCast(dw.count + dw.writer.end);
}
pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 {

View file

@ -1293,13 +1293,14 @@ pub const basic_authorization = struct {
const user: Uri.Component = uri.user orelse .empty;
const password: Uri.Component = uri.password orelse .empty;
var w: std.io.Writer = .discarding(&.{});
user.formatUser(&w) catch unreachable; // discarding
const user_len = w.count;
var dw: std.io.Writer.Discarding = .init(&.{});
user.formatUser(&dw.writer) catch unreachable; // discarding
const user_len = dw.count + dw.writer.end;
w.count = 0;
password.formatPassword(&w) catch unreachable; // discarding
const password_len = w.count;
dw.count = 0;
dw.writer.end = 0;
password.formatPassword(&dw.writer) catch unreachable; // discarding
const password_len = dw.count + dw.writer.end;
return valueLength(@intCast(user_len), @intCast(password_len));
}
@ -1311,7 +1312,6 @@ pub const basic_authorization = struct {
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
var w: std.io.Writer = .fixed(&buf);
user.formatUser(&w) catch unreachable; // fixed
assert(w.count <= max_user_len);
password.formatPassword(&w) catch unreachable; // fixed
@memcpy(out[0..prefix.len], prefix);

View file

@ -132,10 +132,8 @@ pub fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
r.seek += n;
return n;
}
const before = w.count;
const n = try r.vtable.stream(r, w, limit);
assert(n <= @intFromEnum(limit));
assert(w.count == before + n);
return n;
}
@ -158,17 +156,17 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {
pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
assert(r.seek == 0);
assert(r.end == 0);
var w: Writer = .discarding(r.buffer);
const n = r.stream(&w, limit) catch |err| switch (err) {
var dw: Writer.Discarding = .init(r.buffer);
const n = r.stream(&dw.writer, limit) catch |err| switch (err) {
error.WriteFailed => unreachable,
error.ReadFailed => return error.ReadFailed,
error.EndOfStream => return error.EndOfStream,
};
if (n > @intFromEnum(limit)) {
const over_amt = n - @intFromEnum(limit);
r.seek = w.end - over_amt;
r.end = w.end;
assert(r.end <= w.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
r.seek = dw.writer.end - over_amt;
r.end = dw.writer.end;
assert(r.end <= dw.writer.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
return @intFromEnum(limit);
}
return n;

View file

@ -14,12 +14,6 @@ vtable: *const VTable,
buffer: []u8,
/// In `buffer` before this are buffered bytes, after this is `undefined`.
end: usize = 0,
/// Tracks total number of bytes written to this `Writer`. This value
/// only increases. In the case of fixed mode, this value always equals `end`.
///
/// This value is maintained by the interface; `VTable` function
/// implementations need not modify it.
count: usize = 0,
pub const VTable = struct {
/// Sends bytes to the logical sink. A write will only be sent here if it
@ -117,8 +111,7 @@ pub const FileError = error{
Unimplemented,
};
/// Writes to `buffer` and returns `error.WriteFailed` when it is full. Unless
/// modified externally, `count` will always equal `end`.
/// Writes to `buffer` and returns `error.WriteFailed` when it is full.
pub fn fixed(buffer: []u8) Writer {
return .{
.vtable = &.{ .drain = fixedDrain },
@ -137,16 +130,6 @@ pub const failing: Writer = .{
},
};
pub fn discarding(buffer: []u8) Writer {
return .{
.vtable = &.{
.drain = discardingDrain,
.sendFile = discardingSendFile,
},
.buffer = buffer,
};
}
/// Returns the contents not yet drained.
pub fn buffered(w: *const Writer) []u8 {
return w.buffer[0..w.end];
@ -178,12 +161,7 @@ pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
assert(data.len > 0);
const buffer = w.buffer;
const count = countSplat(data, splat);
if (w.end + count > buffer.len) {
const n = try w.vtable.drain(w, data, splat);
w.count += n;
return n;
}
w.count += count;
if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat);
for (data) |bytes| {
@memcpy(buffer[w.end..][0..bytes.len], bytes);
w.end += bytes.len;
@ -236,7 +214,6 @@ pub fn writeSplatHeader(
if (new_end <= w.buffer.len) {
@memcpy(w.buffer[w.end..][0..header.len], header);
w.end = new_end;
w.count += header.len;
return header.len + try writeSplat(w, data, splat);
}
var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size.
@ -249,9 +226,7 @@ pub fn writeSplatHeader(
if (vecs.len - i == 0) break;
}
const new_splat = if (vecs[i - 1].ptr == data[data.len - 1].ptr) splat else 1;
const n = try w.vtable.drain(w, vecs[0..i], new_splat);
w.count += n;
return n;
return w.vtable.drain(w, vecs[0..i], new_splat);
}
/// Equivalent to `writeSplatHeader` but writes at most `limit` bytes.
@ -429,7 +404,6 @@ pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
pub fn undo(w: *Writer, n: usize) void {
w.end -= n;
w.count -= n;
}
/// After calling `writableSliceGreedy`, this function tracks how many bytes
@ -440,13 +414,11 @@ pub fn advance(w: *Writer, n: usize) void {
const new_end = w.end + n;
assert(new_end <= w.buffer.len);
w.end = new_end;
w.count += n;
}
/// After calling `writableVector`, this function tracks how many bytes were
/// written to it.
pub fn advanceVector(w: *Writer, n: usize) usize {
w.count += n;
return consume(w, n);
}
@ -504,12 +476,9 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
@branchHint(.likely);
@memcpy(w.buffer[w.end..][0..bytes.len], bytes);
w.end += bytes.len;
w.count += bytes.len;
return bytes.len;
}
const n = try w.vtable.drain(w, &.{bytes}, 1);
w.count += n;
return n;
return w.vtable.drain(w, &.{bytes}, 1);
}
/// Asserts `buffer` capacity exceeds `preserve_length`.
@ -519,7 +488,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro
@branchHint(.likely);
@memcpy(w.buffer[w.end..][0..bytes.len], bytes);
w.end += bytes.len;
w.count += bytes.len;
return bytes.len;
}
const temp_end = w.end -| preserve_length;
@ -527,7 +495,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro
w.end = temp_end;
defer w.end += preserved.len;
const n = try w.vtable.drain(w, &.{bytes}, 1);
w.count += n;
assert(w.end <= temp_end + preserved.len);
@memmove(w.buffer[w.end..][0..preserved.len], preserved);
return n;
@ -560,15 +527,11 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void
pub fn writeByte(w: *Writer, byte: u8) Error!void {
while (w.buffer.len - w.end == 0) {
const n = try w.vtable.drain(w, &.{&.{byte}}, 1);
if (n > 0) {
w.count += 1;
return;
}
if (n > 0) return;
} else {
@branchHint(.likely);
w.buffer[w.end] = byte;
w.end += 1;
w.count += 1;
}
}
@ -581,7 +544,6 @@ pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!voi
@branchHint(.likely);
w.buffer[w.end] = byte;
w.end += 1;
w.count += 1;
}
}
@ -690,12 +652,10 @@ pub fn sendFileHeader(
if (new_end <= w.buffer.len) {
@memcpy(w.buffer[w.end..][0..header.len], header);
w.end = new_end;
w.count += header.len;
return header.len + try w.vtable.sendFile(w, file_reader, limit);
}
const buffered_contents = limit.slice(file_reader.interface.buffered());
const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1);
w.count += n;
file_reader.interface.toss(n - header.len);
return n;
}
@ -1950,29 +1910,52 @@ pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) File
return error.WriteFailed;
}
pub fn discardingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
pub const Discarding = struct {
count: u64,
writer: Writer,
pub fn init(buffer: []u8) Discarding {
return .{
.count = 0,
.writer = .{
.vtable = &.{
.drain = Discarding.drain,
.sendFile = Discarding.sendFile,
},
.buffer = buffer,
},
};
}
pub fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
const slice = data[0 .. data.len - 1];
const pattern = data[slice.len..];
var written: usize = pattern.len * splat;
for (slice) |bytes| written += bytes.len;
d.count += w.end + written;
w.end = 0;
return written;
}
}
pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
if (File.Handle == void) return error.Unimplemented;
const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
d.count += w.end;
w.end = 0;
if (file_reader.getSize()) |size| {
const n = limit.minInt64(size - file_reader.pos);
file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
w.end = 0;
d.count += n;
return n;
} else |_| {
// Error is observable on `file_reader` instance, and it is better to
// treat the file as a pipe.
return error.Unimplemented;
}
}
}
};
/// Removes the first `n` bytes from `buffer` by shifting buffer contents,
/// returning how many bytes are left after consuming the entire buffer, or
@ -2219,9 +2202,7 @@ pub const Allocating = struct {
}
pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void {
const shrink_by = a.writer.end - new_len;
a.writer.end = new_len;
a.writer.count -= shrink_by;
}
pub fn clearRetainingCapacity(a: *Allocating) void {

View file

@ -195,22 +195,30 @@ fn renderErrorMessageToWriter(
) (Writer.Error || std.posix.UnexpectedError)!void {
const ttyconf = options.ttyconf;
const err_msg = eb.getErrorMessage(err_msg_index);
const prefix_start = w.count;
if (err_msg.src_loc != .none) {
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
var prefix: std.io.Writer.Discarding = .init(&.{});
try w.splatByteAll(' ', indent);
prefix.count += indent;
try ttyconf.setColor(w, .bold);
try w.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
src.data.column + 1,
});
try prefix.writer.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
src.data.column + 1,
});
try ttyconf.setColor(w, color);
try w.writeAll(kind);
prefix.count += kind.len;
try w.writeAll(": ");
prefix.count += 2;
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
const prefix_len = w.count - prefix_start;
const prefix_len: usize = @intCast(prefix.count);
try ttyconf.setColor(w, .reset);
try ttyconf.setColor(w, .bold);
if (err_msg.count == 1) {

View file

@ -1016,8 +1016,8 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
// By using a buffer with maximum length of encoded instruction, we can use
// the `end` field of the Writer for the count.
var buf: [16]u8 = undefined;
var trash = std.io.Writer.discarding(&buf);
inst.encode(&trash, .{
var trash: std.io.Writer.Discarding = .init(&buf);
inst.encode(&trash.writer, .{
.allow_frame_locs = true,
.allow_symbols = true,
}) catch {
@ -1027,7 +1027,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
// (`estimateInstructionLength`) has the wrong function signature.
@panic("unexpected failure to encode");
};
return @intCast(trash.end);
return trash.writer.end;
}
const mnemonic_to_encodings_map = init: {

View file

@ -1390,8 +1390,8 @@ const x86_64 = struct {
// TODO: hack to force imm32s in the assembler
.{ .imm = .s(-129) },
}, t) catch return false;
var trash = std.io.Writer.discarding(&.{});
inst.encode(&trash, .{}) catch return false;
var trash: std.io.Writer.Discarding = .init(&.{});
inst.encode(&trash.writer, .{}) catch return false;
return true;
},
else => return false,