authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-08 17:33:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-09 09:32:07-07:00
logbc2cf0c173465f4e3ac60fe2907dfedd2eebf8eb
tree7a404dc11967aa7d552f9fd727477257dd49ad03
parentd345a10054caa78d6e697089b0b3ca5b540b2d9c

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


8 files changed, 80 insertions(+), 93 deletions(-)

lib/std/debug.zig+2-2
......@@ -1603,10 +1603,10 @@ test "manage resources correctly" {
16031603 // self-hosted debug info is still too buggy
16041604 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
16051605
1606 var writer: std.io.Writer = .discarding(&.{});
1606 var discarding: std.io.Writer.Discarding = .init(&.{});
16071607 var di = try SelfInfo.open(testing.allocator);
16081608 defer di.deinit();
1609 try printSourceAtAddress(&di, &writer, showMyTrace(), io.tty.detectConfig(.stderr()));
1609 try printSourceAtAddress(&di, &discarding.writer, showMyTrace(), io.tty.detectConfig(.stderr()));
16101610}
16111611
16121612noinline fn showMyTrace() usize {
lib/std/fmt.zig+3-3
......@@ -772,11 +772,11 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
772772/// Count the characters needed for format.
773773pub fn count(comptime fmt: []const u8, args: anytype) usize {
774774 var trash_buffer: [64]u8 = undefined;
775 var w: Writer = .discarding(&trash_buffer);
776 w.print(fmt, args) catch |err| switch (err) {
775 var dw: Writer.Discarding = .init(&trash_buffer);
776 dw.writer.print(fmt, args) catch |err| switch (err) {
777777 error.WriteFailed => unreachable,
778778 };
779 return w.count;
779 return @intCast(dw.count + dw.writer.end);
780780}
781781
782782pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 {
lib/std/http/Client.zig+7-7
......@@ -1293,13 +1293,14 @@ pub const basic_authorization = struct {
12931293 const user: Uri.Component = uri.user orelse .empty;
12941294 const password: Uri.Component = uri.password orelse .empty;
12951295
1296 var w: std.io.Writer = .discarding(&.{});
1297 user.formatUser(&w) catch unreachable; // discarding
1298 const user_len = w.count;
1296 var dw: std.io.Writer.Discarding = .init(&.{});
1297 user.formatUser(&dw.writer) catch unreachable; // discarding
1298 const user_len = dw.count + dw.writer.end;
12991299
1300 w.count = 0;
1301 password.formatPassword(&w) catch unreachable; // discarding
1302 const password_len = w.count;
1300 dw.count = 0;
1301 dw.writer.end = 0;
1302 password.formatPassword(&dw.writer) catch unreachable; // discarding
1303 const password_len = dw.count + dw.writer.end;
13031304
13041305 return valueLength(@intCast(user_len), @intCast(password_len));
13051306 }
......@@ -1311,7 +1312,6 @@ pub const basic_authorization = struct {
13111312 var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
13121313 var w: std.io.Writer = .fixed(&buf);
13131314 user.formatUser(&w) catch unreachable; // fixed
1314 assert(w.count <= max_user_len);
13151315 password.formatPassword(&w) catch unreachable; // fixed
13161316
13171317 @memcpy(out[0..prefix.len], prefix);
lib/std/io/Reader.zig+5-7
......@@ -132,10 +132,8 @@ pub fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
132132 r.seek += n;
133133 return n;
134134 }
135 const before = w.count;
136135 const n = try r.vtable.stream(r, w, limit);
137136 assert(n <= @intFromEnum(limit));
138 assert(w.count == before + n);
139137 return n;
140138}
141139
......@@ -158,17 +156,17 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {
158156pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
159157 assert(r.seek == 0);
160158 assert(r.end == 0);
161 var w: Writer = .discarding(r.buffer);
162 const n = r.stream(&w, limit) catch |err| switch (err) {
159 var dw: Writer.Discarding = .init(r.buffer);
160 const n = r.stream(&dw.writer, limit) catch |err| switch (err) {
163161 error.WriteFailed => unreachable,
164162 error.ReadFailed => return error.ReadFailed,
165163 error.EndOfStream => return error.EndOfStream,
166164 };
167165 if (n > @intFromEnum(limit)) {
168166 const over_amt = n - @intFromEnum(limit);
169 r.seek = w.end - over_amt;
170 r.end = w.end;
171 assert(r.end <= w.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
167 r.seek = dw.writer.end - over_amt;
168 r.end = dw.writer.end;
169 assert(r.end <= dw.writer.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
172170 return @intFromEnum(limit);
173171 }
174172 return n;
lib/std/io/Writer.zig+48-67
......@@ -14,12 +14,6 @@ vtable: *const VTable,
1414buffer: []u8,
1515/// In `buffer` before this are buffered bytes, after this is `undefined`.
1616end: usize = 0,
17/// Tracks total number of bytes written to this `Writer`. This value
18/// only increases. In the case of fixed mode, this value always equals `end`.
19///
20/// This value is maintained by the interface; `VTable` function
21/// implementations need not modify it.
22count: usize = 0,
2317
2418pub const VTable = struct {
2519 /// Sends bytes to the logical sink. A write will only be sent here if it
......@@ -117,8 +111,7 @@ pub const FileError = error{
117111 Unimplemented,
118112};
119113
120/// Writes to `buffer` and returns `error.WriteFailed` when it is full. Unless
121/// modified externally, `count` will always equal `end`.
114/// Writes to `buffer` and returns `error.WriteFailed` when it is full.
122115pub fn fixed(buffer: []u8) Writer {
123116 return .{
124117 .vtable = &.{ .drain = fixedDrain },
......@@ -137,16 +130,6 @@ pub const failing: Writer = .{
137130 },
138131};
139132
140pub fn discarding(buffer: []u8) Writer {
141 return .{
142 .vtable = &.{
143 .drain = discardingDrain,
144 .sendFile = discardingSendFile,
145 },
146 .buffer = buffer,
147 };
148}
149
150133/// Returns the contents not yet drained.
151134pub fn buffered(w: *const Writer) []u8 {
152135 return w.buffer[0..w.end];
......@@ -178,12 +161,7 @@ pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
178161 assert(data.len > 0);
179162 const buffer = w.buffer;
180163 const count = countSplat(data, splat);
181 if (w.end + count > buffer.len) {
182 const n = try w.vtable.drain(w, data, splat);
183 w.count += n;
184 return n;
185 }
186 w.count += count;
164 if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat);
187165 for (data) |bytes| {
188166 @memcpy(buffer[w.end..][0..bytes.len], bytes);
189167 w.end += bytes.len;
......@@ -236,7 +214,6 @@ pub fn writeSplatHeader(
236214 if (new_end <= w.buffer.len) {
237215 @memcpy(w.buffer[w.end..][0..header.len], header);
238216 w.end = new_end;
239 w.count += header.len;
240217 return header.len + try writeSplat(w, data, splat);
241218 }
242219 var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size.
......@@ -249,9 +226,7 @@ pub fn writeSplatHeader(
249226 if (vecs.len - i == 0) break;
250227 }
251228 const new_splat = if (vecs[i - 1].ptr == data[data.len - 1].ptr) splat else 1;
252 const n = try w.vtable.drain(w, vecs[0..i], new_splat);
253 w.count += n;
254 return n;
229 return w.vtable.drain(w, vecs[0..i], new_splat);
255230}
256231
257232/// Equivalent to `writeSplatHeader` but writes at most `limit` bytes.
......@@ -429,7 +404,6 @@ pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
429404
430405pub fn undo(w: *Writer, n: usize) void {
431406 w.end -= n;
432 w.count -= n;
433407}
434408
435409/// After calling `writableSliceGreedy`, this function tracks how many bytes
......@@ -440,13 +414,11 @@ pub fn advance(w: *Writer, n: usize) void {
440414 const new_end = w.end + n;
441415 assert(new_end <= w.buffer.len);
442416 w.end = new_end;
443 w.count += n;
444417}
445418
446419/// After calling `writableVector`, this function tracks how many bytes were
447420/// written to it.
448421pub fn advanceVector(w: *Writer, n: usize) usize {
449 w.count += n;
450422 return consume(w, n);
451423}
452424
......@@ -504,12 +476,9 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
504476 @branchHint(.likely);
505477 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
506478 w.end += bytes.len;
507 w.count += bytes.len;
508479 return bytes.len;
509480 }
510 const n = try w.vtable.drain(w, &.{bytes}, 1);
511 w.count += n;
512 return n;
481 return w.vtable.drain(w, &.{bytes}, 1);
513482}
514483
515484/// Asserts `buffer` capacity exceeds `preserve_length`.
......@@ -519,7 +488,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro
519488 @branchHint(.likely);
520489 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
521490 w.end += bytes.len;
522 w.count += bytes.len;
523491 return bytes.len;
524492 }
525493 const temp_end = w.end -| preserve_length;
......@@ -527,7 +495,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro
527495 w.end = temp_end;
528496 defer w.end += preserved.len;
529497 const n = try w.vtable.drain(w, &.{bytes}, 1);
530 w.count += n;
531498 assert(w.end <= temp_end + preserved.len);
532499 @memmove(w.buffer[w.end..][0..preserved.len], preserved);
533500 return n;
......@@ -560,15 +527,11 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void
560527pub fn writeByte(w: *Writer, byte: u8) Error!void {
561528 while (w.buffer.len - w.end == 0) {
562529 const n = try w.vtable.drain(w, &.{&.{byte}}, 1);
563 if (n > 0) {
564 w.count += 1;
565 return;
566 }
530 if (n > 0) return;
567531 } else {
568532 @branchHint(.likely);
569533 w.buffer[w.end] = byte;
570534 w.end += 1;
571 w.count += 1;
572535 }
573536}
574537
......@@ -581,7 +544,6 @@ pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!voi
581544 @branchHint(.likely);
582545 w.buffer[w.end] = byte;
583546 w.end += 1;
584 w.count += 1;
585547 }
586548}
587549
......@@ -690,12 +652,10 @@ pub fn sendFileHeader(
690652 if (new_end <= w.buffer.len) {
691653 @memcpy(w.buffer[w.end..][0..header.len], header);
692654 w.end = new_end;
693 w.count += header.len;
694655 return header.len + try w.vtable.sendFile(w, file_reader, limit);
695656 }
696657 const buffered_contents = limit.slice(file_reader.interface.buffered());
697658 const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1);
698 w.count += n;
699659 file_reader.interface.toss(n - header.len);
700660 return n;
701661}
......@@ -1950,29 +1910,52 @@ pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) File
19501910 return error.WriteFailed;
19511911}
19521912
1953pub fn discardingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
1954 const slice = data[0 .. data.len - 1];
1955 const pattern = data[slice.len..];
1956 var written: usize = pattern.len * splat;
1957 for (slice) |bytes| written += bytes.len;
1958 w.end = 0;
1959 return written;
1960}
1913pub const Discarding = struct {
1914 count: u64,
1915 writer: Writer,
19611916
1962pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
1963 if (File.Handle == void) return error.Unimplemented;
1964 w.end = 0;
1965 if (file_reader.getSize()) |size| {
1966 const n = limit.minInt64(size - file_reader.pos);
1967 file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
1917 pub fn init(buffer: []u8) Discarding {
1918 return .{
1919 .count = 0,
1920 .writer = .{
1921 .vtable = &.{
1922 .drain = Discarding.drain,
1923 .sendFile = Discarding.sendFile,
1924 },
1925 .buffer = buffer,
1926 },
1927 };
1928 }
1929
1930 pub fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
1931 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
1932 const slice = data[0 .. data.len - 1];
1933 const pattern = data[slice.len..];
1934 var written: usize = pattern.len * splat;
1935 for (slice) |bytes| written += bytes.len;
1936 d.count += w.end + written;
19681937 w.end = 0;
1969 return n;
1970 } else |_| {
1971 // Error is observable on `file_reader` instance, and it is better to
1972 // treat the file as a pipe.
1973 return error.Unimplemented;
1938 return written;
19741939 }
1975}
1940
1941 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
1942 if (File.Handle == void) return error.Unimplemented;
1943 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
1944 d.count += w.end;
1945 w.end = 0;
1946 if (file_reader.getSize()) |size| {
1947 const n = limit.minInt64(size - file_reader.pos);
1948 file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
1949 w.end = 0;
1950 d.count += n;
1951 return n;
1952 } else |_| {
1953 // Error is observable on `file_reader` instance, and it is better to
1954 // treat the file as a pipe.
1955 return error.Unimplemented;
1956 }
1957 }
1958};
19761959
19771960/// Removes the first `n` bytes from `buffer` by shifting buffer contents,
19781961/// returning how many bytes are left after consuming the entire buffer, or
......@@ -2219,9 +2202,7 @@ pub const Allocating = struct {
22192202 }
22202203
22212204 pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void {
2222 const shrink_by = a.writer.end - new_len;
22232205 a.writer.end = new_len;
2224 a.writer.count -= shrink_by;
22252206 }
22262207
22272208 pub fn clearRetainingCapacity(a: *Allocating) void {
lib/std/zig/ErrorBundle.zig+10-2
......@@ -195,22 +195,30 @@ fn renderErrorMessageToWriter(
195195) (Writer.Error || std.posix.UnexpectedError)!void {
196196 const ttyconf = options.ttyconf;
197197 const err_msg = eb.getErrorMessage(err_msg_index);
198 const prefix_start = w.count;
199198 if (err_msg.src_loc != .none) {
200199 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
200 var prefix: std.io.Writer.Discarding = .init(&.{});
201201 try w.splatByteAll(' ', indent);
202 prefix.count += indent;
202203 try ttyconf.setColor(w, .bold);
203204 try w.print("{s}:{d}:{d}: ", .{
204205 eb.nullTerminatedString(src.data.src_path),
205206 src.data.line + 1,
206207 src.data.column + 1,
207208 });
209 try prefix.writer.print("{s}:{d}:{d}: ", .{
210 eb.nullTerminatedString(src.data.src_path),
211 src.data.line + 1,
212 src.data.column + 1,
213 });
208214 try ttyconf.setColor(w, color);
209215 try w.writeAll(kind);
216 prefix.count += kind.len;
210217 try w.writeAll(": ");
218 prefix.count += 2;
211219 // This is the length of the part before the error message:
212220 // e.g. "file.zig:4:5: error: "
213 const prefix_len = w.count - prefix_start;
221 const prefix_len: usize = @intCast(prefix.count);
214222 try ttyconf.setColor(w, .reset);
215223 try ttyconf.setColor(w, .bold);
216224 if (err_msg.count == 1) {
src/arch/x86_64/Encoding.zig+3-3
......@@ -1016,8 +1016,8 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
10161016 // By using a buffer with maximum length of encoded instruction, we can use
10171017 // the `end` field of the Writer for the count.
10181018 var buf: [16]u8 = undefined;
1019 var trash = std.io.Writer.discarding(&buf);
1020 inst.encode(&trash, .{
1019 var trash: std.io.Writer.Discarding = .init(&buf);
1020 inst.encode(&trash.writer, .{
10211021 .allow_frame_locs = true,
10221022 .allow_symbols = true,
10231023 }) catch {
......@@ -1027,7 +1027,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
10271027 // (`estimateInstructionLength`) has the wrong function signature.
10281028 @panic("unexpected failure to encode");
10291029 };
1030 return @intCast(trash.end);
1030 return trash.writer.end;
10311031}
10321032
10331033const mnemonic_to_encodings_map = init: {
src/link/Elf/Atom.zig+2-2
......@@ -1390,8 +1390,8 @@ const x86_64 = struct {
13901390 // TODO: hack to force imm32s in the assembler
13911391 .{ .imm = .s(-129) },
13921392 }, t) catch return false;
1393 var trash = std.io.Writer.discarding(&.{});
1394 inst.encode(&trash, .{}) catch return false;
1393 var trash: std.io.Writer.Discarding = .init(&.{});
1394 inst.encode(&trash.writer, .{}) catch return false;
13951395 return true;
13961396 },
13971397 else => return false,