All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xdean.jex.extra.rx2.RxIterator Maven / Gradle / Ivy

The newest version!
package xdean.jex.extra.rx2;

import static xdean.jex.util.lang.ExceptionUtil.uncheck;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.LinkedBlockingQueue;

import org.reactivestreams.Subscription;

import io.reactivex.Flowable;
import io.reactivex.Notification;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
import io.reactivex.annotations.SchedulerSupport;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

/**
 * Convert RxStream to Iterator.
 *
 * @author XDean, Michael@stackoverflow
 *
 */
public class RxIterator {
  public static  Function, Iterator> flowableIterator() {
    return o -> toIterator(o);
  }

  public static  Iterator toIterator(Flowable ob) {
    return new FlowableIterator<>(ob);
  }

  public static  Function, Iterator> observableIterator(Scheduler scheduler) {
    return o -> toIterator(o, scheduler);
  }

  public static  Function, Iterator> observableIterator() {
    return o -> toIterator(o);
  }

  public static  Iterator toIterator(Observable ob, Scheduler scheduler) {
    return new ObservableIterator<>(ob, scheduler);
  }

  @SchedulerSupport(SchedulerSupport.IO)
  public static  Iterator toIterator(Observable ob) {
    return toIterator(ob, Schedulers.io());
  }

  public static final class ObservableIterator implements Iterator {
    private LinkedBlockingQueue> queue = new LinkedBlockingQueue<>();
    private Notification next = null;
    private boolean completed = false;

    public ObservableIterator(Observable source, Scheduler scheduler) {
      source
          .materialize()
          .subscribeOn(scheduler)
          .subscribe(queue::put);
    }

    @Override
    public boolean hasNext() {
      calcNext();
      return !completed;
    }

    @Override
    public T next() {
      calcNext();
      if (next == null) {
        throw new NoSuchElementException();
      }
      T t = next.getValue();
      next = null;
      return t;
    }

    private void calcNext() {
      if (completed) {
        return;
      }
      if (next == null) {
        Notification take = uncheck(queue::take);
        if (take.isOnNext()) {
          next = take;
        } else if (take.isOnError()) {
          completed = true;
          throw new RuntimeException(take.getError());
        } else {
          completed = true;
        }
      }
    }
  }

  public static final class FlowableIterator implements Iterator {
    private Notification next = null;
    private LinkedBlockingQueue> queue = new LinkedBlockingQueue<>(1);
    private boolean completed = false;
    private Subscription subscription;

    public FlowableIterator(Flowable source) {
      source
          .materialize()
          .subscribe(
              e -> queue.put(e),
              e -> completed = true,
              () -> completed = true,
              s -> this.subscription = s
          );
    }

    @Override
    public boolean hasNext() {
      calcNext();
      return !completed;
    }

    @Override
    public T next() {
      calcNext();
      if (next == null) {
        throw new NoSuchElementException();
      }
      T t = next.getValue();
      next = null;
      return t;
    }

    private void calcNext() {
      if (completed) {
        return;
      }
      if (next == null) {
        subscription.request(1);
        Notification take = uncheck(() -> queue.take());
        if (take.isOnNext()) {
          next = take;
        } else if (take.isOnError()) {
          completed = true;
          throw new RuntimeException(take.getError());
        } else {
          completed = true;
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy