/// <summary> /// Subscribes the given completable observer to this subject /// and relays/replays the terminal events of the subject. /// </summary> /// <param name="observer">The completable observer that wants to listen to the terminal events.</param> public void Subscribe(ISingleObserver <T> observer) { var inner = new InnerDisposable(observer, this); observer.OnSubscribe(inner); if (Add(inner)) { if (inner.IsDisposed()) { Remove(inner); } } else { if (!inner.IsDisposed()) { var ex = Volatile.Read(ref error); if (ex == null) { observer.OnSuccess(value); } else { observer.OnError(ex); } } } }
/// <summary> /// Subscribes the given completable observer to this subject /// and relays/replays the terminal events of the subject. /// </summary> /// <param name="observer">The completable observer that wants to listen to the terminal events.</param> public void Subscribe(ICompletableObserver observer) { var inner = new InnerDisposable(observer, this); observer.OnSubscribe(inner); if (Add(inner)) { if (inner.IsDisposed()) { Remove(inner); } } else { if (!inner.IsDisposed()) { var ex = Volatile.Read(ref error); if (ex == ExceptionHelper.TERMINATED) { observer.OnCompleted(); } else { observer.OnError(ex); } } } }
void Remove(InnerDisposable inner) { for (; ;) { var a = Volatile.Read(ref observers); var n = a.Length; if (n == 0) { break; } var j = -1; for (int i = 0; i < n; i++) { if (a[i] == inner) { j = i; break; } } if (j < 0) { break; } var b = default(InnerDisposable[]); if (n == 1) { if (refCount) { if (Interlocked.CompareExchange(ref once, 1, 0) == 0) { this.error = new OperationCanceledException(); if (Interlocked.CompareExchange(ref observers, TERMINATED, a) == a) { DisposableHelper.Dispose(ref upstream); break; } } continue; } else { b = EMPTY; } } else { b = new InnerDisposable[n - 1]; Array.Copy(a, 0, b, 0, j); Array.Copy(a, j + 1, b, j, n - j - 1); } if (Interlocked.CompareExchange(ref observers, b, a) == a) { break; } } }
public void Subscribe(ICompletableObserver observer) { var inner = new InnerDisposable(observer, this); observer.OnSubscribe(inner); if (Add(inner)) { if (inner.IsDisposed()) { Remove(inner); } } else { if (!inner.IsDisposed()) { var ex = Volatile.Read(ref error); if (ex == ExceptionHelper.TERMINATED) { observer.OnCompleted(); } else { observer.OnError(ex); } } return; } var src = Volatile.Read(ref source); if (src != null) { src = Interlocked.Exchange(ref source, null); if (src != null) { var a = cancel; cancel = null; a?.Invoke(this); src.Subscribe(this); } } }
void Remove(InnerDisposable inner) { for (; ;) { var a = Volatile.Read(ref observers); var n = a.Length; if (n == 0) { break; } var j = -1; for (int i = 0; i < n; i++) { if (a[i] == inner) { j = i; break; } } if (j < 0) { break; } var b = default(InnerDisposable[]); if (n == 1) { b = EMPTY; } else { b = new InnerDisposable[n - 1]; Array.Copy(a, 0, b, 0, j); Array.Copy(a, j + 1, b, j, n - j - 1); } if (Interlocked.CompareExchange(ref observers, b, a) == a) { break; } } }
bool Add(InnerDisposable inner) { for (; ;) { var a = Volatile.Read(ref observers); if (a == TERMINATED) { return(false); } var n = a.Length; var b = new InnerDisposable[n + 1]; Array.Copy(a, 0, b, 0, n); b[n] = inner; if (Interlocked.CompareExchange(ref observers, b, a) == a) { return(true); } } }