using System; using System.Collections; using System.Collections.Generic; using gaemstone.ECS.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS; public unsafe class Rule : IDisposable { public World World { get; } public ecs_rule_t* Handle { get; } public Filter Filter { get; } private VariableCollection? _variables; public VariableCollection Variables => _variables ??= new(this); public Variable? ThisVar => Filter.ThisVar; public Rule(World world, FilterDesc desc) { using var alloc = TempAllocator.Use(); var flecsDesc = desc.ToFlecs(alloc); World = world; Handle = ecs_rule_init(world, &flecsDesc); Filter = new(World, ecs_rule_get_filter(Handle)); } public void Dispose() => ecs_rule_fini(this); public RuleIterator Iter() => new(ecs_rule_iter(World, this)); public override string ToString() => ecs_rule_str(Handle).FlecsToStringAndFree()!; public static implicit operator ecs_rule_t*(Rule rule) => rule.Handle; public unsafe class VariableCollection : IReadOnlyCollection { private readonly List _variables = new(); public int Count => _variables.Count; public Variable? this[int index] => _variables.Find(v => v.Index == index); public Variable? this[string name] => _variables.Find(v => string.Equals( v.Name, name, StringComparison.OrdinalIgnoreCase)); internal VariableCollection(ecs_rule_t* handle) { // Find the $this variable, if the rule has one. var thisIndex = ecs_filter_find_this_var(ecs_rule_get_filter(handle)); if (thisIndex >= 0) _variables.Add(new(thisIndex, "this")); // Find all the other "accessible" variables. var count = ecs_rule_var_count(handle); for (var i = 0; i < count; i++) { if ((i == thisIndex) || !ecs_rule_var_is_entity(handle, i)) continue; var name = ecs_rule_var_name(handle, i).FlecsToString()!; _variables.Add(new(i, name)); } } // IEnumerable implementation public IEnumerator GetEnumerator() => _variables.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _variables.GetEnumerator(); } } public unsafe class RuleIterator : Iterator { internal RuleIterator(ecs_iter_t value) : base(value) { } public override bool Next() => ecs_rule_next(Handle); }