|
|
|
//! Since the `std.meta.trait` module was removed from Zig's standard
|
|
|
|
//! library, we're re-introducing some of the functions we needed.
|
|
|
|
|
|
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
/// Returns if the provided type is a tuple.
|
|
|
|
pub fn isTuple(comptime T: type) bool {
|
|
|
|
return @typeInfo(T) == .Struct and @typeInfo(T).Struct.is_tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the passed type will coerce to []const u8.
|
|
|
|
/// Any of the following are considered strings:
|
|
|
|
/// ```
|
|
|
|
/// []const u8, [:S]const u8, *const [N]u8, *const [N:S]u8,
|
|
|
|
/// []u8, [:S]u8, *[:S]u8, *[N:S]u8.
|
|
|
|
/// ```
|
|
|
|
/// These types are not considered strings:
|
|
|
|
/// ```
|
|
|
|
/// u8, [N]u8, [*]const u8, [*:0]const u8,
|
|
|
|
/// [*]const [N]u8, []const u16, []const i8,
|
|
|
|
/// *const u8, ?[]const u8, ?*const [N]u8.
|
|
|
|
/// ```
|
|
|
|
pub fn isZigString(comptime T: type) bool {
|
|
|
|
return comptime blk: {
|
|
|
|
// Only pointer types can be strings, no optionals
|
|
|
|
const info = @typeInfo(T);
|
|
|
|
if (info != .Pointer) break :blk false;
|
|
|
|
|
|
|
|
const ptr = &info.Pointer;
|
|
|
|
// Check for CV qualifiers that would prevent coerction to []const u8
|
|
|
|
if (ptr.is_volatile or ptr.is_allowzero) break :blk false;
|
|
|
|
|
|
|
|
// If it's already a slice, simple check.
|
|
|
|
if (ptr.size == .Slice) {
|
|
|
|
break :blk ptr.child == u8;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise check if it's an array type that coerces to slice.
|
|
|
|
if (ptr.size == .One) {
|
|
|
|
const child = @typeInfo(ptr.child);
|
|
|
|
if (child == .Array) {
|
|
|
|
const arr = &child.Array;
|
|
|
|
break :blk arr.child == u8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break :blk false;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the type of the specified expression, which must be either
|
|
|
|
/// just a `type`, or a tuple in the form of `.{ TRelation, TTarget }`,
|
|
|
|
/// representing a relationship pair in Flecs.
|
|
|
|
///
|
|
|
|
/// If the expression is a pair, the type is determined like this:
|
|
|
|
/// - If `TRelation` is a non-zero-sized type, it is returned.
|
|
|
|
/// - If `TTarget` is a non-zero-sized type, it is returned.
|
|
|
|
/// - Otherwise, a compile error is raised.
|
|
|
|
pub fn AnyToType(comptime expr: anytype) type {
|
|
|
|
switch (@typeInfo(@TypeOf(expr))) {
|
|
|
|
.Type => return expr,
|
|
|
|
.Struct => |s| {
|
|
|
|
if (!s.is_tuple or s.fields.len != 2)
|
|
|
|
@compileError("Expression must be a type or a tuple of two types");
|
|
|
|
|
|
|
|
const TRelation = expr[0];
|
|
|
|
const TTarget = expr[1];
|
|
|
|
if (@TypeOf(TRelation) != type) @compileError("TRelation must be a type, but is " ++ @typeName(@TypeOf(TRelation)));
|
|
|
|
if (@TypeOf(TTarget) != type) @compileError("TTarget must be a type, but is " ++ @typeName(@TypeOf(TTarget)));
|
|
|
|
|
|
|
|
if (@sizeOf(TRelation) > 0) return TRelation;
|
|
|
|
if (@sizeOf(TTarget) > 0) return TTarget;
|
|
|
|
@compileError("Either TRelation or TTarget must be a non-zero-sized type");
|
|
|
|
},
|
|
|
|
else => @compileError("Expression must be a type or a tuple of two types"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the simplified type name of the specified type.
|
|
|
|
/// That is, without any namespace qualifiers.
|
|
|
|
pub fn simpleTypeName(comptime T: type) [:0]const u8 {
|
|
|
|
const fullName = @typeName(T);
|
|
|
|
const index = std.mem.lastIndexOf(u8, fullName, ".");
|
|
|
|
return if (index) |i| fullName[(i + 1)..] else fullName;
|
|
|
|
}
|