const c = @import("./c.zig"); 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 `relation()` and `target()`. pub fn Pair(comptime ctx: anytype) type { return struct { const Self = @This(); const Context = @import("./context.zig").Context(ctx); const World = Context.World; const Entity = Context.Entity; const Id = Context.Id; world: *World, raw: c.ecs_id_t, pub fn fromRaw(world: *World, relation_: c.ecs_entity_t, target_: c.ecs_entity_t) Self { return .{ .world = world, .raw = c.ecs_pair(relation_, target_) }; } /// Build a pair from the specified `relation` and `target` entities. /// Returns an error if either of the entities is not alive. pub fn init(relation_: Entity, target_: Entity) !Self { try relation_.ensureAlive(); try target_.ensureAlive(); return fromRaw(relation_.world, relation_.raw, target_.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) !void { if (self.raw == 0) return error.IsNone; if (!c.ecs_id_is_pair(self.raw)) return error.IsntPair; try self.relation().ensureAlive(); try self.target().ensureAlive(); } /// Ensures this `Pair` and its elements are valid. pub fn ensureValid(self: Self) !void { if (self.raw == 0) return error.IsNone; if (!c.ecs_id_is_pair(self.raw)) return error.IsntPair; try self.relation().ensureValid(); try self.target().ensureValid(); } pub fn asId(self: Self) Id { return .{ .world = self.world, .raw = self.raw }; } pub fn relation(self: Self) Entity { return Entity.fromRaw(self.world, c.ECS_PAIR_FIRST(self.raw)); } pub fn target(self: Self) Entity { return Entity.fromRaw(self.world, c.ECS_PAIR_SECOND(self.raw)); } // TODO: Decide whether to copy `Id` functions over? }; }