package dev.tommyjs.futur.promise;
import dev.tommyjs.futur.function.ExceptionalConsumer;
import dev.tommyjs.futur.function.ExceptionalFunction;
import dev.tommyjs.futur.function.ExceptionalRunnable;
import dev.tommyjs.futur.function.ExceptionalSupplier;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
*
* A promise represents the result of an asynchronous computation. A promise will transition from a
* pending state to a completed state at most once, but may remain in a pending state indefinitely.
*
*
*
* Promises are created by a {@link PromiseFactory} and support chaining operations to be executed
* upon completion. These operations can be synchronous or asynchronous, and can be composed in a
* variety of ways. Promises can be listened to for completions, either with a result or with an
* exception. Promises can be cancelled, which will propagate a cancellation signal through the
* chain, but a promise can also be forked, which will prevent propagation of cancellations.
*
*
* @see #cancel()
* @see #fork()
*/
public interface Promise {
/**
* Returns the factory that created this promise. This factory can be used to create new promises.
*/
@NotNull PromiseFactory getFactory();
/**
* Chains a task to be executed after this promise completes. The task will be executed immediately
* when this promise completes. Cancelling the returned promise will cancel this promise, and
* consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenRun(@NotNull ExceptionalRunnable task);
/**
* Chains a task to be executed after this promise completes. The task will be executed immediately
* when this promise completes and will be passed the result of this promise. Cancelling the returned
* promise will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenConsume(@NotNull ExceptionalConsumer task);
/**
* Chains a task to be executed after this promise completes. The task will be executed immediately
* when this promise completes, and will supply a value to the next promise in the chain. Cancelling
* the returned promise will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenSupply(@NotNull ExceptionalSupplier task);
/**
* Chains a task to be executed after this promise completes. The task will be executed immediately
* when this promise completes, and will apply the specified function to the result of this promise
* in order to supply a value to the next promise in the chain. Cancelling the returned promise will
* cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenApply(@NotNull ExceptionalFunction task);
/**
* Chains a task to be executed after this promise completes. The task will be executed immediately
* when this promise completes, and will compose the next promise in the chainfrom the result of
* this promise. Cancelling the returned promise will cancel this promise, and consequently any
* previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, once this promise and the promise returned by
* the task are complete, with the result of the task promise
*/
@NotNull Promise thenCompose(@NotNull ExceptionalFunction> task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* sync executor of the factory that created this promise, immediately after this promise completes.
* Cancelling the returned promise will cancel this promise, and consequently any previous promises
* in the chain.
*
* @param task the task to execute
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenRunSync(@NotNull ExceptionalRunnable task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* sync executor of the factory that created this promise, after the specified delay after this
* promise completes. Cancelling the returned promise will cancel this promise, and consequently
* any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenRunDelayedSync(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* sync executor of the factory that created this promise immediately after this promise completes,
* and will be passed the result of this promise. Cancelling the returned promise will cancel this
* promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenConsumeSync(@NotNull ExceptionalConsumer task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* sync executor of the factory that created this promise after the specified delay after this
* promise completes, and will be passed the result of this promise. Cancelling the returned promise
* will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenConsumeDelayedSync(@NotNull ExceptionalConsumer task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed immediately
* by the sync executor of the factory that created this promise when this promise completes, and
* will supply a value to the next promise in the chain. Cancelling the returned promise will cancel
* this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenSupplySync(@NotNull ExceptionalSupplier task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the sync
* executor of the factory that created this promise after the specified delay after this promise
* completes, and will supply a value to the next promise in the chain. Cancelling the returned promise
* will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenSupplyDelayedSync(@NotNull ExceptionalSupplier task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the sync
* executor of the factory that created this promise immediately after this promise completes, and
* will apply the specified function to the result of this promise in order to supply a value to the
* next promise in the chain. Cancelling the returned promise will cancel this promise, and consequently
* any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenApplySync(@NotNull ExceptionalFunction task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the sync
* executor of the factory that created this promise after the specified delay after this promise
* completes, and will apply the specified function to the result of this promise in order to supply
* a value to the next promise in the chain. Cancelling the returned promise will cancel this promise,
* and consequently any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenApplyDelayedSync(@NotNull ExceptionalFunction task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the sync
* executor of the factory that created this promise immediately after this promise completes, and
* will compose the next promise in the chain from the result of this promise. Cancelling the returned
* promise will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, once this promise and the promise returned by the task are
* complete, with the result of the task promise
*/
@NotNull Promise thenComposeSync(@NotNull ExceptionalFunction> task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* async executor of the factory that created this promise, immediately after this promise completes.
* Cancelling the returned promise will cancel this promise, and consequently any previous promises
* in the chain.
*
* @param task the task to execute
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenRunAsync(@NotNull ExceptionalRunnable task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* async executor of the factory that created this promise after the specified delay after this
* promise completes. Cancelling the returned promise will cancel this promise, and consequently
* any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenRunDelayedAsync(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* async executor of the factory that created this promise immediately after this promise completes,
* and will be passed the result of this promise. Cancelling the returned promise will cancel this
* promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenConsumeAsync(@NotNull ExceptionalConsumer task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* async executor of the factory that created this promise after the specified delay after this
* promise completes, and will be passed the result of this promise. Cancelling the returned promise
* will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes after the task is executed
*/
@NotNull Promise thenConsumeDelayedAsync(@NotNull ExceptionalConsumer task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the
* async executor of the factory that created this promise immediately after this promise completes,
* and will supply a value to the next promise in the chain. Cancelling the returned promise will
* cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenSupplyAsync(@NotNull ExceptionalSupplier task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the async
* executor of the factory that created this promise after the specified delay after this promise
* completes, and will supply a value to the next promise in the chain. Cancelling the returned promise
* will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenSupplyDelayedAsync(@NotNull ExceptionalSupplier task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the async
* executor of the factory that created this promise immediately after this promise completes, and
* will apply the specified function to the result of this promise in order to supply a value to the
* next promise in the chain. Cancelling the returned promise will cancel this promise, and consequently
* any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenApplyAsync(@NotNull ExceptionalFunction task);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the async
* executor of the factory that created this promise after the specified delay after this promise
* completes, and will apply the specified function to the result of this promise in order to supply
* a value to the next promise in the chain. Cancelling the returned promise will cancel this promise,
* and consequently any previous promises in the chain.
*
* @param task the task to execute
* @param delay the amount of time to wait before executing the task
* @param unit the time unit of the delay
* @return a new promise that completes, after the task is executed, with the task result
*/
@NotNull Promise thenApplyDelayedAsync(@NotNull ExceptionalFunction task, long delay, @NotNull TimeUnit unit);
/**
* Chains a task to be executed after this promise completes. The task will be executed by the async
* executor of the factory that created this promise immediately after this promise completes, and
* will compose the next promise in the chain from the result of this promise. Cancelling the returned
* promise will cancel this promise, and consequently any previous promises in the chain.
*
* @param task the task to execute
* @return a new promise that completes, once this promise and the promise returned by the task are
* complete, with the result of the task promise
*/
@NotNull Promise thenComposeAsync(@NotNull ExceptionalFunction> task);
/**
* Adds a listener to this promise that will populate the specified reference with the result of this
* promise upon successful completion. The reference will not be populated if this promise completes
* exceptionally.
*
* @param reference the reference to populate
* @return continuation of the promise chain
*/
@NotNull Promise thenPopulateReference(@NotNull AtomicReference reference);
/**
* Returns a promise backed by this promise that will complete with {@code null} if this promise
* completes successfully, or with the exception if this promise completes exceptionally. Cancelling
* the returned promise will cancel this promise, and consequently any previous promises in the chain.
*/
@NotNull Promise erase();
/**
* Logs any exceptions that occur in the promise chain with the specified message. The stack trace
* will be captured immediately when invoking this method, and logged alongside an exception if
* encountered, to allow for easier debugging.
*
* @param message the message to log
* @return continuation of the promise chain
*/
@NotNull Promise logExceptions(@NotNull String message);
/**
* Logs any exceptions that occur in the promise chain. The stack trace will be captured immediately
* when invoking this method, and logged alongside an exception if encountered, to allow for easier
* debugging.
*
* @return continuation of the promise chain
*/
default @NotNull Promise logExceptions() {
return logExceptions("Exception caught in promise chain");
}
/**
* Adds a listener to this promise that will be executed immediately when this promise completes,
* on the same thread as the completion call.
*
* @param listener the listener to add
* @return continuation of the promise chain
*/
@NotNull Promise addDirectListener(@NotNull PromiseListener listener);
/**
* Adds a listener to this promise that will be executed immediately when this promise completes,
* on the same thread as the completion call. One of {@code successHandler} and {@code errorHandler} will be
* called when the promise completes successfully or exceptionally, respectively.
*
* @param successHandler the function to call on success
* @param errorHandler the function to call on error
* @return continuation of the promise chain
*/
@NotNull Promise addDirectListener(@Nullable Consumer successHandler, @Nullable Consumer errorHandler);
/**
* Adds a listener to this promise that will be executed immediately when this promise completes,
* by the async executor of the factory that created this promise.
*
* @param listener the listener to add
* @return continuation of the promise chain
*/
@NotNull Promise addAsyncListener(@NotNull AsyncPromiseListener listener);
/**
* Adds a listener to this promise that will be executed immediately when this promise completes.
*
* @param listener the listener to add
* @return continuation of the promise chain
*/
default @NotNull Promise addListener(@NotNull AsyncPromiseListener listener) {
return addAsyncListener(listener);
}
/**
* Adds a listener to this promise that will be executed immediately when this promise completes,
* by the async executor of the factory that created this promise. One of {@code successHandler} and
* {@code errorHandler} will be called when the promise completes successfully or exceptionally, respectively.
*
* @param successHandler the function to call on success
* @param errorHandler the function to call on error
*/
@NotNull Promise addAsyncListener(@Nullable Consumer successHandler, @Nullable Consumer errorHandler);
/**
* Adds a listener to this promise that will be called if the promise is completed successfully.
*
* @param listener the listener to add
* @return continuation of the promise chain
*/
@NotNull Promise onSuccess(@NotNull Consumer listener);
/**
* Adds a listener to this promise that will be called if the promise is completed exceptionally.
*
* @param listener the listener to add
* @return continuation of the promise chain
*/
@NotNull Promise onError(@NotNull Consumer listener);
/**
* Adds a listener to this promise that will be called if the promise is completed exceptionally
* with an exception of the specified type.
*
* @param listener the listener to add
* @param type the class of the exception to listen for
* @return continuation of the promise chain
*/
@NotNull Promise onError(@NotNull Class type, @NotNull Consumer listener);
/**
* Adds a listener to this promise that will be called if the promise is cancelled.
*
* @param listener the listener to add
* @return continuation of the promise chain
*/
@NotNull Promise onCancel(@NotNull Consumer listener);
/**
* Cancels the promise if not already completed after the specified timeout. This will result in
* an exceptional completion with a {@link CancellationException}.
*
* @param time the amount of time to wait before cancelling the promise
* @param unit the time unit of the delay
* @return continuation of the promise chain
*/
@NotNull Promise timeout(long time, @NotNull TimeUnit unit);
/**
* Cancels the promise if not already completed after the specified timeout. This will result in
* an exceptional completion with a {@link CancellationException}.
*
* @param ms the amount of time to wait before cancelling the promise (in milliseconds)
* @return continuation of the promise chain
*/
default @NotNull Promise timeout(long ms) {
return timeout(ms, TimeUnit.MILLISECONDS);
}
/**
* Times out the promise if not already completed after the specified timeout. This will result
* in an exceptional completion with a {@link TimeoutException}. This will not result in the
* promise being cancelled.
*
* @param time the amount of time to wait before timing out the promise
* @param unit the time unit of the delay
* @return continuation of the promise chain
*/
@NotNull Promise maxWaitTime(long time, @NotNull TimeUnit unit);
/**
* Times out the promise if not already completed after the specified timeout. This will result
* in an exceptional completion with a {@link TimeoutException}. This will not result in the
* promise being cancelled.
*
* @param ms the amount of time to wait before timing out the promise (in milliseconds)
* @return continuation of the promise chain
*/
default @NotNull Promise maxWaitTime(long ms) {
return maxWaitTime(ms, TimeUnit.MILLISECONDS);
}
/**
* Cancels the promise if not already completed after the specified timeout. This will result in
* an exceptional completion with the specified cancellation.
*
* @param exception the cancellation exception to complete the promise with
*/
void cancel(@NotNull CancellationException exception);
/**
* Cancels the promise if not already completed after the specified timeout. This will result in
* an exceptional completion with a {@link CancellationException}.
*
* @param reason the reason for the cancellation
*/
default void cancel(@NotNull String reason) {
cancel(new CancellationException(reason));
}
/**
* Cancels the promise if not already completed after the specified timeout. This will result in
* an exceptional completion with a {@link CancellationException}.
*/
default void cancel() {
cancel(new CancellationException());
}
/**
* Blocks until this promise has completed, and then returns its result.
*
* @return the result of the promise
* @throws CancellationException if the promise was cancelled
* @throws CompletionException if the promise completed exceptionally
*/
@Blocking
T await();
/**
* Blocks until this promise has completed, and then returns its result.
*
* @return the result of the promise
* @throws CancellationException if the promise was cancelled
* @throws ExecutionException if the promise completed exceptionally
* @throws InterruptedException if the current thread was interrupted while waiting
*/
@Blocking
T get() throws InterruptedException, ExecutionException;
/**
* Blocks until either this promise has completed or the timeout has been exceeded, and then
* returns its result, if available.
*
* @return the result of the promise
* @throws CancellationException if the promise was cancelled
* @throws ExecutionException if the promise completed exceptionally
* @throws InterruptedException if the current thread was interrupted while waiting
* @throws TimeoutException if the timeout was exceeded
*/
@Blocking
T get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
/**
* Returns a new promise, backed by this promise, that will not propagate cancellations. This means
* that if the returned promise is cancelled, the cancellation will not be propagated to this promise,
* and consequently any previous promises in the chain.
*
* @return continuation the promise chain that will not propagate cancellations
*/
@NotNull Promise fork();
/**
* Returns the current completion state of this promise. If the promise has not completed, this method
* will return {@code null}.
*
* @return the completion state of this promise, or {@code null} if the promise has not completed
*/
@Nullable PromiseCompletion getCompletion();
/**
* Returns whether this promise has completed.
*
* @return {@code true} if the promise has completed, {@code false} otherwise
*/
boolean isCompleted();
/**
* Converts this promise to a {@link CompletableFuture}. The returned future will complete with the
* result of this promise when it completes.
*
* @return a future that will complete with the result of this promise
*/
@NotNull CompletableFuture toFuture();
}