Function printValue [src]
Asserts buffer capacity of at least 2 if value is a union.
Prototype
pub fn printValue( w: *Writer, comptime fmt: []const u8, options: std.fmt.Options, value: anytype, max_depth: usize, ) Error!void
Parameters
w: *Writer
fmt: []const u8
options: std.fmt.Options
max_depth: usize
Possible Errors
See the Writer
implementation for detailed diagnostics.
Source
pub fn printValue(
w: *Writer,
comptime fmt: []const u8,
options: std.fmt.Options,
value: anytype,
max_depth: usize,
) Error!void {
const T = @TypeOf(value);
switch (fmt.len) {
1 => switch (fmt[0]) {
'*' => return w.printAddress(value),
'f' => return value.format(w),
'd' => switch (@typeInfo(T)) {
.float, .comptime_float => return printFloat(w, value, options.toNumber(.decimal, .lower)),
.int, .comptime_int => return printInt(w, value, 10, .lower, options),
.@"struct" => return value.formatNumber(w, options.toNumber(.decimal, .lower)),
.@"enum" => return printInt(w, @intFromEnum(value), 10, .lower, options),
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
'c' => return w.printAsciiChar(value, options),
'u' => return w.printUnicodeCodepoint(value),
'b' => switch (@typeInfo(T)) {
.int, .comptime_int => return printInt(w, value, 2, .lower, options),
.@"enum" => return printInt(w, @intFromEnum(value), 2, .lower, options),
.@"struct" => return value.formatNumber(w, options.toNumber(.binary, .lower)),
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
'o' => switch (@typeInfo(T)) {
.int, .comptime_int => return printInt(w, value, 8, .lower, options),
.@"enum" => return printInt(w, @intFromEnum(value), 8, .lower, options),
.@"struct" => return value.formatNumber(w, options.toNumber(.octal, .lower)),
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
'x' => switch (@typeInfo(T)) {
.float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
.int, .comptime_int => return printInt(w, value, 16, .lower, options),
.@"enum" => return printInt(w, @intFromEnum(value), 16, .lower, options),
.@"struct" => return value.formatNumber(w, options.toNumber(.hex, .lower)),
.pointer => |info| switch (info.size) {
.one, .slice => {
const slice: []const u8 = value;
optionsForbidden(options);
return printHex(w, slice, .lower);
},
.many, .c => {
const slice: [:0]const u8 = std.mem.span(value);
optionsForbidden(options);
return printHex(w, slice, .lower);
},
},
.array => {
const slice: []const u8 = &value;
optionsForbidden(options);
return printHex(w, slice, .lower);
},
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
'X' => switch (@typeInfo(T)) {
.float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .upper)),
.int, .comptime_int => return printInt(w, value, 16, .upper, options),
.@"enum" => return printInt(w, @intFromEnum(value), 16, .upper, options),
.@"struct" => return value.formatNumber(w, options.toNumber(.hex, .upper)),
.pointer => |info| switch (info.size) {
.one, .slice => {
const slice: []const u8 = value;
optionsForbidden(options);
return printHex(w, slice, .upper);
},
.many, .c => {
const slice: [:0]const u8 = std.mem.span(value);
optionsForbidden(options);
return printHex(w, slice, .upper);
},
},
.array => {
const slice: []const u8 = &value;
optionsForbidden(options);
return printHex(w, slice, .upper);
},
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
's' => switch (@typeInfo(T)) {
.pointer => |info| switch (info.size) {
.one, .slice => {
const slice: []const u8 = value;
return w.alignBufferOptions(slice, options);
},
.many, .c => {
const slice: [:0]const u8 = std.mem.span(value);
return w.alignBufferOptions(slice, options);
},
},
.array => {
const slice: []const u8 = &value;
return w.alignBufferOptions(slice, options);
},
else => invalidFmtError(fmt, value),
},
'B' => switch (@typeInfo(T)) {
.int, .comptime_int => return w.printByteSize(value, .decimal, options),
.@"struct" => return value.formatByteSize(w, .decimal),
else => invalidFmtError(fmt, value),
},
'D' => switch (@typeInfo(T)) {
.int, .comptime_int => return w.printDuration(value, options),
.@"struct" => return value.formatDuration(w),
else => invalidFmtError(fmt, value),
},
'e' => switch (@typeInfo(T)) {
.float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .lower)),
.@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .lower)),
else => invalidFmtError(fmt, value),
},
'E' => switch (@typeInfo(T)) {
.float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .upper)),
.@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .upper)),
else => invalidFmtError(fmt, value),
},
't' => switch (@typeInfo(T)) {
.error_set => return w.alignBufferOptions(@errorName(value), options),
.@"enum", .@"union" => return w.alignBufferOptions(@tagName(value), options),
else => invalidFmtError(fmt, value),
},
else => {},
},
2 => switch (fmt[0]) {
'B' => switch (fmt[1]) {
'i' => switch (@typeInfo(T)) {
.int, .comptime_int => return w.printByteSize(value, .binary, options),
.@"struct" => return value.formatByteSize(w, .binary),
else => invalidFmtError(fmt, value),
},
else => {},
},
else => {},
},
3 => if (fmt[0] == 'b' and fmt[1] == '6' and fmt[2] == '4') switch (@typeInfo(T)) {
.pointer => |info| switch (info.size) {
.one, .slice => {
const slice: []const u8 = value;
optionsForbidden(options);
return w.printBase64(slice);
},
.many, .c => {
const slice: [:0]const u8 = std.mem.span(value);
optionsForbidden(options);
return w.printBase64(slice);
},
},
.array => {
const slice: []const u8 = &value;
optionsForbidden(options);
return w.printBase64(slice);
},
else => invalidFmtError(fmt, value),
},
else => {},
}
const is_any = comptime std.mem.eql(u8, fmt, ANY);
if (!is_any and std.meta.hasMethod(T, "format") and fmt.len == 0) {
// after 0.15.0 is tagged, delete this compile error and its condition
@compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it");
}
switch (@typeInfo(T)) {
.float, .comptime_float => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
return printFloat(w, value, options.toNumber(.decimal, .lower));
},
.int, .comptime_int => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
return printInt(w, value, 10, .lower, options);
},
.bool => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
const string: []const u8 = if (value) "true" else "false";
return w.alignBufferOptions(string, options);
},
.void => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
return w.alignBufferOptions("void", options);
},
.optional => {
const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '?')
stripOptionalOrErrorUnionSpec(fmt)
else if (is_any)
ANY
else
@compileError("cannot print optional without a specifier (i.e. {?} or {any})");
if (value) |payload| {
return w.printValue(remaining_fmt, options, payload, max_depth);
} else {
return w.alignBufferOptions("null", options);
}
},
.error_union => {
const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '!')
stripOptionalOrErrorUnionSpec(fmt)
else if (is_any)
ANY
else
@compileError("cannot print error union without a specifier (i.e. {!} or {any})");
if (value) |payload| {
return w.printValue(remaining_fmt, options, payload, max_depth);
} else |err| {
return w.printValue("", options, err, max_depth);
}
},
.error_set => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
optionsForbidden(options);
return printErrorSet(w, value);
},
.@"enum" => |info| {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
optionsForbidden(options);
if (info.is_exhaustive) {
return printEnumExhaustive(w, value);
} else {
return printEnumNonexhaustive(w, value);
}
},
.@"union" => |info| {
if (!is_any) {
if (fmt.len != 0) invalidFmtError(fmt, value);
return printValue(w, ANY, options, value, max_depth);
}
if (max_depth == 0) {
try w.writeAll(".{ ... }");
return;
}
if (info.tag_type) |UnionTagType| {
try w.writeAll(".{ .");
try w.writeAll(@tagName(@as(UnionTagType, value)));
try w.writeAll(" = ");
inline for (info.fields) |u_field| {
if (value == @field(UnionTagType, u_field.name)) {
try w.printValue(ANY, options, @field(value, u_field.name), max_depth - 1);
}
}
try w.writeAll(" }");
} else switch (info.layout) {
.auto => {
return w.writeAll(".{ ... }");
},
.@"extern", .@"packed" => {
if (info.fields.len == 0) return w.writeAll(".{}");
try w.writeAll(".{ ");
inline for (info.fields, 1..) |field, i| {
try w.writeByte('.');
try w.writeAll(field.name);
try w.writeAll(" = ");
try w.printValue(ANY, options, @field(value, field.name), max_depth - 1);
try w.writeAll(if (i < info.fields.len) ", " else " }");
}
},
}
},
.@"struct" => |info| {
if (!is_any) {
if (fmt.len != 0) invalidFmtError(fmt, value);
return printValue(w, ANY, options, value, max_depth);
}
if (info.is_tuple) {
// Skip the type and field names when formatting tuples.
if (max_depth == 0) {
try w.writeAll(".{ ... }");
return;
}
try w.writeAll(".{");
inline for (info.fields, 0..) |f, i| {
if (i == 0) {
try w.writeAll(" ");
} else {
try w.writeAll(", ");
}
try w.printValue(ANY, options, @field(value, f.name), max_depth - 1);
}
try w.writeAll(" }");
return;
}
if (max_depth == 0) {
try w.writeAll(".{ ... }");
return;
}
try w.writeAll(".{");
inline for (info.fields, 0..) |f, i| {
if (i == 0) {
try w.writeAll(" .");
} else {
try w.writeAll(", .");
}
try w.writeAll(f.name);
try w.writeAll(" = ");
try w.printValue(ANY, options, @field(value, f.name), max_depth - 1);
}
try w.writeAll(" }");
},
.pointer => |ptr_info| switch (ptr_info.size) {
.one => switch (@typeInfo(ptr_info.child)) {
.array => |array_info| return w.printValue(fmt, options, @as([]const array_info.child, value), max_depth),
.@"enum", .@"union", .@"struct" => return w.printValue(fmt, options, value.*, max_depth),
else => {
var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" };
try w.writeVecAll(&buffers);
try w.printInt(@intFromPtr(value), 16, .lower, options);
return;
},
},
.many, .c => {
if (!is_any) @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
optionsForbidden(options);
try w.printAddress(value);
},
.slice => {
if (!is_any)
@compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})");
if (max_depth == 0) return w.writeAll("{ ... }");
try w.writeAll("{ ");
for (value, 0..) |elem, i| {
try w.printValue(fmt, options, elem, max_depth - 1);
if (i != value.len - 1) {
try w.writeAll(", ");
}
}
try w.writeAll(" }");
},
},
.array => {
if (!is_any) @compileError("cannot format array without a specifier (i.e. {s} or {any})");
if (max_depth == 0) return w.writeAll("{ ... }");
try w.writeAll("{ ");
for (value, 0..) |elem, i| {
try w.printValue(fmt, options, elem, max_depth - 1);
if (i < value.len - 1) {
try w.writeAll(", ");
}
}
try w.writeAll(" }");
},
.vector => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
return printVector(w, fmt, options, value, max_depth);
},
.@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
.type => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
return w.alignBufferOptions(@typeName(value), options);
},
.enum_literal => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
optionsForbidden(options);
var vecs: [2][]const u8 = .{ ".", @tagName(value) };
return w.writeVecAll(&vecs);
},
.null => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
return w.alignBufferOptions("null", options);
},
else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
}
}