187 lines
5.7 KiB
Zig
187 lines
5.7 KiB
Zig
const std = @import("std");
|
|
const debug = @import("debug.zig");
|
|
|
|
const compileError = debug.compileError;
|
|
|
|
pub const FnSignature = @import("signature.zig").FnSignature;
|
|
|
|
pub fn isStruct(comptime T: type) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Struct => true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isTuple(comptime T: type) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Struct => |info| info.is_tuple,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isStructOf(comptime T: type, comptime Elem: type) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Struct => |info| blk: {
|
|
inline for (info.fields) |field| {
|
|
if (field.type != Elem) {
|
|
break :blk false;
|
|
}
|
|
}
|
|
break :blk true;
|
|
},
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isStructOfAny(comptime T: type, comptime f: fn (comptime type) bool) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Struct => |info| blk: {
|
|
inline for (info.fields) |field| {
|
|
if (f(field.type) == false) {
|
|
break :blk false;
|
|
}
|
|
}
|
|
break :blk true;
|
|
},
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isTupleOf(comptime T: type, comptime Elem: type) bool {
|
|
return isTuple(T) and isStructOf(T, Elem);
|
|
}
|
|
|
|
pub fn isTupleOfAny(comptime T: type, comptime f: fn (comptime type) bool) bool {
|
|
return isTuple(T) and isStructOfAny(T, f);
|
|
}
|
|
|
|
pub fn isSliceOf(comptime T: type, comptime Elem: type) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Pointer => |info| switch (info.size) {
|
|
.Slice => info.child == Elem,
|
|
.One => switch (@typeInfo(info.child)) {
|
|
// As Zig, convert pointer to Array as a slice.
|
|
.Array => |arr_info| arr_info.child == Elem,
|
|
else => false,
|
|
},
|
|
else => false,
|
|
},
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isInteger(comptime T: type) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Int, .ComptimeInt => true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isSliceOfAny(comptime T: type, comptime f: fn (comptime type) bool) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.Pointer => |info| info.size == .Slice and f(info.child),
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn DeclEnum(comptime T: type) type {
|
|
const field_infos = std.meta.declarations(T);
|
|
if (field_infos.len == 0) {
|
|
compileError("Struct {} has no declarations", .{T});
|
|
}
|
|
return std.meta.DeclEnum(UnwrapPtr(T));
|
|
}
|
|
|
|
pub fn UnwrapPtr(comptime T: type) type {
|
|
return switch (@typeInfo(T)) {
|
|
.Pointer => |info| switch (info.size) {
|
|
.One => info.child,
|
|
else => T,
|
|
},
|
|
else => T,
|
|
};
|
|
}
|
|
|
|
pub fn asSlice(comptime T: type) type {
|
|
const err_msg = "Type " ++ @typeName(T) ++ " can't be interpreted as a slice";
|
|
return switch (@typeInfo(T)) {
|
|
.Pointer => |info| switch (info.size) {
|
|
.Slice => info.child,
|
|
.One => switch (@typeInfo(info.child)) {
|
|
// As Zig, convert pointer to Array as a slice.
|
|
.Array => |arr_info| arr_info.child,
|
|
else => @compileError(err_msg),
|
|
},
|
|
else => @compileError(err_msg),
|
|
},
|
|
else => @compileError(err_msg),
|
|
};
|
|
}
|
|
|
|
pub fn TupleRange(comptime T: type, comptime start: ?usize, comptime end: ?usize) type {
|
|
return TupleRangeX(T, start orelse 0, end orelse std.meta.fields(T).len);
|
|
}
|
|
|
|
pub fn TupleRangeX(comptime T: type, comptime start: usize, comptime end: usize) type {
|
|
const fields = std.meta.fields(T);
|
|
var new_fields: [end - start]std.builtin.Type.StructField = undefined;
|
|
inline for (start..end, 0..) |i, j| {
|
|
var new_field = fields[i];
|
|
var num_buf: [32]u8 = undefined;
|
|
new_field.name = blk: {
|
|
const s = std.fmt.formatIntBuf(&num_buf, j, 10, .lower, .{});
|
|
num_buf[s] = 0;
|
|
break :blk num_buf[0..s :0];
|
|
};
|
|
new_fields[j] = new_field;
|
|
}
|
|
return @Type(.{
|
|
.Struct = .{
|
|
.is_tuple = true,
|
|
.layout = .auto,
|
|
.decls = &.{},
|
|
.fields = &new_fields,
|
|
},
|
|
});
|
|
}
|
|
|
|
pub fn FnParam(comptime func: anytype, comptime n: comptime_int) type {
|
|
return @typeInfo(@TypeOf(func)).Fn.params[n].type orelse @compileError("anytype is not supported");
|
|
}
|
|
|
|
pub fn FnArgs(comptime func: anytype) type {
|
|
debug.assertComptime(!@typeInfo(@TypeOf(func)).Fn.is_generic, "FnArgs expects non generic function, got: {}", .{@TypeOf(func)});
|
|
return FnSignature(func, null).ArgsT;
|
|
}
|
|
|
|
pub fn FnArgsWithHint(comptime func: anytype, ArgsT: type) type {
|
|
debug.assertComptime(@typeInfo(@TypeOf(func)).Fn.is_generic, "FnArgsWithHint expects a generic function, got: {}", .{@TypeOf(func)});
|
|
return FnSignature(func, ArgsT).ArgsT;
|
|
}
|
|
|
|
pub fn FnResult(comptime func: anytype) type {
|
|
return @typeInfo(@TypeOf(func)).Fn.return_type orelse @compileError("anytype is not supported");
|
|
}
|
|
|
|
pub fn Head(Tuple: type) type {
|
|
return switch (@typeInfo(Tuple)) {
|
|
.Struct => |struct_info| {
|
|
if (struct_info.fields.len == 0) @compileError("Can't tail empty tuple");
|
|
return struct_info.fields[0].type;
|
|
},
|
|
else => @compileError("Head works on tuple type"),
|
|
};
|
|
}
|
|
|
|
pub fn Tail(Tuple: type) type {
|
|
return switch (@typeInfo(Tuple)) {
|
|
.Struct => |struct_info| {
|
|
if (struct_info.fields.len == 0) @compileError("Can't tail empty tuple");
|
|
var types: [struct_info.fields.len - 1]type = undefined;
|
|
for (struct_info.fields[1..], 0..) |field, i| types[i] = field.type;
|
|
return std.meta.Tuple(&types);
|
|
},
|
|
else => @compileError("Tail works on tuple type"),
|
|
};
|
|
}
|