array list tests passing again

This commit is contained in:
Andrew Kelley 2025-04-10 22:22:56 -07:00
parent 646454beb5
commit 60854795b8
7 changed files with 187 additions and 234 deletions

View File

@ -40,17 +40,16 @@ pub const Component = union(enum) {
};
}
pub fn format(component: Component, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!usize {
var n: usize = 0;
pub fn format(component: Component, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void {
if (fmt.len == 0) {
n += try bw.printCount("std.Uri.Component{{ .{s} = \"{}\" }}", .{
try bw.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
@tagName(component),
std.zig.fmtEscapes(switch (component) {
.raw, .percent_encoded => |string| string,
}),
});
} else if (comptime std.mem.eql(u8, fmt, "raw")) switch (component) {
.raw => |raw| n += try bw.writeAllCount(raw),
.raw => |raw| try bw.writeAll(raw),
.percent_encoded => |percent_encoded| {
var start: usize = 0;
var index: usize = 0;
@ -59,55 +58,51 @@ pub const Component = union(enum) {
if (percent_encoded.len - index < 2) continue;
const percent_encoded_char =
std.fmt.parseInt(u8, percent_encoded[index..][0..2], 16) catch continue;
n += try bw.printCount("{s}{c}", .{
try bw.print("{s}{c}", .{
percent_encoded[start..percent],
percent_encoded_char,
});
start = percent + 3;
index = percent + 3;
}
n += try bw.writeAllCount(percent_encoded[start..]);
try bw.writeAll(percent_encoded[start..]);
},
} else if (comptime std.mem.eql(u8, fmt, "%")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isUnreserved),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isUnreserved),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt, "user")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isUserChar),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isUserChar),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt, "password")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isPasswordChar),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isPasswordChar),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt, "host")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isHostChar),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isHostChar),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt, "path")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isPathChar),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isPathChar),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt, "query")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isQueryChar),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isQueryChar),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt, "fragment")) switch (component) {
.raw => |raw| n += try percentEncode(bw, raw, isFragmentChar),
.percent_encoded => |percent_encoded| n += try bw.writeAllCount(percent_encoded),
.raw => |raw| try percentEncode(bw, raw, isFragmentChar),
.percent_encoded => |percent_encoded| try bw.writeAll(percent_encoded),
} else @compileError("invalid format string '" ++ fmt ++ "'");
return n;
}
pub fn percentEncode(
bw: *std.io.BufferedWriter,
raw: []const u8,
comptime isValidChar: fn (u8) bool,
) anyerror!usize {
var n: usize = 0;
) anyerror!void {
var start: usize = 0;
for (raw, 0..) |char, index| {
if (isValidChar(char)) continue;
n += try bw.printCount("{s}%{X:0>2}", .{ raw[start..index], char });
try bw.print("{s}%{X:0>2}", .{ raw[start..index], char });
start = index + 1;
}
n += try bw.writeAllCount(raw[start..]);
return n;
try bw.writeAll(raw[start..]);
}
};

View File

