|
|
|
@ -70,12 +70,21 @@ pub const Path = struct { |
|
|
|
|
} { |
|
|
|
|
const len = @typeInfo(@TypeOf(parts)).Struct.fields.len; |
|
|
|
|
var result: [len]EntityPart = undefined; |
|
|
|
|
inline for (&result, parts) |*res, part| |
|
|
|
|
res.* = switch (@TypeOf(part)) { |
|
|
|
|
[]u8, []const u8 => |name| .{ .name = name }, |
|
|
|
|
u32, comptime_int => |id| .{ .id = id }, |
|
|
|
|
else => @compileError("Expected []u8, []const u8, u32 or comptime_int, got '" ++ @typeName(@TypeOf(part)) ++ "'"), |
|
|
|
|
inline for (&result, parts) |*res, part| { |
|
|
|
|
const msg = "Expected '[]const u8' or 'u32', got '" ++ @typeName(@TypeOf(part)) ++ "'"; |
|
|
|
|
res.* = switch (@typeInfo(@TypeOf(part))) { |
|
|
|
|
.Pointer => |p| switch (p.size) { |
|
|
|
|
.One => switch (@typeInfo(p.child)) { |
|
|
|
|
.Array => |a| if (a.child == u8) .{ .name = part } else @compileError(msg), |
|
|
|
|
else => @compileError(msg), |
|
|
|
|
}, |
|
|
|
|
.Slice => if (p.child == u8) .{ .name = part } else @compileError(msg), |
|
|
|
|
else => @compileError(msg), |
|
|
|
|
}, |
|
|
|
|
.Int, .ComptimeInt => .{ .id = part }, |
|
|
|
|
else => @compileError(msg), |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -130,12 +139,24 @@ pub const Path = struct { |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Creates a `Path` for the specified `child` entity, optionally in |
|
|
|
|
/// relation to the specified `parent` entity. If `parent` is not `null`, |
|
|
|
|
/// the resulting path is relative. Otherwise it will be absolute. |
|
|
|
|
/// |
|
|
|
|
/// This function allocates an array for the parts that make up the entity's |
|
|
|
|
/// path, however each part itself is owned by Flecs and could change or be |
|
|
|
|
/// invalidated ay any time, such as when an entity is renamed or removed. |
|
|
|
|
pub fn fromEntity(comptime ctx: type, parent: ?Entity(ctx), child: Entity(ctx), alloc: Allocator) !Path { |
|
|
|
|
if (parent) |p| std.debug.assert(p.raw != 0); |
|
|
|
|
std.debug.assert(child.raw != 0); |
|
|
|
|
if (parent) |p| { |
|
|
|
|
std.debug.assert(p.raw != 0); |
|
|
|
|
std.debug.assert(p.raw != child.raw); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: Use a threadlocal field with reasonable size, then clone the result. |
|
|
|
|
const starting_capacity: usize = 12; |
|
|
|
|
var parts = try alloc.alloc(EntityPart, starting_capacity); |
|
|
|
|
errdefer alloc.free(parts); |
|
|
|
|
var num_parts: usize = 0; |
|
|
|
|
|
|
|
|
|
// Traverse up the entity hierarchy starting from the specified child |
|
|
|
@ -148,7 +169,14 @@ pub const Path = struct { |
|
|
|
|
else |
|
|
|
|
.{ .id = current.getEntityId() }; |
|
|
|
|
num_parts += 1; |
|
|
|
|
current = current.getParent() orelse break; |
|
|
|
|
|
|
|
|
|
// Move to the parent entity, if any. |
|
|
|
|
current = current.getParent() orelse |
|
|
|
|
// If `parent` wasn't specified, we reached the root. Done. |
|
|
|
|
// Otherwise, if the parent wasn't found, return an error. |
|
|
|
|
if (parent == null) break else return error.ParentNotFound; |
|
|
|
|
|
|
|
|
|
// If we reached the specified `parent`, we're done here! |
|
|
|
|
if (parent != null and current.raw == parent.?.raw) break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|