@@ -5,10 +5,12 @@ type: []const u8,
55size : usize = 0 ,
66ptr : * anyopaque ,
77
8+ /// Initializes a runtime anytype from a comptime anytype.
89pub inline fn init (value : anytype ) Self {
910 return initExplicit (@TypeOf (value ), value );
1011}
1112
13+ /// Explicitly initialize a runtime anytype to fit the type T.
1214pub inline fn initExplicit (comptime T : type , value : T ) Self {
1315 var size : usize = @sizeOf (T );
1416 const ptr : * anyopaque = switch (@typeInfo (T )) {
@@ -33,25 +35,32 @@ pub inline fn initExplicit(comptime T: type, value: T) Self {
3335 };
3436}
3537
38+ /// Safely casts from the anytype to the real type.
39+ /// This returns an error if the cast cannot be made safely.
3640pub inline fn cast (self : Self , comptime T : type ) error {InvalidCast }! T {
3741 if (! std .mem .eql (u8 , self .type , @typeName (T ))) return error .InvalidCast ;
42+ return self .unsafeCast (T );
43+ }
3844
45+ /// Casts a type without any of the safety
46+ pub inline fn unsafeCast (self : Self , comptime T : type ) T {
3947 return switch (@typeInfo (T )) {
4048 .Int , .ComptimeInt = > @intFromPtr (self .ptr ),
4149 .Float , .ComptimeFloat = > @floatCast (@as (f128 , @bitCast (self .ptr ))),
4250 .Enum = > | e | @enumFromInt (@as (e .tag_type , @ptrFromInt (self .ptr ))),
4351 .Struct , .Union = > @ptrCast (@alignCast (self .ptr )),
4452 .Pointer = > | p | switch (@typeInfo (p .child )) {
4553 .Array = > blk : {
46- const length = @divExact (self .size , @sizeOf (p .child ));
47- break :blk @as ([* ]p .child , @ptrCast (@alignCast (self .ptr )))[0.. length ];
54+ break :blk @as ([* ]p .child , @ptrCast (@alignCast (self .ptr )))[0.. self .len (T )];
4855 },
4956 else = > | f | @compileError ("Unsupported pointer type: " ++ @tagName (f )),
5057 },
5158 else = > | f | @compileError ("Unsupported type: " ++ @tagName (f )),
5259 };
5360}
5461
62+ /// Returns the number of elements in the anytype.
63+ /// If 1 is returned, it could be a single element type.
5564pub inline fn len (self : Self , comptime T : type ) usize {
5665 const size = switch (@typeInfo (T )) {
5766 .Pointer = > | p | @sizeOf (p .child ),
@@ -60,3 +69,17 @@ pub inline fn len(self: Self, comptime T: type) usize {
6069
6170 return @divExact (self .size , size );
6271}
72+
73+ test "Casting integers and floats" {
74+ comptime var i : usize = 0 ;
75+ inline while (i < std .math .maxInt (u8 )) : (i += 1 ) {
76+ try std .testing .expectEqual (i , try initExplicit (u8 , i ).cast (u8 ));
77+ }
78+
79+ try std .testing .expectEqual (123.456 , try initExplicit (f32 , 123.456 ).cast (f32 ));
80+ }
81+
82+ test "Invalid casts" {
83+ try std .testing .expectError (error .InvalidCast , initExplicit (f32 , 123.456 ).cast (u8 ));
84+ try std .testing .expectError (error .InvalidCast , initExplicit (f32 , 123.456 ).cast (f128 ));
85+ }
0 commit comments