2024-10-18 15:05:08 +00:00
|
|
|
const std = @import("std");
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn slice(any_slice: anytype) FmtSlice(std.meta.Elem(@TypeOf(any_slice))) {
|
|
|
|
|
return .{ .slice = any_slice };
|
|
|
|
|
}
|
2024-10-18 15:05:08 +00:00
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
fn FmtSlice(T: type) type {
|
|
|
|
|
return struct {
|
|
|
|
|
slice: []const T,
|
|
|
|
|
|
|
|
|
|
pub fn formatNumber(f: @This(), writer: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
|
|
|
|
|
return switch (@typeInfo(T)) {
|
|
|
|
|
.comptime_float, .float => try formatFloatSlice(f.slice, n, writer),
|
|
|
|
|
.comptime_int, .int => try formatIntSlice(f.slice, n, writer),
|
|
|
|
|
.bool => try formatBoolSlice(f.slice, n, writer),
|
|
|
|
|
.@"struct" => if (@hasField(T, "re") and @hasField(T, "im")) {
|
|
|
|
|
try formatComplexSlice(f.slice, n, writer);
|
|
|
|
|
} else if (@hasDecl(T, "toF32")) {
|
|
|
|
|
try formatFloatSlice(f.slice, n, writer);
|
|
|
|
|
} else {
|
|
|
|
|
try formatSliceAny(f.slice, n, writer);
|
|
|
|
|
},
|
|
|
|
|
else => @compileError("FmtSlice doesn't support type: " ++ @typeName(T)),
|
|
|
|
|
};
|
|
|
|
|
}
|
2024-10-18 15:05:08 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatFloat(value: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
2024-10-18 15:05:08 +00:00
|
|
|
const x = switch (@typeInfo(@TypeOf(value))) {
|
|
|
|
|
.@"struct" => value.toF32(),
|
|
|
|
|
.float => value,
|
2025-08-20 10:27:54 +00:00
|
|
|
else => @compileError("formatFloat expects a float, got: " ++ @typeName(@TypeOf(value))),
|
2024-10-18 15:05:08 +00:00
|
|
|
};
|
2025-08-20 10:27:54 +00:00
|
|
|
return writer.printFloat(x, spec);
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatInt(value: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
2024-10-18 15:05:08 +00:00
|
|
|
switch (@typeInfo(@TypeOf(value))) {
|
|
|
|
|
.int => {},
|
2025-08-20 10:27:54 +00:00
|
|
|
else => @compileError("formatInt expects an int, got: " ++ @typeName(@TypeOf(value))),
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
2025-08-20 10:27:54 +00:00
|
|
|
return writer.printInt(value, spec.mode.base().?, spec.case, .{ .alignment = spec.alignment, .fill = spec.fill });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn formatComplex(value: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
try writer.writeAll(".{.re=");
|
|
|
|
|
try writer.printFloat(value.re, spec);
|
|
|
|
|
try writer.writeAll(", .im=");
|
|
|
|
|
try writer.printFloat(value.im, spec);
|
|
|
|
|
try writer.writeAll("}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn formatBool(value: bool, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
try writer.alignBufferOptions(if (value) "1" else "0", .{ .alignment = spec.alignment, .fill = spec.fill });
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatAny(value: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
2024-10-18 15:05:08 +00:00
|
|
|
var buf: [48]u8 = undefined;
|
2025-08-20 10:27:54 +00:00
|
|
|
const T = @TypeOf(value);
|
|
|
|
|
const fmt = if (@hasDecl(T, "formatNumber")) "{d}" else "{f}";
|
|
|
|
|
|
|
|
|
|
const s = std.fmt.bufPrint(&buf, fmt, .{value}) catch blk: {
|
2024-10-18 15:05:08 +00:00
|
|
|
buf[45..].* = "...".*;
|
|
|
|
|
break :blk buf[0..];
|
|
|
|
|
};
|
2025-08-20 10:27:54 +00:00
|
|
|
return try writer.alignBufferOptions(s, .{ .alignment = spec.alignment, .fill = spec.fill });
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatSliceCustom(fmt_func: anytype, values: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
// use the format "width" for the number of columns instead of individual width.
|
|
|
|
|
const num_cols: usize = spec.width orelse 12;
|
|
|
|
|
var my_options = spec;
|
|
|
|
|
my_options.width = null;
|
2024-10-18 15:05:08 +00:00
|
|
|
const n: usize = values.len;
|
2025-08-20 10:27:54 +00:00
|
|
|
|
2024-10-18 15:05:08 +00:00
|
|
|
_ = try writer.write("{");
|
|
|
|
|
if (n <= num_cols) {
|
|
|
|
|
for (values, 0..) |v, i| {
|
|
|
|
|
// Force inlining so that the switch and the buffer can be done once.
|
2025-08-20 10:27:54 +00:00
|
|
|
try @call(.always_inline, fmt_func, .{ v, my_options, writer });
|
2024-10-18 15:05:08 +00:00
|
|
|
if (i < n - 1) _ = try writer.write(",");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const half = @divFloor(num_cols, 2);
|
|
|
|
|
for (values[0..half]) |v| {
|
2025-08-20 10:27:54 +00:00
|
|
|
try @call(.always_inline, fmt_func, .{ v, my_options, writer });
|
2024-10-18 15:05:08 +00:00
|
|
|
_ = try writer.write(",");
|
|
|
|
|
}
|
|
|
|
|
_ = try writer.write(" ..., ");
|
|
|
|
|
for (values[n - half ..], 0..) |v, i| {
|
2025-08-20 10:27:54 +00:00
|
|
|
try @call(.always_inline, fmt_func, .{ v, my_options, writer });
|
2024-10-18 15:05:08 +00:00
|
|
|
if (i < half - 1) _ = try writer.write(",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ = try writer.write("}");
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatSliceAny(values: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
return try formatSliceCustom(formatAny, values, spec, writer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn formatFloatSlice(values: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
return try formatSliceCustom(formatFloat, values, spec, writer);
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatIntSlice(values: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
return try formatSliceCustom(formatInt, values, spec, writer);
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatComplexSlice(values: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
return try formatSliceCustom(formatComplex, values, spec, writer);
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:27:54 +00:00
|
|
|
pub fn formatBoolSlice(values: anytype, spec: std.fmt.Number, writer: *std.Io.Writer) !void {
|
|
|
|
|
return try formatSliceCustom(formatBool, values, spec, writer);
|
2024-10-18 15:05:08 +00:00
|
|
|
}
|