11const std = @import ("std" );
22const 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+
47type : []const u8 ,
58size : usize = 0 ,
69ptr : * anyopaque ,
10+ ptrFormat : ? PointerFormat = null ,
711
812/// Initializes a runtime anytype from a comptime anytype.
913pub 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.
1418pub 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+
73117test "Casting integers and floats" {
74118 comptime var i : usize = 0 ;
75119 inline while (i < std .math .maxInt (u8 )) : (i += 1 ) {
0 commit comments