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(); }