Compare commits

...

2 Commits

  1. 11
      src/builtin/flecs.core.zig
  2. 4
      src/context.zig
  3. 79
      src/meta.zig
  4. 10
      src/world.zig

@ -122,15 +122,14 @@ pub const Panic = struct {};
// Query markers
// zig fmt: off
/// Query marker to express `$this` variable.
pub const This = struct {};
pub const _This_Name = "$";
pub const This = struct { pub const name = "$"; };
/// Query marker to express match all wildcard (`*` in query DSL).
pub const Wildcard = struct {};
pub const _Wildcard_Name = "*";
pub const Wildcard = struct { pub const name = "*"; };
/// Query marker to express match at least one wildcard (`_` in query DSL).
pub const Any = struct {};
pub const _Any_Name = "_";
pub const Any = struct { pub const name = "_"; };
// zig fmt: on
/// Query marker to express `==` operator.
pub const PredEq = struct {};

@ -150,8 +150,8 @@ pub fn Context(comptime ctx: anytype) type {
if (@TypeOf(ChildType) != type) continue;
comptime var child_name = decl.name;
if (@hasDecl(T, "_" ++ decl.name ++ "_Name"))
child_name = @field(T, "_" ++ decl.name ++ "_Name");
if (@hasDecl(ChildType, "name"))
child_name = @field(ChildType, "name");
const child = try lookupAndRegister(world, parent, child_name, ChildType, error_writer);
try lookupAndRegisterDeclarations(world, child, ChildType, error_writer);

@ -85,3 +85,82 @@ pub fn AnyToType(comptime expr: anytype) type {
else => @compileError("Expression must be a type or a tuple of two types"),
}
}
/// Gets a Flecs-compatible symbol name for the specified type.
/// Supports structs (except anonymous or generic), as well as
/// single-item pointers to supported structs.
///
/// If the struct defines a public accessible `name`, it is used.
pub fn flecsTypeName(comptime T: type) [:0]const u8 {
const allowed_characters =
"abcdefghijklmnopqrstuvwxyz" ++
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++
"0123456789_";
switch (@typeInfo(T)) {
.Struct => {
comptime var name: [:0]const u8 = undefined;
comptime if (@hasDecl(T, "name")) {
name = @field(T, "name");
} else {
name = @typeName(T);
if (std.mem.indexOfScalar(u8, name, '{') != null)
@compileError("Expected type with simple name, got '" ++ @typeName(T) ++ "' (anonymous type?)");
// If name includes fully qualified namespace, strip it.
if (std.mem.lastIndexOfScalar(u8, name, '.')) |i|
name = name[(i + 1)..];
if (std.mem.indexOfScalar(u8, name, '(') != null)
@compileError("Expected type with simple name, got '" ++ @typeName(T) ++ "' (generic type?)");
if (std.mem.indexOf(u8, name, "__") != null)
@compileError("Expected type with simple name, got '" ++ @typeName(T) ++ "' (anonymous type?)");
if (std.mem.indexOfNone(u8, name, allowed_characters) != null)
@compileError("Expected type with simple name, got '" ++ @typeName(T) ++ "' (invalid characters?)");
};
return name;
},
.Pointer => |p| {
if (p.size != .One)
@compileError("Expected struct or single-item pointer, got '" ++ @typeName(T) ++ "'");
return flecsTypeName(p.child);
},
else => @compileError("Expected struct or single-item pointer, got '" ++ @typeName(T) ++ "'"),
}
}
const expect = @import("./test/expect.zig");
test flecsTypeName {
const Foo = struct {};
try expect.equal("Foo", flecsTypeName(Foo));
try expect.equal("Foo", flecsTypeName(*Foo));
const Bar = struct {
const Baz = struct {
const Quux = struct {};
};
};
try expect.equal("Quux", flecsTypeName(Bar.Baz.Quux));
try expect.equal("Anon", flecsTypeName((struct {
const Anon = struct {};
}).Anon));
try expect.equal("Random", flecsTypeName(std.Random));
// error: Expected struct or single-item pointer, got 'i32'
// _ = flecsTypeName(i32);
// error: Expected type with simple name, got 'array_list.ArrayListAligned(i32,null)' (generic type?)
// _ flecsTypeName(std.ArrayList(i32));
// error: Expected type with simple name, got 'meta.decltest.flecsTypeName__struct_...' (anonymous type?)
// _ = flecsTypeName(struct {});
// error: Expected type with simple name, got 'struct{comptime foo: comptime_int = 0}' (anonymous type?)
// _ = flecsTypeName(@TypeOf(.{ .foo = 0 }));
// error: Expected type with simple name, got 'meta.decltest.flecsTypeName.%&!*' (invalid characters?)
// const @"%&!*" = struct {};
// _ = flecsTypeName(@"%&!*");
}

@ -137,14 +137,16 @@ pub fn World(comptime ctx: anytype) type {
return Entity.init(self, config, add);
}
pub fn tag(self: *Self, name: [:0]const u8, comptime T: type) !Entity {
pub fn tag(self: *Self, comptime T: type) !Entity {
const name = meta.flecsTypeName(T);
if (@sizeOf(T) > 0) @compileError("'" ++ @typeName(T) ++ "' must be a zero-sized type");
const result = try self.entity(.{ .name = name, .symbol = name }, .{});
Context.lookupMut(T).* = result.raw;
return result;
}
pub fn component(self: *Self, name: [:0]const u8, comptime T: type) !Entity {
pub fn component(self: *Self, comptime T: type) !Entity {
const name = meta.flecsTypeName(T);
if (@sizeOf(T) == 0) @compileError("'" ++ @typeName(T) ++ "' must not be a zero-sized type");
const entity_ = try self.entity(.{ .name = name, .symbol = name, .use_low_id = true }, .{});
@ -167,8 +169,8 @@ pub fn World(comptime ctx: anytype) type {
/// Use `get()` and `set()` to get and set the value of this singleton.
///
/// Returns the created component entity.
pub fn singleton(self: *Self, name: [:0]const u8, comptime T: type, value: T) !Entity {
const single = try component(self, name, T);
pub fn singleton(self: *Self, comptime T: type, value: T) !Entity {
const single = try component(self, T);
single.set(T, value);
return single;
}

Loading…
Cancel
Save