package com.github.davidmoten.rx.internal.operators; import java.util.concurrent.atomic.AtomicBoolean; import rx.Observable; import rx.Observable.OnSubscribe; import rx.exceptions.Exceptions; import rx.exceptions.OnErrorThrowable; import rx.Producer; import rx.Subscriber; import rx.functions.Func1; public final class OnSubscribeMapLast<T> implements OnSubscribe<T> { private final Observable<T> source; private final Func1<? super T, ? extends T> function; public OnSubscribeMapLast(Observable<T> source, Func1<? super T, ? extends T> function) { this.source = source; this.function = function; } @Override public void call(Subscriber<? super T> child) { final MapLastSubscriber<T> parent = new MapLastSubscriber<T>(child, function); child.add(parent); child.setProducer(new Producer() { @Override public void request(long n) { parent.requestMore(n); } }); source.unsafeSubscribe(parent); } private final static class MapLastSubscriber<T> extends Subscriber<T> { private static final Object EMPTY = new Object(); private final Subscriber<? super T> child; private final Func1<? super T, ? extends T> function; private final AtomicBoolean firstRequest = new AtomicBoolean(true); @SuppressWarnings("unchecked") private T value = (T) EMPTY; public MapLastSubscriber(Subscriber<? super T> child, Func1<? super T, ? extends T> function) { this.child = child; this.function = function; } public void requestMore(long n) { if (n < 0) { throw new IllegalArgumentException("cannot request negative amount"); } else if (n == 0) { return; } else if (firstRequest.compareAndSet(true, false)) { long m = n + 1; if (m < 0) { m = Long.MAX_VALUE; } request(m); } else { request(n); } } @Override public void onCompleted() { if (value != EMPTY) { T value2; try { value2 = function.call(value); } catch (Throwable e) { Exceptions.throwIfFatal(e); onError(OnErrorThrowable.addValueAsLastCause(e, value)); return; } child.onNext(value2); } child.onCompleted(); } @Override public void onError(Throwable e) { if (value != EMPTY) { child.onNext(value); } child.onError(e); } @Override public void onNext(T t) { if (value == EMPTY) { value = t; } else { child.onNext(value); value = t; } } } }