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: *Writerfmt: []const u8options: std.fmt.Optionsmax_depth: usize

Possible Errors

WriteFailed

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) ++ "'"), } }