using System; using System.Collections.Concurrent; using System.Collections.Generic; using Cysharp.Threading.Tasks; namespace BITKit { public interface IValidHandle { bool Allow { get; } void AddElement(object obj); void RemoveElement(object obj); void AddDisableElements(object obj); void RemoveDisableElements(object obj); void SetElements(object obj, bool add = true); void SetDisableElements(object obj, bool add = true); void Invoke(); void Invoke(bool value); void AddListener(Action action); void RemoveListener(Action action); void Clear(); } [CustomType(typeof(IValidHandle))] public sealed class ValidHandle: IValidHandle,IDisposable { public class MyHandle:IDisposable { private readonly ValidHandle _validHandle; private readonly bool _isDisable; public MyHandle(ValidHandle validHandle,bool isDisable = false) { _validHandle = validHandle; _isDisable = isDisable; if (isDisable) { _validHandle.AddDisableElements(this); } else { _validHandle.AddElement(this); } } public void Dispose() { if (_isDisable) { _validHandle.RemoveDisableElements(this); } else { _validHandle.RemoveElement(this); } } } public MyHandle GetHandle() => new MyHandle(this); public MyHandle GetDisableHandle()=> new MyHandle(this,true); public override string ToString() { return $"Allow:{_enableHandle}\nElements:{string.Join("\n",_objs)}\nDisableElements:{string.Join("\n",_disableObjs)}"; } public ValidHandle() {} public ValidHandle(Action boolDelegate) { AddListener(boolDelegate); _eventOnEnableChanged?.Invoke(_enableHandle); } public static implicit operator bool(ValidHandle validHandle) { return !validHandle._isDisposed && validHandle._enableHandle; } public bool Allow => this; private bool _enableHandle; /// /// ⚠️Dont operate this field directly /// private readonly HashSet _objs = new(); /// /// ⚠️Dont operate this field directly /// private readonly HashSet _disableObjs = new(); private bool _tempEnable; private Action _eventOnEnableChanged; private readonly ConcurrentQueue _completionSources = new(); private bool _isDisposed; public void AddElement(object obj) { _objs.Add(obj); CheckEnable(); } private void CheckEnable() { _tempEnable = _objs.Count > 0 && _disableObjs.Count == 0; if (_tempEnable == _enableHandle) return; _enableHandle = _tempEnable; _eventOnEnableChanged?.Invoke(_enableHandle); if (_tempEnable) return; if (_completionSources.TryDequeue(out var cs)) { cs.TrySetResult(); } } public void RemoveElement(object obj) { if (_objs.Contains(obj)) { _objs.Remove(obj); } CheckEnable(); } public int Lenght => _objs.Count; public bool Contains(object obj) => _objs.Contains(obj); public void AddDisableElements(object obj) { _disableObjs.Add(obj); CheckEnable(); } public void RemoveDisableElements(object obj) { if (_disableObjs.Contains(obj)) { _disableObjs.Remove(obj); } else { } CheckEnable(); } public void SetElements(object obj, bool add = true) { if (add) { AddElement(obj); } else { RemoveElement(obj); } } public void SetDisableElements(object obj, bool add = true) { if (add) { AddDisableElements(obj); } else { RemoveDisableElements(obj); } } public void Invoke() { var enable = _disableObjs.Count == 0 && _objs.Count > 0; _eventOnEnableChanged?.Invoke(enable); } public void Invoke(bool value) { _eventOnEnableChanged?.Invoke(value); } public void AddListener(Action action) { _eventOnEnableChanged+= action; } public void RemoveListener(Action action) { if(_eventOnEnableChanged is not null && action is not null) { _eventOnEnableChanged -= action; } } public UniTask.Awaiter GetAwaiter() { if (Allow is false) { return UniTask.CompletedTask.GetAwaiter(); } var cs = new UniTaskCompletionSource(); _completionSources.Enqueue(cs); return cs.Task.GetAwaiter(); } public void Clear() { _objs.Clear(); _disableObjs.Clear(); Invoke(); } public void Dispose() { _isDisposed = true; _objs.Clear(); _disableObjs.Clear(); _eventOnEnableChanged = null; } } }