internal void InnerError(long index, SwitchMapInnerSubscriber inner, Exception ex) { if (Volatile.Read(ref this.index) == index) { if (ExceptionHelper.AddError(ref error, ex)) { s.Cancel(); inner.SetDone(); Drain(); return; } } ExceptionHelper.OnErrorDropped(ex); }
public void OnNext(T t) { if (done) { return; } long idx = Interlocked.Increment(ref index); var current = Volatile.Read(ref inner); current?.Cancel(); IPublisher <R> p; try { p = mapper(t); if (p == null) { throw new NullReferenceException("The mapper returned a null IPublisher"); } } catch (Exception ex) { ExceptionHelper.ThrowIfFatal(ex); s.Cancel(); if (ExceptionHelper.AddError(ref error, ex)) { Volatile.Write(ref done, true); Drain(); } else { Volatile.Write(ref done, true); ExceptionHelper.OnErrorDropped(ex); } return; } var inr = new SwitchMapInnerSubscriber(this, prefetch, idx); if (Interlocked.CompareExchange(ref inner, inr, current) == current) { p.Subscribe(inr); } }
internal void Drain() { if (!QueueDrainHelper.Enter(ref wip)) { return; } int missed = 1; var a = actual; for (;;) { long r = Volatile.Read(ref requested); long e = 0L; while (e != r) { if (Volatile.Read(ref cancelled)) { inner = null; return; } Exception ex = Volatile.Read(ref error); if (ex != null) { ex = ExceptionHelper.Terminate(ref error); inner = null; a.OnError(ex); return; } bool d = Volatile.Read(ref done); var inr = Volatile.Read(ref inner); d = d && (inr == null || inr.IsDone()); R v; bool empty; if (inr != null) { try { empty = !inr.queue.Poll(out v); } catch (Exception exc) { ExceptionHelper.ThrowIfFatal(exc); ExceptionHelper.AddError(ref error, exc); s.Cancel(); inner = null; exc = ExceptionHelper.Terminate(ref error); a.OnError(exc); return; } } else { v = default(R); empty = true; } if (d && empty) { inner = null; a.OnComplete(); return; } if (empty) { break; } a.OnNext(v); e++; inner.RequestOne(); } if (e == r) { if (Volatile.Read(ref cancelled)) { inner = null; return; } Exception ex = Volatile.Read(ref error); if (ex != null) { ex = ExceptionHelper.Terminate(ref error); inner = null; a.OnError(ex); return; } bool d = Volatile.Read(ref done); var inr = Volatile.Read(ref inner); d = d && (inr == null || inr.IsDone()); bool empty = inr == null || inr.queue.IsEmpty(); if (d && empty) { inner = null; a.OnComplete(); return; } } if (e != 0L && r != long.MaxValue) { Interlocked.Add(ref requested, -e); } missed = QueueDrainHelper.Leave(ref wip, missed); if (missed == 0) { break; } } }