Commit bc2cf0c173
Changed files (8)
lib
src
arch
x86_64
link
Elf
lib/std/http/Client.zig
@@ -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);
lib/std/io/Reader.zig
@@ -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;
lib/std/io/Writer.zig
@@ -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 {
- const slice = data[0 .. data.len - 1];
- const pattern = data[slice.len..];
- var written: usize = pattern.len * splat;
- for (slice) |bytes| written += bytes.len;
- w.end = 0;
- return written;
-}
+pub const Discarding = struct {
+ count: u64,
+ writer: Writer,
-pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
- if (File.Handle == void) return error.Unimplemented;
- 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;
+ 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 n;
- } else |_| {
- // Error is observable on `file_reader` instance, and it is better to
- // treat the file as a pipe.
- return error.Unimplemented;
+ return written;
}
-}
+
+ 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 {
lib/std/zig/ErrorBundle.zig
@@ -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) {
lib/std/debug.zig
@@ -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 {
lib/std/fmt.zig
@@ -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 {
src/arch/x86_64/Encoding.zig
@@ -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: {
src/link/Elf/Atom.zig
@@ -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,