docs: public static <T, X extends Throwable> Tuple3<CompletableFuture<Subscription>, Runnable, CompletableFuture<Boolean>> forEachEvent(
              final Stream<T> stream, final Consumer<? super T> consumerElement, final Consumer<? super Throwable> consumerError,
              final Runnable onComplete) {
  
          final CompletableFuture<Subscription> subscription = new CompletableFuture<>();
          final CompletableFuture<Boolean> streamCompleted = new CompletableFuture<>();
          return tuple(subscription, () -> {
              final Iterator<T> it = stream.iterator();
              final Object UNSET = new Object();
              Streams.stream(new Iterator<T>() {
                  boolean errored = false;
  
                  @Override
                  public boolean hasNext() {
                      boolean result = false;
                      try {
                          result = it.hasNext();
  
                          return result;
                      } catch (final Throwable t) {
  
                          consumerError.accept(t);
  
                          errored = true;
                          return true;
                      } finally {
                          if (!result && !errored) {
                              try {
                                  onComplete.run();
                              } finally {
                                  streamCompleted.complete(true);
                              }
                          }
                      }
                  }
  
                  @Override
                  public T next() {
                      try {
                          if (errored)
                              return (T) UNSET;
                          else {
                              try {
                                  return it.next();
                              }catch(Throwable t){
                                  consumerError.accept(t);
                                  return (T) UNSET;
                              }
                          }
                      } finally {
                          errored = false;
                      }
                  }
  
              })
                         .filter(t -> t != UNSET)
                         .forEach(consumerElement);
          } , streamCompleted);
      }