Use writer in std.fmt
This commit is contained in:
committed by
Veikka Tuominen
parent
aa894cea2c
commit
5229f6ec68
350
lib/std/fmt.zig
350
lib/std/fmt.zig
@@ -69,14 +69,14 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
|
||||
///
|
||||
/// If a formatted user type contains a function of the type
|
||||
/// ```
|
||||
/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void
|
||||
/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: var) !void
|
||||
/// ```
|
||||
/// with `?` being the type formatted, this function will be called instead of the default implementation.
|
||||
/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
|
||||
///
|
||||
/// A user type may be a `struct`, `vector`, `union` or `enum` type.
|
||||
pub fn format(
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
comptime fmt: []const u8,
|
||||
args: var,
|
||||
) !void {
|
||||
@@ -136,7 +136,7 @@ pub fn format(
|
||||
.Start => switch (c) {
|
||||
'{' => {
|
||||
if (start_index < i) {
|
||||
try out_stream.writeAll(fmt[start_index..i]);
|
||||
try writer.writeAll(fmt[start_index..i]);
|
||||
}
|
||||
|
||||
start_index = i;
|
||||
@@ -148,7 +148,7 @@ pub fn format(
|
||||
},
|
||||
'}' => {
|
||||
if (start_index < i) {
|
||||
try out_stream.writeAll(fmt[start_index..i]);
|
||||
try writer.writeAll(fmt[start_index..i]);
|
||||
}
|
||||
state = .CloseBrace;
|
||||
},
|
||||
@@ -183,7 +183,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[0..0],
|
||||
options,
|
||||
out_stream,
|
||||
writer,
|
||||
default_max_depth,
|
||||
);
|
||||
|
||||
@@ -214,7 +214,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[specifier_start..i],
|
||||
options,
|
||||
out_stream,
|
||||
writer,
|
||||
default_max_depth,
|
||||
);
|
||||
state = .Start;
|
||||
@@ -259,7 +259,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[specifier_start..specifier_end],
|
||||
options,
|
||||
out_stream,
|
||||
writer,
|
||||
default_max_depth,
|
||||
);
|
||||
state = .Start;
|
||||
@@ -285,7 +285,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[specifier_start..specifier_end],
|
||||
options,
|
||||
out_stream,
|
||||
writer,
|
||||
default_max_depth,
|
||||
);
|
||||
state = .Start;
|
||||
@@ -306,7 +306,7 @@ pub fn format(
|
||||
}
|
||||
}
|
||||
if (start_index < fmt.len) {
|
||||
try out_stream.writeAll(fmt[start_index..]);
|
||||
try writer.writeAll(fmt[start_index..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,140 +314,140 @@ pub fn formatType(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
max_depth: usize,
|
||||
) @TypeOf(out_stream).Error!void {
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (comptime std.mem.eql(u8, fmt, "*")) {
|
||||
try out_stream.writeAll(@typeName(@TypeOf(value).Child));
|
||||
try out_stream.writeAll("@");
|
||||
try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
|
||||
try writer.writeAll(@typeName(@TypeOf(value).Child));
|
||||
try writer.writeAll("@");
|
||||
try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
|
||||
return;
|
||||
}
|
||||
|
||||
const T = @TypeOf(value);
|
||||
if (comptime std.meta.trait.hasFn("format")(T)) {
|
||||
return try value.format(fmt, options, out_stream);
|
||||
return try value.format(fmt, options, writer);
|
||||
}
|
||||
|
||||
switch (@typeInfo(T)) {
|
||||
.ComptimeInt, .Int, .ComptimeFloat, .Float => {
|
||||
return formatValue(value, fmt, options, out_stream);
|
||||
return formatValue(value, fmt, options, writer);
|
||||
},
|
||||
.Void => {
|
||||
return formatBuf("void", options, out_stream);
|
||||
return formatBuf("void", options, writer);
|
||||
},
|
||||
.Bool => {
|
||||
return formatBuf(if (value) "true" else "false", options, out_stream);
|
||||
return formatBuf(if (value) "true" else "false", options, writer);
|
||||
},
|
||||
.Optional => {
|
||||
if (value) |payload| {
|
||||
return formatType(payload, fmt, options, out_stream, max_depth);
|
||||
return formatType(payload, fmt, options, writer, max_depth);
|
||||
} else {
|
||||
return formatBuf("null", options, out_stream);
|
||||
return formatBuf("null", options, writer);
|
||||
}
|
||||
},
|
||||
.ErrorUnion => {
|
||||
if (value) |payload| {
|
||||
return formatType(payload, fmt, options, out_stream, max_depth);
|
||||
return formatType(payload, fmt, options, writer, max_depth);
|
||||
} else |err| {
|
||||
return formatType(err, fmt, options, out_stream, max_depth);
|
||||
return formatType(err, fmt, options, writer, max_depth);
|
||||
}
|
||||
},
|
||||
.ErrorSet => {
|
||||
try out_stream.writeAll("error.");
|
||||
return out_stream.writeAll(@errorName(value));
|
||||
try writer.writeAll("error.");
|
||||
return writer.writeAll(@errorName(value));
|
||||
},
|
||||
.Enum => |enumInfo| {
|
||||
try out_stream.writeAll(@typeName(T));
|
||||
try writer.writeAll(@typeName(T));
|
||||
if (enumInfo.is_exhaustive) {
|
||||
try out_stream.writeAll(".");
|
||||
try out_stream.writeAll(@tagName(value));
|
||||
try writer.writeAll(".");
|
||||
try writer.writeAll(@tagName(value));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use @tagName only if value is one of known fields
|
||||
inline for (enumInfo.fields) |enumField| {
|
||||
if (@enumToInt(value) == enumField.value) {
|
||||
try out_stream.writeAll(".");
|
||||
try out_stream.writeAll(@tagName(value));
|
||||
try writer.writeAll(".");
|
||||
try writer.writeAll(@tagName(value));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try out_stream.writeAll("(");
|
||||
try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
|
||||
try out_stream.writeAll(")");
|
||||
try writer.writeAll("(");
|
||||
try formatType(@enumToInt(value), fmt, options, writer, max_depth);
|
||||
try writer.writeAll(")");
|
||||
},
|
||||
.Union => {
|
||||
try out_stream.writeAll(@typeName(T));
|
||||
try writer.writeAll(@typeName(T));
|
||||
if (max_depth == 0) {
|
||||
return out_stream.writeAll("{ ... }");
|
||||
return writer.writeAll("{ ... }");
|
||||
}
|
||||
const info = @typeInfo(T).Union;
|
||||
if (info.tag_type) |UnionTagType| {
|
||||
try out_stream.writeAll("{ .");
|
||||
try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
|
||||
try out_stream.writeAll(" = ");
|
||||
try writer.writeAll("{ .");
|
||||
try writer.writeAll(@tagName(@as(UnionTagType, value)));
|
||||
try writer.writeAll(" = ");
|
||||
inline for (info.fields) |u_field| {
|
||||
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
|
||||
try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);
|
||||
try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1);
|
||||
}
|
||||
}
|
||||
try out_stream.writeAll(" }");
|
||||
try writer.writeAll(" }");
|
||||
} else {
|
||||
try format(out_stream, "@{x}", .{@ptrToInt(&value)});
|
||||
try format(writer, "@{x}", .{@ptrToInt(&value)});
|
||||
}
|
||||
},
|
||||
.Struct => |StructT| {
|
||||
try out_stream.writeAll(@typeName(T));
|
||||
try writer.writeAll(@typeName(T));
|
||||
if (max_depth == 0) {
|
||||
return out_stream.writeAll("{ ... }");
|
||||
return writer.writeAll("{ ... }");
|
||||
}
|
||||
try out_stream.writeAll("{");
|
||||
try writer.writeAll("{");
|
||||
inline for (StructT.fields) |f, i| {
|
||||
if (i == 0) {
|
||||
try out_stream.writeAll(" .");
|
||||
try writer.writeAll(" .");
|
||||
} else {
|
||||
try out_stream.writeAll(", .");
|
||||
try writer.writeAll(", .");
|
||||
}
|
||||
try out_stream.writeAll(f.name);
|
||||
try out_stream.writeAll(" = ");
|
||||
try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
|
||||
try writer.writeAll(f.name);
|
||||
try writer.writeAll(" = ");
|
||||
try formatType(@field(value, f.name), fmt, options, writer, max_depth - 1);
|
||||
}
|
||||
try out_stream.writeAll(" }");
|
||||
try writer.writeAll(" }");
|
||||
},
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.One => switch (@typeInfo(ptr_info.child)) {
|
||||
.Array => |info| {
|
||||
if (info.child == u8) {
|
||||
return formatText(value, fmt, options, out_stream);
|
||||
return formatText(value, fmt, options, writer);
|
||||
}
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
},
|
||||
.Enum, .Union, .Struct => {
|
||||
return formatType(value.*, fmt, options, out_stream, max_depth);
|
||||
return formatType(value.*, fmt, options, writer, max_depth);
|
||||
},
|
||||
else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
|
||||
else => return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
|
||||
},
|
||||
.Many, .C => {
|
||||
if (ptr_info.sentinel) |sentinel| {
|
||||
return formatType(mem.span(value), fmt, options, out_stream, max_depth);
|
||||
return formatType(mem.span(value), fmt, options, writer, max_depth);
|
||||
}
|
||||
if (ptr_info.child == u8) {
|
||||
if (fmt.len > 0 and fmt[0] == 's') {
|
||||
return formatText(mem.span(value), fmt, options, out_stream);
|
||||
return formatText(mem.span(value), fmt, options, writer);
|
||||
}
|
||||
}
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
},
|
||||
.Slice => {
|
||||
if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
|
||||
return formatText(value, fmt, options, out_stream);
|
||||
return formatText(value, fmt, options, writer);
|
||||
}
|
||||
if (ptr_info.child == u8) {
|
||||
return formatText(value, fmt, options, out_stream);
|
||||
return formatText(value, fmt, options, writer);
|
||||
}
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
|
||||
return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
|
||||
},
|
||||
},
|
||||
.Array => |info| {
|
||||
@@ -462,27 +462,27 @@ pub fn formatType(
|
||||
.sentinel = null,
|
||||
},
|
||||
});
|
||||
return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
|
||||
return formatType(@as(Slice, &value), fmt, options, writer, max_depth);
|
||||
},
|
||||
.Vector => {
|
||||
const len = @typeInfo(T).Vector.len;
|
||||
try out_stream.writeAll("{ ");
|
||||
try writer.writeAll("{ ");
|
||||
var i: usize = 0;
|
||||
while (i < len) : (i += 1) {
|
||||
try formatValue(value[i], fmt, options, out_stream);
|
||||
try formatValue(value[i], fmt, options, writer);
|
||||
if (i < len - 1) {
|
||||
try out_stream.writeAll(", ");
|
||||
try writer.writeAll(", ");
|
||||
}
|
||||
}
|
||||
try out_stream.writeAll(" }");
|
||||
try writer.writeAll(" }");
|
||||
},
|
||||
.Fn => {
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
|
||||
return format(writer, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
|
||||
},
|
||||
.Type => return out_stream.writeAll(@typeName(T)),
|
||||
.Type => return writer.writeAll(@typeName(T)),
|
||||
.EnumLiteral => {
|
||||
const buffer = [_]u8{'.'} ++ @tagName(value);
|
||||
return formatType(buffer, fmt, options, out_stream, max_depth);
|
||||
return formatType(buffer, fmt, options, writer, max_depth);
|
||||
},
|
||||
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
@@ -492,19 +492,19 @@ fn formatValue(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
if (comptime std.mem.eql(u8, fmt, "B")) {
|
||||
return formatBytes(value, options, 1000, out_stream);
|
||||
return formatBytes(value, options, 1000, writer);
|
||||
} else if (comptime std.mem.eql(u8, fmt, "Bi")) {
|
||||
return formatBytes(value, options, 1024, out_stream);
|
||||
return formatBytes(value, options, 1024, writer);
|
||||
}
|
||||
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.Float, .ComptimeFloat => return formatFloatValue(value, fmt, options, out_stream),
|
||||
.Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
|
||||
.Bool => return formatBuf(if (value) "true" else "false", options, out_stream),
|
||||
.Float, .ComptimeFloat => return formatFloatValue(value, fmt, options, writer),
|
||||
.Int, .ComptimeInt => return formatIntValue(value, fmt, options, writer),
|
||||
.Bool => return formatBuf(if (value) "true" else "false", options, writer),
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
@@ -513,7 +513,7 @@ pub fn formatIntValue(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
comptime var radix = 10;
|
||||
comptime var uppercase = false;
|
||||
@@ -529,7 +529,7 @@ pub fn formatIntValue(
|
||||
uppercase = false;
|
||||
} else if (comptime std.mem.eql(u8, fmt, "c")) {
|
||||
if (@TypeOf(int_value).bit_count <= 8) {
|
||||
return formatAsciiChar(@as(u8, int_value), options, out_stream);
|
||||
return formatAsciiChar(@as(u8, int_value), options, writer);
|
||||
} else {
|
||||
@compileError("Cannot print integer that is larger than 8 bits as a ascii");
|
||||
}
|
||||
@@ -546,19 +546,19 @@ pub fn formatIntValue(
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
|
||||
return formatInt(int_value, radix, uppercase, options, out_stream);
|
||||
return formatInt(int_value, radix, uppercase, options, writer);
|
||||
}
|
||||
|
||||
fn formatFloatValue(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
|
||||
return formatFloatScientific(value, options, out_stream);
|
||||
return formatFloatScientific(value, options, writer);
|
||||
} else if (comptime std.mem.eql(u8, fmt, "d")) {
|
||||
return formatFloatDecimal(value, options, out_stream);
|
||||
return formatFloatDecimal(value, options, writer);
|
||||
} else {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
@@ -568,13 +568,13 @@ pub fn formatText(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
if (comptime std.mem.eql(u8, fmt, "s") or (fmt.len == 0)) {
|
||||
return formatBuf(bytes, options, out_stream);
|
||||
return formatBuf(bytes, options, writer);
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
|
||||
for (bytes) |c| {
|
||||
try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);
|
||||
try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
@@ -585,38 +585,38 @@ pub fn formatText(
|
||||
pub fn formatAsciiChar(
|
||||
c: u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
return out_stream.writeAll(@as(*const [1]u8, &c));
|
||||
return writer.writeAll(@as(*const [1]u8, &c));
|
||||
}
|
||||
|
||||
pub fn formatBuf(
|
||||
buf: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
const width = options.width orelse buf.len;
|
||||
var padding = if (width > buf.len) (width - buf.len) else 0;
|
||||
const pad_byte = [1]u8{options.fill};
|
||||
switch (options.alignment) {
|
||||
.Left => {
|
||||
try out_stream.writeAll(buf);
|
||||
try writer.writeAll(buf);
|
||||
while (padding > 0) : (padding -= 1) {
|
||||
try out_stream.writeAll(&pad_byte);
|
||||
try writer.writeAll(&pad_byte);
|
||||
}
|
||||
},
|
||||
.Center => {
|
||||
const padl = padding / 2;
|
||||
var i: usize = 0;
|
||||
while (i < padl) : (i += 1) try out_stream.writeAll(&pad_byte);
|
||||
try out_stream.writeAll(buf);
|
||||
while (i < padding) : (i += 1) try out_stream.writeAll(&pad_byte);
|
||||
while (i < padl) : (i += 1) try writer.writeAll(&pad_byte);
|
||||
try writer.writeAll(buf);
|
||||
while (i < padding) : (i += 1) try writer.writeAll(&pad_byte);
|
||||
},
|
||||
.Right => {
|
||||
while (padding > 0) : (padding -= 1) {
|
||||
try out_stream.writeAll(&pad_byte);
|
||||
try writer.writeAll(&pad_byte);
|
||||
}
|
||||
try out_stream.writeAll(buf);
|
||||
try writer.writeAll(buf);
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -627,38 +627,38 @@ pub fn formatBuf(
|
||||
pub fn formatFloatScientific(
|
||||
value: var,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
var x = @floatCast(f64, value);
|
||||
|
||||
// Errol doesn't handle these special cases.
|
||||
if (math.signbit(x)) {
|
||||
try out_stream.writeAll("-");
|
||||
try writer.writeAll("-");
|
||||
x = -x;
|
||||
}
|
||||
|
||||
if (math.isNan(x)) {
|
||||
return out_stream.writeAll("nan");
|
||||
return writer.writeAll("nan");
|
||||
}
|
||||
if (math.isPositiveInf(x)) {
|
||||
return out_stream.writeAll("inf");
|
||||
return writer.writeAll("inf");
|
||||
}
|
||||
if (x == 0.0) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
|
||||
if (options.precision) |precision| {
|
||||
if (precision != 0) {
|
||||
try out_stream.writeAll(".");
|
||||
try writer.writeAll(".");
|
||||
var i: usize = 0;
|
||||
while (i < precision) : (i += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try out_stream.writeAll(".0");
|
||||
try writer.writeAll(".0");
|
||||
}
|
||||
|
||||
try out_stream.writeAll("e+00");
|
||||
try writer.writeAll("e+00");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -668,50 +668,50 @@ pub fn formatFloatScientific(
|
||||
if (options.precision) |precision| {
|
||||
errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
|
||||
|
||||
try out_stream.writeAll(float_decimal.digits[0..1]);
|
||||
try writer.writeAll(float_decimal.digits[0..1]);
|
||||
|
||||
// {e0} case prints no `.`
|
||||
if (precision != 0) {
|
||||
try out_stream.writeAll(".");
|
||||
try writer.writeAll(".");
|
||||
|
||||
var printed: usize = 0;
|
||||
if (float_decimal.digits.len > 1) {
|
||||
const num_digits = math.min(float_decimal.digits.len, precision + 1);
|
||||
try out_stream.writeAll(float_decimal.digits[1..num_digits]);
|
||||
try writer.writeAll(float_decimal.digits[1..num_digits]);
|
||||
printed += num_digits - 1;
|
||||
}
|
||||
|
||||
while (printed < precision) : (printed += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try out_stream.writeAll(float_decimal.digits[0..1]);
|
||||
try out_stream.writeAll(".");
|
||||
try writer.writeAll(float_decimal.digits[0..1]);
|
||||
try writer.writeAll(".");
|
||||
if (float_decimal.digits.len > 1) {
|
||||
const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
|
||||
|
||||
try out_stream.writeAll(float_decimal.digits[1..num_digits]);
|
||||
try writer.writeAll(float_decimal.digits[1..num_digits]);
|
||||
} else {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
}
|
||||
|
||||
try out_stream.writeAll("e");
|
||||
try writer.writeAll("e");
|
||||
const exp = float_decimal.exp - 1;
|
||||
|
||||
if (exp >= 0) {
|
||||
try out_stream.writeAll("+");
|
||||
try writer.writeAll("+");
|
||||
if (exp > -10 and exp < 10) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
|
||||
try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, writer);
|
||||
} else {
|
||||
try out_stream.writeAll("-");
|
||||
try writer.writeAll("-");
|
||||
if (exp > -10 and exp < 10) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
|
||||
try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,34 +720,34 @@ pub fn formatFloatScientific(
|
||||
pub fn formatFloatDecimal(
|
||||
value: var,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
var x = @as(f64, value);
|
||||
|
||||
// Errol doesn't handle these special cases.
|
||||
if (math.signbit(x)) {
|
||||
try out_stream.writeAll("-");
|
||||
try writer.writeAll("-");
|
||||
x = -x;
|
||||
}
|
||||
|
||||
if (math.isNan(x)) {
|
||||
return out_stream.writeAll("nan");
|
||||
return writer.writeAll("nan");
|
||||
}
|
||||
if (math.isPositiveInf(x)) {
|
||||
return out_stream.writeAll("inf");
|
||||
return writer.writeAll("inf");
|
||||
}
|
||||
if (x == 0.0) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
|
||||
if (options.precision) |precision| {
|
||||
if (precision != 0) {
|
||||
try out_stream.writeAll(".");
|
||||
try writer.writeAll(".");
|
||||
var i: usize = 0;
|
||||
while (i < precision) : (i += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
} else {
|
||||
try out_stream.writeAll(".0");
|
||||
try writer.writeAll(".0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,14 +769,14 @@ pub fn formatFloatDecimal(
|
||||
|
||||
if (num_digits_whole > 0) {
|
||||
// We may have to zero pad, for instance 1e4 requires zero padding.
|
||||
try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
try writer.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
|
||||
var i = num_digits_whole_no_pad;
|
||||
while (i < num_digits_whole) : (i += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
} else {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
|
||||
// {.0} special case doesn't want a trailing '.'
|
||||
@@ -784,7 +784,7 @@ pub fn formatFloatDecimal(
|
||||
return;
|
||||
}
|
||||
|
||||
try out_stream.writeAll(".");
|
||||
try writer.writeAll(".");
|
||||
|
||||
// Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
|
||||
var printed: usize = 0;
|
||||
@@ -796,7 +796,7 @@ pub fn formatFloatDecimal(
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < zeros_to_print) : (i += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
@@ -808,14 +808,14 @@ pub fn formatFloatDecimal(
|
||||
// Remaining fractional portion, zero-padding if insufficient.
|
||||
assert(precision >= printed);
|
||||
if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
|
||||
try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
|
||||
try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
|
||||
return;
|
||||
} else {
|
||||
try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
printed += float_decimal.digits.len - num_digits_whole_no_pad;
|
||||
|
||||
while (printed < precision) : (printed += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -827,14 +827,14 @@ pub fn formatFloatDecimal(
|
||||
|
||||
if (num_digits_whole > 0) {
|
||||
// We may have to zero pad, for instance 1e4 requires zero padding.
|
||||
try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
try writer.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
|
||||
var i = num_digits_whole_no_pad;
|
||||
while (i < num_digits_whole) : (i += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
} else {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
|
||||
// Omit `.` if no fractional portion
|
||||
@@ -842,7 +842,7 @@ pub fn formatFloatDecimal(
|
||||
return;
|
||||
}
|
||||
|
||||
try out_stream.writeAll(".");
|
||||
try writer.writeAll(".");
|
||||
|
||||
// Zero-fill until we reach significant digits or run out of precision.
|
||||
if (float_decimal.exp < 0) {
|
||||
@@ -850,11 +850,11 @@ pub fn formatFloatDecimal(
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < zero_digit_count) : (i += 1) {
|
||||
try out_stream.writeAll("0");
|
||||
try writer.writeAll("0");
|
||||
}
|
||||
}
|
||||
|
||||
try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,10 +862,10 @@ pub fn formatBytes(
|
||||
value: var,
|
||||
options: FormatOptions,
|
||||
comptime radix: usize,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
if (value == 0) {
|
||||
return out_stream.writeAll("0B");
|
||||
return writer.writeAll("0B");
|
||||
}
|
||||
|
||||
const is_float = comptime std.meta.trait.is(.Float)(@TypeOf(value));
|
||||
@@ -885,10 +885,10 @@ pub fn formatBytes(
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
try formatFloatDecimal(new_value, options, out_stream);
|
||||
try formatFloatDecimal(new_value, options, writer);
|
||||
|
||||
if (suffix == ' ') {
|
||||
return out_stream.writeAll("B");
|
||||
return writer.writeAll("B");
|
||||
}
|
||||
|
||||
const buf = switch (radix) {
|
||||
@@ -896,7 +896,7 @@ pub fn formatBytes(
|
||||
1024 => &[_]u8{ suffix, 'i', 'B' },
|
||||
else => unreachable,
|
||||
};
|
||||
return out_stream.writeAll(buf);
|
||||
return writer.writeAll(buf);
|
||||
}
|
||||
|
||||
pub fn formatInt(
|
||||
@@ -904,7 +904,7 @@ pub fn formatInt(
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
const int_value = if (@TypeOf(value) == comptime_int) blk: {
|
||||
const Int = math.IntFittingRange(value, value);
|
||||
@@ -913,9 +913,9 @@ pub fn formatInt(
|
||||
value;
|
||||
|
||||
if (@TypeOf(int_value).is_signed) {
|
||||
return formatIntSigned(int_value, base, uppercase, options, out_stream);
|
||||
return formatIntSigned(int_value, base, uppercase, options, writer);
|
||||
} else {
|
||||
return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
|
||||
return formatIntUnsigned(int_value, base, uppercase, options, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,7 +924,7 @@ fn formatIntSigned(
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
const new_options = FormatOptions{
|
||||
.width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
|
||||
@@ -934,15 +934,15 @@ fn formatIntSigned(
|
||||
const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
|
||||
const Uint = std.meta.Int(false, bit_count);
|
||||
if (value < 0) {
|
||||
try out_stream.writeAll("-");
|
||||
try writer.writeAll("-");
|
||||
const new_value = math.absCast(value);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
|
||||
} else if (options.width == null or options.width.? == 0) {
|
||||
return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);
|
||||
return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, writer);
|
||||
} else {
|
||||
try out_stream.writeAll("+");
|
||||
try writer.writeAll("+");
|
||||
const new_value = @intCast(Uint, value);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -951,7 +951,7 @@ fn formatIntUnsigned(
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
assert(base >= 2);
|
||||
var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
|
||||
@@ -976,22 +976,22 @@ fn formatIntUnsigned(
|
||||
const zero_byte: u8 = options.fill;
|
||||
var leftover_padding = padding - index;
|
||||
while (true) {
|
||||
try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
|
||||
try writer.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
|
||||
leftover_padding -= 1;
|
||||
if (leftover_padding == 0) break;
|
||||
}
|
||||
mem.set(u8, buf[0..index], options.fill);
|
||||
return out_stream.writeAll(&buf);
|
||||
return writer.writeAll(&buf);
|
||||
} else {
|
||||
const padded_buf = buf[index - padding ..];
|
||||
mem.set(u8, padded_buf[0..padding], options.fill);
|
||||
return out_stream.writeAll(padded_buf);
|
||||
return writer.writeAll(padded_buf);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
|
||||
var fbs = std.io.fixedBufferStream(out_buf);
|
||||
formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;
|
||||
formatInt(value, base, uppercase, options, fbs.writer()) catch unreachable;
|
||||
return fbs.pos;
|
||||
}
|
||||
|
||||
@@ -1098,15 +1098,15 @@ pub const BufPrintError = error{
|
||||
};
|
||||
pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
|
||||
var fbs = std.io.fixedBufferStream(buf);
|
||||
try format(fbs.outStream(), fmt, args);
|
||||
try format(fbs.writer(), fmt, args);
|
||||
return fbs.getWritten();
|
||||
}
|
||||
|
||||
// Count the characters needed for format. Useful for preallocating memory
|
||||
pub fn count(comptime fmt: []const u8, args: var) u64 {
|
||||
var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
|
||||
format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
|
||||
return counting_stream.bytes_written;
|
||||
var counting_writer = std.io.countingWriter(std.io.null_writer);
|
||||
format(counting_writer.writer(), fmt, args) catch |err| switch (err) {};
|
||||
return counting_writer.bytes_written;
|
||||
}
|
||||
|
||||
pub const AllocPrintError = error{OutOfMemory};
|
||||
@@ -1215,15 +1215,15 @@ test "buffer" {
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf1);
|
||||
try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);
|
||||
try formatType(1234, "", FormatOptions{}, fbs.writer(), default_max_depth);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
|
||||
|
||||
fbs.reset();
|
||||
try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
|
||||
try formatType('a', "c", FormatOptions{}, fbs.writer(), default_max_depth);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
|
||||
|
||||
fbs.reset();
|
||||
try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
|
||||
try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), default_max_depth);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
|
||||
}
|
||||
}
|
||||
@@ -1413,12 +1413,12 @@ test "custom" {
|
||||
self: SelfType,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
|
||||
return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
} else if (comptime std.mem.eql(u8, fmt, "d")) {
|
||||
return std.fmt.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
|
||||
return std.fmt.format(writer, "{d:.3}x{d:.3}", .{ self.x, self.y });
|
||||
} else {
|
||||
@compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||
}
|
||||
@@ -1604,7 +1604,7 @@ test "formatIntValue with comptime_int" {
|
||||
|
||||
var buf: [20]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
|
||||
try formatIntValue(value, "", FormatOptions{}, fbs.writer());
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
|
||||
}
|
||||
|
||||
@@ -1613,7 +1613,7 @@ test "formatFloatValue with comptime_float" {
|
||||
|
||||
var buf: [20]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
try formatFloatValue(value, "", FormatOptions{}, fbs.outStream());
|
||||
try formatFloatValue(value, "", FormatOptions{}, fbs.writer());
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "1.0e+00"));
|
||||
|
||||
try testFmt("1.0e+00", "{}", .{value});
|
||||
@@ -1630,10 +1630,10 @@ test "formatType max_depth" {
|
||||
self: SelfType,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
out_stream: var,
|
||||
writer: var,
|
||||
) !void {
|
||||
if (fmt.len == 0) {
|
||||
return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
} else {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
@@ -1669,19 +1669,19 @@ test "formatType max_depth" {
|
||||
|
||||
var buf: [1000]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);
|
||||
try formatType(inst, "", FormatOptions{}, fbs.writer(), 0);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
|
||||
|
||||
fbs.reset();
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);
|
||||
try formatType(inst, "", FormatOptions{}, fbs.writer(), 1);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
|
||||
fbs.reset();
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);
|
||||
try formatType(inst, "", FormatOptions{}, fbs.writer(), 2);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
|
||||
fbs.reset();
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);
|
||||
try formatType(inst, "", FormatOptions{}, fbs.writer(), 3);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user