using System; using System.Collections.Generic; using System.Threading.Tasks; namespace Gum.Signal.Core { public sealed class SignalCenter { private readonly object _lock = new object(); private readonly List _entries = new List(); public void Subscribe(Action action) { lock (_lock) { _entries.Add(new Entry(action, typeof(T), false)); } } public void Subscribe(Func func) { lock (_lock) { _entries.Add(new Entry(func, typeof(T), true)); } } public void Unsubscribe(Func func) { lock (_lock) { for (int index = 0; index < _entries.Count; index++) { Entry entry = _entries[index]; if (entry.Delegate as Func == func) { _entries.Remove(entry); } } } } public void Unsubscribe(Action action) { lock (_lock) { for (int index = 0; index < _entries.Count; index++) { Entry entry = _entries[index]; if (entry.Delegate as Action == action) { _entries.Remove(entry); } } } } public bool TryUnsubscribe(Action action) { bool isSuccessful = false; lock (_lock) { for (int index = 0; index < _entries.Count; index++) { Entry entry = _entries[index]; if (entry.Delegate as Action != action || !_entries.Contains(entry)) { continue; } _entries.Remove(entry); isSuccessful = true; } } return isSuccessful; } public void Fire(T signal) { int hashCode = typeof(T).GetHashCode(); lock (_lock) { for (int index = 0; index < _entries.Count; index++) { Entry entry = _entries[index]; if (entry.TypeHashCode != hashCode) { continue; } if (!entry.IsAsync) { ((Action)entry.Delegate).Invoke(signal); continue; } ((Func)entry.Delegate).Invoke(signal); } } } public async Task FireAsync(T signal) { await Task.Factory.StartNew(() => Fire(signal)); } public bool Exists(Action action) { lock (_lock) { for (int index = 0; index < _entries.Count; index++) { if (_entries[index].Delegate.Equals(action)) { return true; } } } return false; } public bool Exists(Func func) { lock (_lock) { for (int index = 0; index < _entries.Count; index++) { if (_entries[index].Delegate.Equals(func)) { return true; } } } return false; } private readonly struct Entry : IEquatable { public readonly Delegate Delegate; public readonly int TypeHashCode; public readonly bool IsAsync; public Entry(Delegate @delegate, Type type, bool isAsync) { Delegate = @delegate; IsAsync = isAsync; TypeHashCode = type.GetHashCode(); } public bool Equals(Entry other) { return Equals(Delegate, other.Delegate) && TypeHashCode == other.TypeHashCode; } public override bool Equals(object obj) { return obj is Entry other && Equals(other); } public override int GetHashCode() { unchecked { return ((Delegate != null ? Delegate.GetHashCode() : 0) * 397) ^ TypeHashCode; } } } } }