const c = @import("./c.zig"); const Entity = @import("./entity.zig").Entity; const Id = @import("./id.zig").Id; const World = @import("./world.zig").World; pub const PairError = error{ /// Id is `0`. IsNone, /// Id is not a `Pair`. IsNotPair, }; /// A `Pair` is an `Id` which encodes a relationship between two entities. /// It is made of two parts, `relation` and `target`, each represented as /// entities themselves. `relation` is an entity describing the nature of the /// relationship, and `target` is the target this relationship is about. /// /// For example, if the entity `Alice` likes another entity `Bob`, you would /// add the pair `(Likes, Bob)` to entity `Alice`. /// /// `Pair`s are created using `init()`, or can be converted from `Id`s using /// `Id.asPair()` (fails if the id isn't a pair). They can be turned back /// to an `Id` with `asId()` (always succeeds). Elements of the relationship /// can be extracted by calling `getRelation()` and `getTarget()`. pub fn Pair(comptime ctx: anytype) type { return struct { world: *World(ctx), raw: c.ecs_id_t, const Self = @This(); /// Build a pair from the specified `relation` and `target` entities. /// The specified entities must be alive in the world. pub fn init(relation: Entity(ctx), target: Entity(ctx)) !Self { const raw = c.ecs_make_pair(relation.ensureAlive().raw, target.ensureAlive().raw); return .{ .world = relation.world, .raw = raw }; } /// Ensures this `Pair` is valid and its `relation` and `target` /// entities are alive in the world, returning an error otherwise. pub fn ensureAlive(self: Self) !Self { if (self.raw == 0) return error.IsNone; if (!c.ecs_id_is_pair(self.raw)) return error.IsntPair; _ = try self.getRelation().ensureAlive(); _ = try self.getTarget().ensureAlive(); return self; } /// Ensures this `Pair` and its elements are valid. pub fn ensureValid(self: Self) !Self { if (self.raw == 0) return error.IsNone; if (!c.ecs_id_is_pair(self.raw)) return error.IsntPair; _ = try self.getRelation().ensureValid(); _ = try self.getTarget().ensureValid(); return self; } pub fn asId(self: Self) Id(ctx) { return @bitCast(self); } pub fn getRelation(self: Self) Entity(ctx) { return Entity(ctx).fromRaw(self.world, c.ECS_PAIR_FIRST(self.raw)); } pub fn getTarget(self: Self) Entity(ctx) { return Entity(ctx).fromRaw(self.world, c.ECS_PAIR_SECOND(self.raw)); } // TODO: Decide whether to copy `Id` functions over? }; }