Skip to content

Commit 142cb24

Browse files
feat(anytype): add format
1 parent f9244f5 commit 142cb24

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

any+/anytype.zig

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
const std = @import("std");
22
const Self = @This();
33

4+
// TODO: use any-writer when it exists
5+
const PointerFormat = *const fn (*anyopaque, options: std.fmt.FormatOptions, std.io.FixedBufferStream(u8)) anyerror!void;
6+
47
type: []const u8,
58
size: usize = 0,
69
ptr: *anyopaque,
10+
ptrFormat: ?PointerFormat = null,
711

812
/// Initializes a runtime anytype from a comptime anytype.
913
pub inline fn init(value: anytype) Self {
@@ -13,11 +17,22 @@ pub inline fn init(value: anytype) Self {
1317
/// Explicitly initialize a runtime anytype to fit the type T.
1418
pub inline fn initExplicit(comptime T: type, value: T) Self {
1519
var size: usize = @sizeOf(T);
20+
var ptrFormat: ?PointerFormat = null;
1621
const ptr: *anyopaque = switch (@typeInfo(T)) {
1722
.Int, .ComptimeInt => @ptrFromInt(value),
1823
.Float, .ComptimeFloat => @ptrFromInt(@as(usize, @bitCast(@as(f128, @floatCast(value))))),
1924
.Enum => @ptrFromInt(@intFromEnum(value)),
20-
.Struct, .Union => @constCast(&value),
25+
.Struct, .Union => blk: {
26+
if (@hasDecl(T, "format")) {
27+
ptrFormat = (struct {
28+
fn func(selfPointer: *anyopaque, options: std.fmt.FormatOptions, stream: std.io.FixedBufferStream(u8)) !void {
29+
const self: *T = @ptrCast(@alignCast(selfPointer));
30+
return self.format("", options, stream.writer());
31+
}
32+
}).func;
33+
}
34+
break :blk @constCast(&value);
35+
},
2136
.Pointer => |p| switch (@typeInfo(p.child)) {
2237
.Array => blk: {
2338
size = value.len * @sizeOf(p.child);
@@ -32,6 +47,7 @@ pub inline fn initExplicit(comptime T: type, value: T) Self {
3247
.type = @typeName(T),
3348
.size = size,
3449
.ptr = ptr,
50+
.ptrFormat = ptrFormat,
3551
};
3652
}
3753

@@ -70,6 +86,34 @@ pub inline fn len(self: Self, comptime T: type) usize {
7086
return @divExact(self.size, size);
7187
}
7288

89+
pub inline fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
90+
if (self.ptrFormat) |ptrFormat| {
91+
const size = comptime if (std.mem.indexOf(u8, fmt, "%")) |sizeStart| std.fmt.parseInt(comptime_int, fmt[sizeStart..]) else 0x1000;
92+
93+
const trunc_msg = "(msg truncated)";
94+
var buf: [size + trunc_msg.len]u8 = undefined;
95+
96+
const stream = std.io.fixedBufferStream(buf[0..size]);
97+
ptrFormat(self.ptr, options, stream) catch |err| switch (err) {
98+
error.NoSpaceLeft => blk: {
99+
@memcpy(buf[size..], trunc_msg);
100+
break :blk &buf;
101+
},
102+
else => return err,
103+
};
104+
105+
try writer.writeAll(buf);
106+
} else {
107+
try writer.writeAll(@typeName(Self));
108+
try writer.print("{{ .size = {}, .len = {}, .type = \"{s}\", .ptr = {*} }}", .{
109+
self.size,
110+
self.len(),
111+
self.type,
112+
self.ptr,
113+
});
114+
}
115+
}
116+
73117
test "Casting integers and floats" {
74118
comptime var i: usize = 0;
75119
inline while (i < std.math.maxInt(u8)) : (i += 1) {

0 commit comments

Comments
 (0)