@ -34,8 +34,8 @@ pub const StackTrace = struct {
index: usize,
instruction_addresses: []usize,
pub fn format(st: StackTrace, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!usize {
comptime std.debug.assert(fmt.len == 0);
pub fn format(st: StackTrace, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void {
comptime if (fmt.len != 0) unreachable;
// TODO: re-evaluate whether to use format() methods at all.
// Until then, avoid an error when using DebugAllocator with WebAssembly
@ -43,17 +43,15 @@ pub const StackTrace = struct {
if (builtin.os.tag == .freestanding) return 0;
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
return bw.printCount("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{
return bw.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{
@errorName(err),
});
};
const tty_config = std.io.tty.detectConfig(.stderr());
var n: usize = 0;
n += try bw.writeAllCount("\n");
n += std.debug.writeStackTrace(st, bw, debug_info, tty_config) catch |err| {
try bw.writeAll("\n");
std.debug.writeStackTrace(st, bw, debug_info, tty_config) catch |err| {
try bw.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
};
return n;
}
};

View File

@ -733,28 +733,26 @@ pub fn writeStackTrace(
writer: *std.io.BufferedWriter,
debug_info: *SelfInfo,
tty_config: io.tty.Config,
) !usize {
) !void {
if (builtin.strip_debug_info) return error.MissingDebugInfo;
var frame_index: usize = 0;
var frames_left: usize = @min(stack_trace.index, stack_trace.instruction_addresses.len);
var n: usize = 0;
while (frames_left != 0) : ({
frames_left -= 1;
frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
}) {
const return_address = stack_trace.instruction_addresses[frame_index];
n += try printSourceAtAddress(debug_info, writer, return_address - 1, tty_config);
try printSourceAtAddress(debug_info, writer, return_address - 1, tty_config);
}
if (stack_trace.index > stack_trace.instruction_addresses.len) {
const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;
n += tty_config.setColor(writer, .bold) catch {};
n += try writer.printCount("({d} additional stack frames skipped...)\n", .{dropped_frames});
n += tty_config.setColor(writer, .reset) catch {};
tty_config.setColor(writer, .bold) catch {};
try writer.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
tty_config.setColor(writer, .reset) catch {};
}
return n;
}
pub const UnwindError = if (have_ucontext)
@ -1102,12 +1100,7 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, addre
try tty_config.setColor(writer, .reset);
}
pub fn printSourceAtAddress(
debug_info: *SelfInfo,
writer: *std.io.BufferedWriter,
address: usize,
tty_config: io.tty.Config,
) !void {
pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void {
const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config),
else => return err,

View File

@ -91,7 +91,7 @@ pub const Options = struct {
/// 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(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype) anyerror!usize {
pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype) anyerror!void {
const ArgsType = @TypeOf(args);
const args_type_info = @typeInfo(ArgsType);
if (args_type_info != .@"struct") {
@ -107,7 +107,6 @@ pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytyp
comptime var arg_state: ArgState = .{ .args_len = fields_info.len };
comptime var i = 0;
comptime var literal: []const u8 = "";
var bytes_written: usize = 0;
inline while (true) {
const start_index = i;
@ -137,7 +136,7 @@ pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytyp
// Write out the literal
if (literal.len != 0) {
bytes_written += try bw.writeAllCount(literal);
try bw.writeAll(literal);
literal = "";
}
@ -197,7 +196,7 @@ pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytyp
const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse
@compileError("too few arguments");
bytes_written += try bw.printValue(
try bw.printValue(
placeholder.specifier_arg,
.{
.fill = placeholder.fill,
@ -218,8 +217,6 @@ pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytyp
else => @compileError(comptimePrint("{d}", .{missing_count}) ++ " unused arguments in '" ++ fmt ++ "'"),
}
}
return bytes_written;
}
fn cacheString(str: anytype) []const u8 {
@ -858,7 +855,8 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
pub fn count(comptime fmt: []const u8, args: anytype) usize {
var buffer: [std.atomic.cache_line]u8 = undefined;
var bw = std.io.Writer.null.buffered(&buffer);
return bw.printCount(fmt, args) catch unreachable;
bw.print(fmt, args) catch unreachable;
return bw.bytes_written;
}
pub const AllocPrintError = error{OutOfMemory};

View File

@ -19,6 +19,10 @@ buffer: std.ArrayListUnmanaged(u8),
/// equals number of bytes provided. This property is exploited by
/// `std.io.AllocatingWriter` for example.
unbuffered_writer: Writer,
/// Tracks total number of bytes written to this `BufferedWriter`. This value
/// only increases. In the case of fixed mode, this value always equals
/// `buffer.items.len`.
bytes_written: usize = 0,
/// Number of slices to store on the stack, when trying to send as many byte
/// vectors through the underlying write calls as possible.
@ -106,6 +110,7 @@ pub fn advance(bw: *BufferedWriter, n: usize) void {
const list = &bw.buffer;
list.items.len += n;
assert(list.items.len <= list.capacity);
bw.bytes_written += n;
}
/// The `data` parameter is mutable because this function needs to mutate the
@ -114,8 +119,9 @@ pub fn writevAll(bw: *BufferedWriter, data: [][]const u8) anyerror!void {
var i: usize = 0;
while (true) {
var n = try passthru_writeSplat(bw, data[i..], 1);
while (n >= data[i].len) {
n -= data[i].len;
const len = data[i].len;
while (n >= len) {
n -= len;
i += 1;
if (i >= data.len) return;
}
@ -147,7 +153,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
end = new_end;
continue;
}
if (end == 0) return bw.unbuffered_writer.writeSplat(data, splat);
if (end == 0) return track(&bw.bytes_written, try bw.unbuffered_writer.writeSplat(data, splat));
buffers[0] = buffer[0..end];
const remaining_data = data[i..];
const remaining_buffers = buffers[1..];
@ -163,10 +169,10 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
}
const n = try bw.unbuffered_writer.writeSplat(send_buffers, 1);
if (n < end) {
@ -174,10 +180,10 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
}
const pattern = data[data.len - 1];
@ -187,7 +193,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
// It was added in the loop above; undo it here.
end -= pattern.len;
list.items.len = end;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
const remaining_splat = splat - 1;
@ -195,7 +201,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
switch (pattern.len) {
0 => {
list.items.len = end;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
},
1 => {
const new_end = end + remaining_splat;
@ -203,7 +209,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
@branchHint(.likely);
@memset(buffer[end..new_end], pattern[0]);
list.items.len = new_end;
return new_end - start_end;
return track(&bw.bytes_written, new_end - start_end);
}
buffers[0] = buffer[0..end];
buffers[1] = pattern;
@ -213,10 +219,10 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
},
else => {
const new_end = end + pattern.len * remaining_splat;
@ -226,7 +232,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
@memcpy(buffer[end..][0..pattern.len], pattern);
}
list.items.len = new_end;
return new_end - start_end;
return track(&bw.bytes_written, new_end - start_end);
}
buffers[0] = buffer[0..end];
buffers[1] = pattern;
@ -236,14 +242,19 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
},
}
}
fn track(bytes_written: *usize, n: usize) usize {
bytes_written.* += n;
return n;
}
/// When this function is called it means the buffer got full, so it's time
/// to return an error. However, we still need to make sure all of the
/// available buffer has been filled.
@ -256,6 +267,7 @@ fn fixed_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize
const len = @min(bytes.len, dest.len);
@memcpy(dest[0..len], bytes[0..len]);
list.items.len += len;
bw.bytes_written = list.items.len;
}
const pattern = data[data.len - 1];
const dest = list.unusedCapacitySlice();
@ -265,6 +277,7 @@ fn fixed_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize
else => for (0..splat - 1) |i| @memcpy(dest[i * pattern.len ..][0..pattern.len], pattern),
}
list.items.len = list.capacity;
bw.bytes_written = list.items.len;
return error.NoSpaceLeft;
}
@ -284,17 +297,11 @@ pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize {
return 0;
}
list.items.len = 0;
return n - end;
return track(&bw.bytes_written, n - end);
}
@memcpy(buffer[end..new_end], bytes);
list.items.len = new_end;
return bytes.len;
}
/// Convenience function that calls `writeAll` and then returns `bytes.len`.
pub fn writeAllCount(bw: *BufferedWriter, bytes: []const u8) anyerror!usize {
try writeAll(bw, bytes);
return bytes.len;
return track(&bw.bytes_written, bytes.len);
}
/// Calls `write` as many times as necessary such that all of `bytes` are
@ -305,17 +312,7 @@ pub fn writeAll(bw: *BufferedWriter, bytes: []const u8) anyerror!void {
}
pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) anyerror!void {
_ = try std.fmt.format(bw, format, args);
}
pub fn printCount(bw: *BufferedWriter, comptime format: []const u8, args: anytype) anyerror!usize {
return std.fmt.format(bw, format, args);
}
/// Returns 0 or 1 indicating how many bytes were written.
pub fn writeByteCount(bw: *BufferedWriter, byte: u8) anyerror!usize {
try writeByte(bw, byte);
return 1;
try std.fmt.format(bw, format, args);
}
pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void {
@ -325,6 +322,7 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void {
@branchHint(.likely);
buffer.ptr[buffer.len] = byte;
list.items.len = buffer.len + 1;
bw.bytes_written += 1;
return;
}
var buffers: [2][]const u8 = .{ buffer, &.{byte} };
@ -333,7 +331,9 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void {
if (n == 0) {
@branchHint(.unlikely);
continue;
} else if (n >= buffer.len) {
}
bw.bytes_written += 1;
if (n >= buffer.len) {
@branchHint(.likely);
if (n > buffer.len) {
@branchHint(.likely);
@ -353,12 +353,6 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void {
}
}
/// Convenience function that calls `splatByteAll` and then returns `n`.
pub fn splatByteAllCount(bw: *BufferedWriter, byte: u8, n: usize) anyerror!usize {
try splatByteAll(bw, byte, n);
return n;
}
/// Writes the same byte many times, performing the underlying write call as
/// many times as necessary.
pub fn splatByteAll(bw: *BufferedWriter, byte: u8, n: usize) anyerror!void {
@ -438,7 +432,10 @@ fn passthru_writeFile(
const bw: *BufferedWriter = @alignCast(@ptrCast(context));
const list = &bw.buffer;
const buffer = list.allocatedSlice();
if (buffer.len == 0) return bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len);
if (buffer.len == 0) return track(
&bw.bytes_written,
try bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len),
);
const start_end = list.items.len;
const headers = headers_and_trailers[0..headers_len];
const trailers = headers_and_trailers[headers_len..];
@ -470,10 +467,10 @@ fn passthru_writeFile(
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
}
// Have not made it past the headers yet; must call `writev`.
const n = try bw.unbuffered_writer.writev(buffers[0 .. buffers_len + 1]);
@ -482,10 +479,10 @@ fn passthru_writeFile(
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
}
// All headers written to buffer.
buffers[0] = buffer[0..end];
@ -500,10 +497,10 @@ fn passthru_writeFile(
const remainder = buffer[n..end];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
list.items.len = remainder.len;
return end - start_end;
return track(&bw.bytes_written, end - start_end);
}
list.items.len = 0;
return n - start_end;
return track(&bw.bytes_written, n - start_end);
}
pub const WriteFileOptions = struct {
@ -583,54 +580,51 @@ pub fn alignBuffer(
width: usize,
alignment: std.fmt.Alignment,
fill: u8,
) anyerror!usize {
) anyerror!void {
const padding = if (buffer.len < width) width - buffer.len else 0;
if (padding == 0) {
@branchHint(.likely);
return bw.writeAllCount(buffer);
return bw.writeAll(buffer);
}
var n: usize = 0;
switch (alignment) {
.left => {
n += try bw.writeAllCount(buffer);
n += try bw.splatByteAllCount(fill, padding);
try bw.writeAll(buffer);
try bw.splatByteAll(fill, padding);
},
.center => {
const left_padding = padding / 2;
const right_padding = (padding + 1) / 2;
n += try bw.splatByteAllCount(fill, left_padding);
n += try bw.writeAllCount(buffer);
n += try bw.splatByteAllCount(fill, right_padding);
try bw.splatByteAll(fill, left_padding);
try bw.writeAll(buffer);
try bw.splatByteAll(fill, right_padding);
},
.right => {
n += try bw.splatByteAllCount(fill, padding);
n += try bw.writeAllCount(buffer);
try bw.splatByteAll(fill, padding);
try bw.writeAll(buffer);
},
}
return n;
}
pub fn alignBufferOptions(bw: *BufferedWriter, buffer: []const u8, options: std.fmt.Options) anyerror!usize {
pub fn alignBufferOptions(bw: *BufferedWriter, buffer: []const u8, options: std.fmt.Options) anyerror!void {
return alignBuffer(bw, buffer, options.width orelse buffer.len, options.alignment, options.fill);
}
pub fn printAddress(bw: *BufferedWriter, value: anytype) anyerror!usize {
pub fn printAddress(bw: *BufferedWriter, value: anytype) anyerror!void {
const T = @TypeOf(value);
var n: usize = 0;
switch (@typeInfo(T)) {
.pointer => |info| {
n += try bw.writeAllCount(@typeName(info.child) ++ "@");
try bw.writeAll(@typeName(info.child) ++ "@");
if (info.size == .slice)
n += try printIntOptions(bw, @intFromPtr(value.ptr), 16, .lower, .{})
try printIntOptions(bw, @intFromPtr(value.ptr), 16, .lower, .{})
else
n += try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{});
return n;
try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{});
return;
},
.optional => |info| {
if (@typeInfo(info.child) == .pointer) {
n += try bw.writeAll(@typeName(info.child) ++ "@");
n += try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{});
return n;
try bw.writeAll(@typeName(info.child) ++ "@");
try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{});
return;
}
},
else => {},
@ -645,7 +639,7 @@ pub fn printValue(
options: std.fmt.Options,
value: anytype,
max_depth: usize,
) anyerror!usize {
) anyerror!void {
const T = @TypeOf(value);
const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY))
defaultFormatString(T)
@ -700,104 +694,96 @@ pub fn printValue(
},
.error_set => {
if (actual_fmt.len > 0 and actual_fmt[0] == 's') {
return bw.writeAllCount(@errorName(value));
return bw.writeAll(@errorName(value));
} else if (actual_fmt.len != 0) {
invalidFmtError(fmt, value);
} else {
var n: usize = 0;
n += try bw.writeAllCount("error.");
n += try bw.writeAllCount(@errorName(value));
return n;
try bw.writeAll("error.");
try bw.writeAll(@errorName(value));
}
},
.@"enum" => |enum_info| {
var n: usize = 0;
n += try bw.writeAllCount(@typeName(T));
try bw.writeAll(@typeName(T));
if (enum_info.is_exhaustive) {
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
n += try bw.writeAllCount(".");
n += try bw.writeAllCount(@tagName(value));
return n;
try bw.writeAll(".");
try bw.writeAll(@tagName(value));
return;
}
// Use @tagName only if value is one of known fields
@setEvalBranchQuota(3 * enum_info.fields.len);
inline for (enum_info.fields) |enumField| {
if (@intFromEnum(value) == enumField.value) {
n += try bw.writeAllCount(".");
n += try bw.writeAllCount(@tagName(value));
try bw.writeAll(".");
try bw.writeAll(@tagName(value));
return;
}
}
n += try bw.writeByteCount('(');
n += try printValue(bw, actual_fmt, options, @intFromEnum(value), max_depth);
n += try bw.writeByteCount(')');
return n;
try bw.writeByteCount('(');
try printValue(bw, actual_fmt, options, @intFromEnum(value), max_depth);
try bw.writeByteCount(')');
},
.@"union" => |info| {
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
var n: usize = 0;
n += try bw.writeAllCount(@typeName(T));
try bw.writeAll(@typeName(T));
if (max_depth == 0) {
n += bw.writeAllCount("{ ... }");
return n;
bw.writeAll("{ ... }");
return;
}
if (info.tag_type) |UnionTagType| {
n += try bw.writeAllCount("{ .");
n += try bw.writeAllCount(@tagName(@as(UnionTagType, value)));
n += try bw.writeAllCount(" = ");
try bw.writeAll("{ .");
try bw.writeAll(@tagName(@as(UnionTagType, value)));
try bw.writeAll(" = ");
inline for (info.fields) |u_field| {
if (value == @field(UnionTagType, u_field.name)) {
n += try printValue(bw, ANY, options, @field(value, u_field.name), max_depth - 1);
try printValue(bw, ANY, options, @field(value, u_field.name), max_depth - 1);
}
}
n += try bw.writeAllCount(" }");
try bw.writeAll(" }");
} else {
n += try bw.writeByte('@');
n += try bw.printIntOptions(@intFromPtr(&value), 16, .lower);
try bw.writeByte('@');
try bw.printIntOptions(@intFromPtr(&value), 16, .lower);
}
return n;
},
.@"struct" => |info| {
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
var n: usize = 0;
if (info.is_tuple) {
// Skip the type and field names when formatting tuples.
if (max_depth == 0) {
n += try bw.writeAllCount("{ ... }");
return n;
try bw.writeAll("{ ... }");
return;
}
n += try bw.writeAllCount("{");
try bw.writeAll("{");
inline for (info.fields, 0..) |f, i| {
if (i == 0) {
n += try bw.writeAllCount(" ");
try bw.writeAll(" ");
} else {
n += try bw.writeAllCount(", ");
try bw.writeAll(", ");
}
n += try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1);
try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1);
}
n += try bw.writeAllCount(" }");
return n;
try bw.writeAll(" }");
return;
}
n += try bw.writeAllCount(@typeName(T));
try bw.writeAll(@typeName(T));
if (max_depth == 0) {
n += try bw.writeAllCount("{ ... }");
return n;
try bw.writeAll("{ ... }");
return;
}
n += try bw.writeAllCount("{");
try bw.writeAll("{");
inline for (info.fields, 0..) |f, i| {
if (i == 0) {
n += try bw.writeAllCount(" .");
try bw.writeAll(" .");
} else {
n += try bw.writeAllCount(", .");
try bw.writeAll(", .");
}
n += try bw.writeAllCount(f.name);
n += try bw.writeAllCount(" = ");
n += try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1);
try bw.writeAll(f.name);
try bw.writeAll(" = ");
try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1);
}
n += try bw.writeAllCount(" }");
return n;
try bw.writeAll(" }");
},
.pointer => |ptr_info| switch (ptr_info.size) {
.one => switch (@typeInfo(ptr_info.child)) {
@ -806,10 +792,9 @@ pub fn printValue(
},
else => {
var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" };
var n: usize = 0;
n += try writevAll(bw, &buffers);
n += try printIntOptions(bw, @intFromPtr(value), 16, .lower, options);
return n;
try writevAll(bw, &buffers);
try printIntOptions(bw, @intFromPtr(value), 16, .lower, options);
return;
},
},
.many, .c => {
@ -827,7 +812,7 @@ pub fn printValue(
if (actual_fmt.len == 0)
@compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})");
if (max_depth == 0) {
return bw.writeAllCount("{ ... }");
return bw.writeAll("{ ... }");
}
if (ptr_info.child == u8) switch (actual_fmt.len) {
1 => switch (actual_fmt[0]) {
@ -841,23 +826,21 @@ pub fn printValue(
},
else => {},
};
var n: usize = 0;
n += try bw.writeAllCount("{ ");
try bw.writeAll("{ ");
for (value, 0..) |elem, i| {
n += try printValue(bw, actual_fmt, options, elem, max_depth - 1);
try printValue(bw, actual_fmt, options, elem, max_depth - 1);
if (i != value.len - 1) {
n += try bw.writeAllCount(", ");
try bw.writeAll(", ");
}
}
n += try bw.writeAllCount(" }");
return n;
try bw.writeAll(" }");
},
},
.array => |info| {
if (actual_fmt.len == 0)
@compileError("cannot format array without a specifier (i.e. {s} or {any})");
if (max_depth == 0) {
return bw.writeAllCount("{ ... }");
return bw.writeAll("{ ... }");
}
if (info.child == u8) {
if (actual_fmt[0] == 's') {
@ -868,32 +851,28 @@ pub fn printValue(
return printHex(bw, &value, .upper);
}
}
var n: usize = 0;
n += try bw.writeAllCount("{ ");
try bw.writeAll("{ ");
for (value, 0..) |elem, i| {
n += try printValue(bw, actual_fmt, options, elem, max_depth - 1);
try printValue(bw, actual_fmt, options, elem, max_depth - 1);
if (i < value.len - 1) {
n += try bw.writeAllCount(", ");
try bw.writeAll(", ");
}
}
n += try bw.writeAllCount(" }");
return n;
try bw.writeAll(" }");
},
.vector => |info| {
if (max_depth == 0) {
return bw.writeAllCount("{ ... }");
return bw.writeAll("{ ... }");
}
var n: usize = 0;
n += try bw.writeAllCount("{ ");
try bw.writeAll("{ ");
var i: usize = 0;
while (i < info.len) : (i += 1) {
n += try printValue(bw, actual_fmt, options, value[i], max_depth - 1);
try printValue(bw, actual_fmt, options, value[i], max_depth - 1);
if (i < info.len - 1) {
n += try bw.writeAllCount(", ");
try bw.writeAll(", ");
}
}
n += try bw.writeAllCount(" }");
return n;
try bw.writeAll(" }");
},
.@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
.type => {
@ -918,7 +897,7 @@ pub fn printInt(
comptime fmt: []const u8,
options: std.fmt.Options,
value: anytype,
) anyerror!usize {
) anyerror!void {
const int_value = if (@TypeOf(value) == comptime_int) blk: {
const Int = std.math.IntFittingRange(value, value);
break :blk @as(Int, value);
@ -962,15 +941,15 @@ pub fn printInt(
comptime unreachable;
}
pub fn printAsciiChar(bw: *BufferedWriter, c: u8, options: std.fmt.Options) anyerror!usize {
pub fn printAsciiChar(bw: *BufferedWriter, c: u8, options: std.fmt.Options) anyerror!void {
return alignBufferOptions(bw, @as(*const [1]u8, &c), options);
}
pub fn printAscii(bw: *BufferedWriter, bytes: []const u8, options: std.fmt.Options) anyerror!usize {
pub fn printAscii(bw: *BufferedWriter, bytes: []const u8, options: std.fmt.Options) anyerror!void {
return alignBufferOptions(bw, bytes, options);
}
pub fn printUnicodeCodepoint(bw: *BufferedWriter, c: u21, options: std.fmt.Options) anyerror!usize {
pub fn printUnicodeCodepoint(bw: *BufferedWriter, c: u21, options: std.fmt.Options) anyerror!void {
var buf: [4]u8 = undefined;
const len = try std.unicode.utf8Encode(c, &buf);
return alignBufferOptions(bw, buf[0..len], options);
@ -982,7 +961,7 @@ pub fn printIntOptions(
base: u8,
case: std.fmt.Case,
options: std.fmt.Options,
) anyerror!usize {
) anyerror!void {
assert(base >= 2);
const int_value = if (@TypeOf(value) == comptime_int) blk: {
@ -1049,7 +1028,7 @@ pub fn printFloat(
comptime fmt: []const u8,
options: std.fmt.Options,
value: anytype,
) anyerror!usize {
) anyerror!void {
var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined;
if (fmt.len > 1) invalidFmtError(fmt, value);
@ -1337,7 +1316,7 @@ pub fn printDuration(bw: *BufferedWriter, nanoseconds: anytype, options: std.fmt
return alignBufferOptions(bw, sub_bw.getWritten(), options);
}
pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anyerror!usize {
pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anyerror!void {
const charset = switch (case) {
.upper => "0123456789ABCDEF",
.lower => "0123456789abcdef",
@ -1346,21 +1325,18 @@ pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anye
try writeByte(bw, charset[c >> 4]);
try writeByte(bw, charset[c & 15]);
}
return bytes.len * 2;
}
pub fn printBase64(bw: *BufferedWriter, bytes: []const u8) anyerror!usize {
pub fn printBase64(bw: *BufferedWriter, bytes: []const u8) anyerror!void {
var chunker = std.mem.window(u8, bytes, 3, 3);
var temp: [5]u8 = undefined;
var n: usize = 0;
while (chunker.next()) |chunk| {
n += try bw.writeAllCount(std.base64.standard.Encoder.encode(&temp, chunk));
try bw.writeAll(std.base64.standard.Encoder.encode(&temp, chunk));
}
return n;
}
/// Write a single unsigned integer as unsigned LEB128 to the given writer.
pub fn writeUleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!usize {
pub fn writeUleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!void {
const Arg = @TypeOf(arg);
const Int = switch (Arg) {
comptime_int => std.math.IntFittingRange(arg, arg),
@ -1368,23 +1344,21 @@ pub fn writeUleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!usize {
};
const Value = if (@typeInfo(Int).int.bits < 8) u8 else Int;
var value: Value = arg;
var n: usize = 0;
while (true) {
const byte: u8 = @truncate(value & 0x7f);
value >>= 7;
if (value == 0) {
try bw.writeByte(byte);
return n + 1;
return;
} else {
try bw.writeByte(byte | 0x80);
n += 1;
}
}
}
/// Write a single signed integer as signed LEB128 to the given writer.
pub fn writeIleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!usize {
pub fn writeIleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!void {
const Arg = @TypeOf(arg);
const Int = switch (Arg) {
comptime_int => std.math.IntFittingRange(-@abs(arg), @abs(arg)),
@ -1393,7 +1367,6 @@ pub fn writeIleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!usize {
const Signed = if (@typeInfo(Int).int.bits < 8) i8 else Int;
const Unsigned = std.meta.Int(.unsigned, @typeInfo(Signed).int.bits);
var value: Signed = arg;
var n: usize = 0;
while (true) {
const unsigned: Unsigned = @bitCast(value);
@ -1401,11 +1374,10 @@ pub fn writeIleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!usize {
value >>= 6;
if (value == -1 or value == 0) {
try bw.writeByte(byte & 0x7F);
return n + 1;
return;
} else {
value >>= 1;
try bw.writeByte(byte | 0x80);
n += 1;
}
}
}

View File

@ -190,21 +190,22 @@ fn renderErrorMessageToWriter(
) anyerror!void {
const ttyconf = options.ttyconf;
const err_msg = eb.getErrorMessage(err_msg_index);
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
var prefix_len: usize = 0;
const prefix_start = bw.bytes_written;
if (err_msg.src_loc != .none) {
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
prefix_len += try bw.splatByteAllCount(' ', indent);
try bw.splatByteAll(' ', indent);
try ttyconf.setColor(bw, .bold);
prefix_len += try bw.printCount("{s}:{d}:{d}: ", .{
try bw.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
src.data.column + 1,
});
try ttyconf.setColor(bw, color);
prefix_len += try bw.writeAllCount(kind);
prefix_len += try bw.writeAllCount(": ");
try bw.writeAll(kind);
try bw.writeAll(": ");
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
const prefix_len = bw.bytes_written - prefix_start;
try ttyconf.setColor(bw, .reset);
try ttyconf.setColor(bw, .bold);
if (err_msg.count == 1) {

View File

@ -119,28 +119,24 @@ const Value = extern struct {
}
}
pub fn format(
value: Value,
bw: *std.io.BufferedWriter,
comptime fmt: []const u8,
) anyerror!usize {
pub fn format(value: Value, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void {
comptime assert(fmt.len == 0);
// Work around x86_64 backend limitation.
if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) {
return bw.writeAllCount("(unknown)");
return bw.writeAll("(unknown)");
}
switch (value.td.kind) {
.integer => {
if (value.td.isSigned()) {
return bw.printCount("{d}", .{value.getSignedInteger()});
return bw.print("{d}", .{value.getSignedInteger()});
} else {
return bw.printCount("{d}", .{value.getUnsignedInteger()});
return bw.print("{d}", .{value.getUnsignedInteger()});
}
},
.float => return bw.printCount("{d}", .{value.getFloat()}),
.unknown => return bw.writeAllCount("(unknown)"),
.float => return bw.print("{d}", .{value.getFloat()}),
.unknown => return bw.writeAll("(unknown)"),
}
}
};