Allow specifying pairs in Entity get/set functions

main
copygirl 9 months ago
parent 5273084f99
commit 01d5ed7e48
  1. 23
      src/entity.zig
  2. 28
      src/meta.zig

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const meta = @import("./meta.zig");
const flecs = @import("./main.zig"); const flecs = @import("./main.zig");
const Path = flecs.Path; const Path = flecs.Path;
const c = flecs.c; const c = flecs.c;
@ -84,10 +85,10 @@ pub fn Entity(comptime ctx: anytype) type {
/// To set their values you'll need to use `set(...)` on the /// To set their values you'll need to use `set(...)` on the
/// `Entity` returned from this function. /// `Entity` returned from this function.
pub fn init(world: *World, config: Config, ids: anytype) !Self { pub fn init(world: *World, config: Config, ids: anytype) !Self {
const meta = @typeInfo(@TypeOf(ids)); const info = @typeInfo(@TypeOf(ids));
if (meta != .Struct or (meta.Struct.is_tuple == false and meta.Struct.fields.len > 0)) if (info != .Struct or (info.Struct.is_tuple == false and info.Struct.fields.len > 0))
@compileError("Expected tuple or empty struct, got '" ++ @typeName(@TypeOf(ids)) ++ "'"); @compileError("Expected tuple or empty struct, got '" ++ @typeName(@TypeOf(ids)) ++ "'");
if (meta.Struct.fields.len > c.FLECS_ID_DESC_MAX) if (info.Struct.fields.len > c.FLECS_ID_DESC_MAX)
@compileError("Adding more than FLECS_ID_DESC_MAX ids"); @compileError("Adding more than FLECS_ID_DESC_MAX ids");
var id = if (config.id) |i| i.raw else null; var id = if (config.id) |i| i.raw else null;
@ -303,7 +304,7 @@ pub fn Entity(comptime ctx: anytype) type {
/// Gets a value copy of a component. /// Gets a value copy of a component.
/// If the component does not exist, returns null. /// If the component does not exist, returns null.
pub fn get(self: Self, comptime T: type) ?T { pub fn get(self: Self, comptime T: anytype) ?meta.AnyToType(T) {
return if (getRef(self, T)) |p| p.* else null; return if (getRef(self, T)) |p| p.* else null;
} }
@ -313,8 +314,8 @@ pub fn Entity(comptime ctx: anytype) type {
/// The returned pointer may become invalid after calling other Flecs /// The returned pointer may become invalid after calling other Flecs
/// functions, notably when an `Entity` moves to another table caused /// functions, notably when an `Entity` moves to another table caused
/// by adding or removing other components. /// by adding or removing other components.
pub fn getRef(self: Self, comptime T: type) ?*const T { pub fn getRef(self: Self, comptime T: anytype) ?*const meta.AnyToType(T) {
const id = Context.lookup(T).*; const id = Context.anyToId(T);
const ptr = c.ecs_get_id(self.world.raw, self.raw, id); const ptr = c.ecs_get_id(self.world.raw, self.raw, id);
return @alignCast(@ptrCast(ptr)); return @alignCast(@ptrCast(ptr));
} }
@ -329,15 +330,15 @@ pub fn Entity(comptime ctx: anytype) type {
/// If `getMut` is called when the world is in deferred / readonly /// If `getMut` is called when the world is in deferred / readonly
/// mode, and the component does not yet exist, it will return a /// mode, and the component does not yet exist, it will return a
/// pointer to a temp storage. /// pointer to a temp storage.
pub fn getMut(self: Self, comptime T: type) *T { pub fn getMut(self: Self, comptime T: anytype) *meta.AnyToType(T) {
const id = Context.lookup(T).*; const id = Context.anyToId(T);
const ptr = c.ecs_get_mut_id(self.world.raw, self.raw, id); const ptr = c.ecs_get_mut_id(self.world.raw, self.raw, id);
return @alignCast(@ptrCast(ptr)); return @alignCast(@ptrCast(ptr));
} }
pub fn set(self: Self, comptime T: type, value: T) void { pub fn set(self: Self, comptime T: anytype, value: meta.AnyToType(T)) void {
const id = Context.lookup(T).*; const id = Context.anyToId(T);
_ = c.ecs_set_id(self.world.raw, self.raw, id, @sizeOf(T), &value); _ = c.ecs_set_id(self.world.raw, self.raw, id, @sizeOf(@TypeOf(value)), &value);
} }
}; };
} }

@ -48,6 +48,34 @@ pub fn isZigString(comptime T: type) bool {
}; };
} }
/// 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. /// Gets the simplified type name of the specified type.
/// That is, without any namespace qualifiers. /// That is, without any namespace qualifiers.
pub fn simpleTypeName(comptime T: type) [:0]const u8 { pub fn simpleTypeName(comptime T: type) [:0]const u8 {

Loading…
Cancel
Save