diff --git a/src/path.zig b/src/path.zig index 5c2d052..de0b5f9 100644 --- a/src/path.zig +++ b/src/path.zig @@ -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; }