using System; using gaemstone.ECS.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS; public unsafe struct Id : IEquatable> { public readonly World World; public readonly Id Value; public IdFlags Flags => Value.Flags; public bool IsPair => Value.IsPair; public bool IsWildcard => Value.IsWildcard; public bool IsValid => ecs_id_is_valid(World, this); public bool IsTag => ecs_id_is_tag(World, this); public bool IsInUse => ecs_id_in_use(World, this); public int Count => ecs_count_id(World, this); private Id(World world, Id id) { World = world; Value = id; } public static Id GetUnsafe(World world, Id value) => new(world, value); public static Id? GetOrNull(World world, Id value) => ecs_id_is_valid(world, value) ? new(world, value) : null; public static Id GetOrThrow(World world, Id value) => ecs_id_is_valid(world, value) ? new(world, value) : throw new InvalidOperationException($"The id {value} is not valid"); public Entity? AsEntity() => !IsPair ? World.LookupAliveOrNull(new Entity(new() { Data = Value })) : null; public (Entity Relation, Entity Target)? AsPair() => IsPair && (World.LookupAliveOrNull(Value.RelationUnsafe) is Entity relation) && (World.LookupAliveOrNull(Value.TargetUnsafe ) is Entity target ) ? (relation, target) : null; public bool Equals(Id other) { #if DEBUG // In DEBUG mode, we additionally check if the worlds the two compared // values are from the same world. This accounts for the world being a // stage, hence why it might not be the cheapest operation. if (World != other.World) throw new ArgumentException( "The specified values are not from the same world"); #endif return Value == other.Value; } public override bool Equals(object? obj) => (obj is Id other) && Equals(other); public override int GetHashCode() => Value.GetHashCode(); public override string? ToString() => ecs_id_str(World, this).FlecsToStringAndFree()!; public static bool operator ==(Id left, Id right) => left.Equals(right); public static bool operator !=(Id left, Id right) => !left.Equals(right); public static implicit operator Id (Id id) => id.Value; public static implicit operator ecs_id_t(Id id) => id.Value.Value; public static implicit operator Term(Id id) => new(id.Value); } [Flags] public enum IdFlags : ulong { Pair = 1ul << 63, Override = 1ul << 62, Toggle = 1ul << 61, And = 1ul << 60, }