123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- using System;
- using System.Threading;
- namespace Cysharp.Threading.Tasks
- {
- public interface ITriggerHandler<T>
- {
- void OnNext(T value);
- void OnError(Exception ex);
- void OnCompleted();
- void OnCanceled(CancellationToken cancellationToken);
- // set/get from TriggerEvent<T>
- ITriggerHandler<T> Prev { get; set; }
- ITriggerHandler<T> Next { get; set; }
- }
- // be careful to use, itself is struct.
- public struct TriggerEvent<T>
- {
- ITriggerHandler<T> head; // head.prev is last
- ITriggerHandler<T> iteratingHead;
- bool preserveRemoveSelf;
- ITriggerHandler<T> iteratingNode;
- void LogError(Exception ex)
- {
- #if UNITY_2018_3_OR_NEWER
- UnityEngine.Debug.LogException(ex);
- #else
- Console.WriteLine(ex);
- #endif
- }
- public void SetResult(T value)
- {
- if (iteratingNode != null)
- {
- throw new InvalidOperationException("Can not trigger itself in iterating.");
- }
- var h = head;
- while (h != null)
- {
- iteratingNode = h;
- try
- {
- h.OnNext(value);
- }
- catch (Exception ex)
- {
- LogError(ex);
- Remove(h);
- }
- if (preserveRemoveSelf)
- {
- preserveRemoveSelf = false;
- iteratingNode = null;
- var next = h.Next;
- Remove(h);
- h = next;
- }
- else
- {
- h = h.Next;
- }
- }
- iteratingNode = null;
- if (iteratingHead != null)
- {
- Add(iteratingHead);
- iteratingHead = null;
- }
- }
- public void SetCanceled(CancellationToken cancellationToken)
- {
- if (iteratingNode != null)
- {
- throw new InvalidOperationException("Can not trigger itself in iterating.");
- }
- var h = head;
- while (h != null)
- {
- iteratingNode = h;
- try
- {
- h.OnCanceled(cancellationToken);
- }
- catch (Exception ex)
- {
- LogError(ex);
- }
- preserveRemoveSelf = false;
- iteratingNode = null;
- var next = h.Next;
- Remove(h);
- h = next;
- }
- iteratingNode = null;
- if (iteratingHead != null)
- {
- Add(iteratingHead);
- iteratingHead = null;
- }
- }
- public void SetCompleted()
- {
- if (iteratingNode != null)
- {
- throw new InvalidOperationException("Can not trigger itself in iterating.");
- }
- var h = head;
- while (h != null)
- {
- iteratingNode = h;
- try
- {
- h.OnCompleted();
- }
- catch (Exception ex)
- {
- LogError(ex);
- }
- preserveRemoveSelf = false;
- iteratingNode = null;
- var next = h.Next;
- Remove(h);
- h = next;
- }
- iteratingNode = null;
- if (iteratingHead != null)
- {
- Add(iteratingHead);
- iteratingHead = null;
- }
- }
- public void SetError(Exception exception)
- {
- if (iteratingNode != null)
- {
- throw new InvalidOperationException("Can not trigger itself in iterating.");
- }
- var h = head;
- while (h != null)
- {
- iteratingNode = h;
- try
- {
- h.OnError(exception);
- }
- catch (Exception ex)
- {
- LogError(ex);
- }
- preserveRemoveSelf = false;
- iteratingNode = null;
- var next = h.Next;
- Remove(h);
- h = next;
- }
- iteratingNode = null;
- if (iteratingHead != null)
- {
- Add(iteratingHead);
- iteratingHead = null;
- }
- }
- public void Add(ITriggerHandler<T> handler)
- {
- if (handler == null) throw new ArgumentNullException(nameof(handler));
- // zero node.
- if (head == null)
- {
- head = handler;
- return;
- }
- if (iteratingNode != null)
- {
- if (iteratingHead == null)
- {
- iteratingHead = handler;
- return;
- }
- var last = iteratingHead.Prev;
- if (last == null)
- {
- // single node.
- iteratingHead.Prev = handler;
- iteratingHead.Next = handler;
- handler.Prev = iteratingHead;
- }
- else
- {
- // multi node
- iteratingHead.Prev = handler;
- last.Next = handler;
- handler.Prev = last;
- }
- }
- else
- {
- var last = head.Prev;
- if (last == null)
- {
- // single node.
- head.Prev = handler;
- head.Next = handler;
- handler.Prev = head;
- }
- else
- {
- // multi node
- head.Prev = handler;
- last.Next = handler;
- handler.Prev = last;
- }
- }
- }
- public void Remove(ITriggerHandler<T> handler)
- {
- if (handler == null) throw new ArgumentNullException(nameof(handler));
- if (iteratingNode != null && iteratingNode == handler)
- {
- // if remove self, reserve remove self after invoke completed.
- preserveRemoveSelf = true;
- }
- else
- {
- var prev = handler.Prev;
- var next = handler.Next;
- if (next != null)
- {
- next.Prev = prev;
- }
- if (handler == head)
- {
- head = next;
- }
- else if (handler == iteratingHead)
- {
- iteratingHead = next;
- }
- else
- {
- // when handler is head, prev indicate last so don't use it.
- if (prev != null)
- {
- prev.Next = next;
- }
- }
- if (head != null)
- {
- if (head.Prev == handler)
- {
- if (prev != head)
- {
- head.Prev = prev;
- }
- else
- {
- head.Prev = null;
- }
- }
- }
- if (iteratingHead != null)
- {
- if (iteratingHead.Prev == handler)
- {
- if (prev != iteratingHead.Prev)
- {
- iteratingHead.Prev = prev;
- }
- else
- {
- iteratingHead.Prev = null;
- }
- }
- }
- handler.Prev = null;
- handler.Next = null;
- }
- }
- }
- }
|