@@ -2,12 +2,12 @@ const std = @import("std");
22const Self = @This ();
33
44// TODO: use any-writer when it exists
5- const PointerFormat = * const fn (* anyopaque , options : std.fmt.FormatOptions , std.io.FixedBufferStream (u8 )) anyerror ! void ;
5+ const PointerFormat = * const fn (* Self , options : std.fmt.FormatOptions , * std.io.FixedBufferStream ([] u8 )) anyerror ! void ;
66
77type : []const u8 ,
88size : usize = 0 ,
9- ptr : * anyopaque ,
10- ptrFormat : ? PointerFormat = null ,
9+ ptr : ? * anyopaque ,
10+ ptrFormat : PointerFormat ,
1111
1212/// Initializes a runtime anytype from a comptime anytype.
1313pub inline fn init (value : anytype ) Self {
@@ -17,20 +17,24 @@ pub inline fn init(value: anytype) Self {
1717/// Explicitly initialize a runtime anytype to fit the type T.
1818pub inline fn initExplicit (comptime T : type , value : T ) Self {
1919 var size : usize = @sizeOf (T );
20- var ptrFormat : ? PointerFormat = null ;
21- const ptr : * anyopaque = switch (@typeInfo (T )) {
20+ var ptrFormat : PointerFormat = (struct {
21+ fn func (t : * Self , options : std.fmt.FormatOptions , stream : * std .io .FixedBufferStream ([]u8 )) ! void {
22+ const self : T = try t .cast (T );
23+ return std .fmt .formatType (self , "" , options , stream .writer (), 3 );
24+ }
25+ }).func ;
26+
27+ const ptr : ? * anyopaque = switch (@typeInfo (T )) {
2228 .Int , .ComptimeInt = > @ptrFromInt (value ),
23- .Float , .ComptimeFloat = > @ptrFromInt (@as (usize , @bitCast (@as (f128 , @floatCast (value ))))),
29+ .Float , .ComptimeFloat = > @ptrFromInt (@as (u64 , @bitCast (@as (f64 , @floatCast (value ))))),
2430 .Enum = > @ptrFromInt (@intFromEnum (value )),
2531 .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- }
32+ ptrFormat = (struct {
33+ fn func (t : * Self , options : std.fmt.FormatOptions , stream : * std .io .FixedBufferStream ([]u8 )) ! void {
34+ const self : T = try t .cast (T );
35+ return if (@hasDecl (T , "format" )) self .format ("" , options , stream .writer ()) else std .fmt .formatType (self , "" , options , stream .writer (), 3 );
36+ }
37+ }).func ;
3438 break :blk @constCast (& value );
3539 },
3640 .Pointer = > | p | switch (@typeInfo (p .child )) {
@@ -61,13 +65,13 @@ pub inline fn cast(self: Self, comptime T: type) error{InvalidCast}!T {
6165/// Casts a type without any of the safety
6266pub inline fn unsafeCast (self : Self , comptime T : type ) T {
6367 return switch (@typeInfo (T )) {
64- .Int , .ComptimeInt = > @intFromPtr (self .ptr ),
65- .Float , .ComptimeFloat = > @floatCast (@as (f128 , @bitCast (self .ptr ))),
68+ .Int , .ComptimeInt = > @intCast ( @ intFromPtr (self .ptr ) ),
69+ .Float , .ComptimeFloat = > @floatCast (@as (f64 , @bitCast (@intFromPtr ( self .ptr ) ))),
6670 .Enum = > | e | @enumFromInt (@as (e .tag_type , @ptrFromInt (self .ptr ))),
67- .Struct , .Union = > @ptrCast (@alignCast (self .ptr )) ,
71+ .Struct , .Union = > @as ( * T , @ ptrCast (@alignCast (self .ptr .? ))) .* ,
6872 .Pointer = > | p | switch (@typeInfo (p .child )) {
6973 .Array = > blk : {
70- break :blk @as ([* ]p .child , @ptrCast (@alignCast (self .ptr )))[0.. self .len (T )];
74+ break :blk @as ([* ]p .child , @ptrCast (@alignCast (self .ptr .? )))[0.. self .len (T )];
7175 },
7276 else = > | f | @compileError ("Unsupported pointer type: " ++ @tagName (f )),
7377 },
@@ -93,8 +97,8 @@ pub inline fn format(self: Self, comptime fmt: []const u8, options: std.fmt.Form
9397 const trunc_msg = "(msg truncated)" ;
9498 var buf : [size + trunc_msg .len ]u8 = undefined ;
9599
96- const stream = std .io .fixedBufferStream (buf [0.. size ]);
97- ptrFormat (self . ptr , options , stream ) catch | err | switch (err ) {
100+ var stream = std .io .fixedBufferStream (buf [0.. size ]);
101+ ptrFormat (self , options , & stream ) catch | err | switch (err ) {
98102 error .NoSpaceLeft = > blk : {
99103 @memcpy (buf [size .. ], trunc_msg );
100104 break :blk & buf ;
@@ -115,12 +119,43 @@ pub inline fn format(self: Self, comptime fmt: []const u8, options: std.fmt.Form
115119}
116120
117121test "Casting integers and floats" {
122+ @setEvalBranchQuota (100_000 );
118123 comptime var i : usize = 0 ;
119124 inline while (i < std .math .maxInt (u8 )) : (i += 1 ) {
120125 try std .testing .expectEqual (i , try initExplicit (u8 , i ).cast (u8 ));
121126 }
122127
123- try std .testing .expectEqual (123.456 , try initExplicit (f32 , 123.456 ).cast (f32 ));
128+ try std .testing .expectEqual (@as (f32 , 123.456 ), try initExplicit (f32 , 123.456 ).cast (f32 ));
129+ }
130+
131+ test "Casting structs and unions" {
132+ const UnionType = union (enum ) {
133+ a : u32 ,
134+ b : [2 ]u16 ,
135+ c : [4 ]u8 ,
136+ };
137+
138+ const StructType = struct {
139+ a : u32 ,
140+ b : u16 ,
141+ c : u8 ,
142+ };
143+
144+ try std .testing .expectEqualDeep (UnionType {
145+ .a = 4096 ,
146+ }, try initExplicit (UnionType , UnionType {
147+ .a = 4096 ,
148+ }).cast (UnionType ));
149+
150+ try std .testing .expectEqualDeep (StructType {
151+ .a = 4096 ,
152+ .b = 1024 ,
153+ .c = 255 ,
154+ }, try initExplicit (StructType , StructType {
155+ .a = 4096 ,
156+ .b = 1024 ,
157+ .c = 255 ,
158+ }).cast (StructType ));
124159}
125160
126161test "Invalid casts" {
0 commit comments