com.github.tonivade.purefun.concurrent.Future Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2019, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.concurrent;
import static com.github.tonivade.purefun.Function1.cons;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.time.Duration;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.github.tonivade.purefun.CheckedProducer;
import com.github.tonivade.purefun.CheckedRunnable;
import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Consumer2;
import com.github.tonivade.purefun.Filterable;
import com.github.tonivade.purefun.FlatMap1;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Higher1;
import com.github.tonivade.purefun.Holder;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Matcher1;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.type.Try;
public interface Future extends FlatMap1, Holder, Filterable {
Executor DEFAULT_EXECUTOR = Executors.newCachedThreadPool();
final class µ implements Kind {}
Try await();
Try await(Duration timeout);
void cancel(boolean mayInterruptThread);
boolean isCompleted();
boolean isCancelled();
default boolean isSuccess() {
return await().isSuccess();
}
default boolean isFailure() {
return await().isFailure();
}
Future onSuccess(Consumer1 callback);
Future onFailure(Consumer1 callback);
Future onComplete(Consumer1> callback);
@Override
Future map(Function1 mapper);
@Override
Future flatMap(Function1> mapper);
Future andThen(Future next);
@Override
Future filter(Matcher1 matcher);
Future orElse(Future other);
@Override
default T get() {
return getOrElseThrow(NoSuchElementException::new);
}
default T getOrElse(T value) {
return getOrElse(Producer.cons(value));
}
default T getOrElse(Producer value) {
return await().getOrElse(value);
}
default T getOrElseThrow(Producer producer) throws X {
return await().getOrElseThrow(producer);
}
default Throwable getCause() {
return await().getCause();
}
@Override
@SuppressWarnings("unchecked")
default Future flatten() {
return flatMap(value -> {
try {
return (Future) value;
} catch (ClassCastException e) {
return Future.failure(new UnsupportedOperationException(e));
}
});
}
Future recover(Function1 mapper);
Future recoverWith(Class type, Function1 mapper);
Future fold(Function1 failureMapper, Function1 successMapper);
default CompletableFuture toCompletableFuture() {
CompletableFuture completableFuture = new CompletableFuture<>();
onSuccess(completableFuture::complete);
onFailure(completableFuture::completeExceptionally);
return completableFuture;
}
Promise toPromise();
FutureModule getModule();
static Future success(T value) {
return success(DEFAULT_EXECUTOR, value);
}
static Future success(Executor executor, T value) {
return FutureImpl.sync(executor, () -> Try.success(value));
}
static Future failure(Throwable error) {
return failure(DEFAULT_EXECUTOR, error);
}
static Future failure(Executor executor, Throwable error) {
return FutureImpl.sync(executor, () -> Try.failure(error));
}
static Future from(Callable callable) {
return run(callable::call);
}
static Future from(java.util.concurrent.Future future) {
return run(future::get);
}
static Future run(CheckedProducer task) {
return run(DEFAULT_EXECUTOR, task);
}
static Future run(Executor executor, CheckedProducer task) {
return FutureImpl.async(executor, task.liftTry());
}
static Future exec(CheckedRunnable task) {
return exec(DEFAULT_EXECUTOR, task);
}
static Future exec(Executor executor, CheckedRunnable task) {
return run(executor, () -> { task.run(); return Unit.unit(); });
}
static Future delay(Duration timeout, CheckedProducer producer) {
return delay(DEFAULT_EXECUTOR, timeout, producer);
}
static Future delay(Executor executor, Duration timeout, CheckedProducer producer) {
return run(executor, () -> { MILLISECONDS.sleep(timeout.toMillis()); return producer.get(); });
}
static Future defer(CheckedProducer> producer) {
return defer(DEFAULT_EXECUTOR, producer);
}
static Future defer(Executor executor, CheckedProducer> producer) {
return run(executor, () -> producer.get()).flatten();
}
static Future narrowK(Higher1 hkt) {
return (Future) hkt;
}
}
interface FutureModule { }
final class FutureImpl implements Future {
private final Executor executor;
private final Promise promise = Promise.make();
private final Cancellable cancellable = Cancellable.from(promise);
private FutureImpl(Executor executor, Consumer2, Cancellable> task) {
this.executor = requireNonNull(executor);
requireNonNull(task).accept(promise, cancellable);
}
@Override
public Future map(Function1 mapper) {
return transform(executor, this, value -> value.map(mapper));
}
@Override
public Future flatMap(Function1> mapper) {
return chain(executor, this,
value -> value.fold(Future::failure, mapper.andThen(Future::narrowK)));
}
@Override
public Future andThen(Future next) {
return flatMap(ignore -> next);
}
@Override
public Future filter(Matcher1 matcher) {
return transform(executor, this, value -> value.filter(matcher));
}
@Override
public Future orElse(Future other) {
return chain(executor, this, value -> value.fold(cons(other), Future::success));
}
@Override
public Future recover(Function1 mapper) {
return transform(executor, this, value -> value.recover(mapper));
}
@Override
public Future recoverWith(Class type, Function1 mapper) {
return transform(executor, this, value -> value.recoverWith(type, mapper));
}
@Override
public Future fold(Function1 failureMapper, Function1 successMapper) {
return transform(executor, this, value -> Try.success(value.fold(failureMapper, successMapper)));
}
@Override
public Promise toPromise() {
return promise;
}
@Override
public Try await() {
return promise.get();
}
@Override
public Try await(Duration timeout) {
return promise.get(timeout);
}
@Override
public void cancel(boolean mayInterruptThread) {
cancellable.cancel(mayInterruptThread);
}
@Override
public boolean isCompleted() {
return promise.isCompleted();
}
@Override
public boolean isCancelled() {
return cancellable.isCancelled();
}
@Override
public Future onSuccess(Consumer1 callback) {
promise.onComplete(value -> value.onSuccess(callback));
return this;
}
@Override
public Future onFailure(Consumer1 callback) {
promise.onComplete(value -> value.onFailure(callback));
return this;
}
@Override
public Future onComplete(Consumer1> callback) {
promise.onComplete(callback);
return this;
}
@Override
public FutureModule getModule() {
throw new UnsupportedOperationException();
}
static Future sync(Executor executor, Producer> producer) {
return new FutureImpl<>(executor, (promise, cancel) -> promise.tryComplete(producer.get()));
}
static Future transform(Executor executor, Future current, Function1, Try> mapper) {
return new FutureImpl<>(executor,
(promise, cancel) -> current.onComplete(value -> promise.tryComplete(mapper.apply(value))));
}
static Future chain(Executor executor, Future current, Function1, Future> mapper) {
return new FutureImpl<>(executor,
(promise, cancel) -> current.onComplete(value -> mapper.apply(value).onComplete(promise::tryComplete)));
}
static Future async(Executor executor, Producer> producer) {
return new FutureImpl<>(executor,
(promise, cancel) -> executor.execute(() -> { cancel.updateThread(); promise.tryComplete(producer.get()); }));
}
static Future from(Executor executor, Promise promise) {
return new FutureImpl<>(executor, (current, cancel) -> promise.onComplete(current::tryComplete));
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy