From 3af7b90270cf00180d48d46295f4a48c96909309 Mon Sep 17 00:00:00 2001 From: tommyskeff Date: Wed, 28 May 2025 14:34:33 +0100 Subject: [PATCH] finalize changes for 2.5.0 release --- .github/workflows/publish.yml | 26 ++ build.gradle | 33 ++- .../futur/executor/PromiseExecutor.java | 4 +- .../futur/executor/PromiseScheduler.java | 4 +- .../executor/PromiseSchedulerDefault.java | 13 +- .../futur/function/FunctionAdapter.java | 6 +- .../futur/joiner/CompletionJoiner.java | 6 +- .../futur/joiner/MappedResultJoiner.java | 7 +- .../tommyjs/futur/joiner/ResultJoiner.java | 6 +- .../futur/promise/AbstractPromise.java | 264 +++++++++--------- .../futur/promise/AbstractPromiseFactory.java | 46 +-- .../futur/promise/AsyncPromiseListener.java | 1 - .../tommyjs/futur/promise/BasePromise.java | 66 ++--- .../dev/tommyjs/futur/promise/Promise.java | 33 ++- .../futur/promise/PromiseCompletion.java | 16 +- .../tommyjs/futur/promise/PromiseFactory.java | 29 +- .../futur/promise/PromiseFactoryImpl.java | 16 +- 17 files changed, 305 insertions(+), 271 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..1f19ed9 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,26 @@ +name: Build and publish + +on: + push: + branches: + - main + +jobs: + publish: + name: Publish build + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: 23 + + - name: Make Gradle executable + run: chmod +x ./gradlew + + - name: Build and publish project + run: ./gradlew publish -PtommyjsUsername=${{ secrets.NEXUS_USERNAME }} -PtommyjsPassword=${{ secrets.NEXUS_PASSWORD }} diff --git a/build.gradle b/build.gradle index 88740aa..1eb3b4d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,7 @@ plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' -} - -nexusPublishing { - repositories { - tommyjs { - nexusUrl = uri("https://repo.tommyjs.dev/repository/maven-releases") - } - } + id 'maven-publish' } subprojects { @@ -18,6 +10,29 @@ subprojects { apply plugin: 'java-library' apply plugin: 'com.github.johnrengelman.shadow' + apply plugin : 'maven-publish' + + publishing { + publications { + mavenJava(MavenPublication) { + from(components["java"]) + pom { + name = project.name + } + } + } + + repositories { + maven { + name = 'tommyjs' + url = uri("https://repo.tommyjs.dev/repository/maven-releases/") + credentials { + username = findProperty("tommyjsUsername") as String + password = findProperty("tommyjsPassword") as String + } + } + } + } tasks { build { diff --git a/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseExecutor.java b/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseExecutor.java index c883fb3..86bee7b 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseExecutor.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseExecutor.java @@ -73,8 +73,8 @@ public interface PromiseExecutor { * Cancels the given task if possible. This may interrupt the task mid-execution. * * @param task the task - * @return {@code true} if the task was cancelled. {@code false} if the task was already completed - * or could not be cancelled. + * @return {@code true} if the task was cancelled, {@code false} if the task was already completed + * or could not be cancelled */ boolean cancel(@NotNull T task); diff --git a/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseScheduler.java b/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseScheduler.java index dbffd5a..d9fdafc 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseScheduler.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseScheduler.java @@ -28,8 +28,8 @@ public interface PromiseScheduler { * Cancels the given task if possible. This may interrupt the task mid-execution. * * @param task the task - * @return {@code true} if the task was cancelled. {@code false} if the task was already completed - * or could not be cancelled. + * @return {@code true} if the task was cancelled, {@code false} if the task was already completed + * or could not be cancelled */ boolean cancel(@NotNull T task); diff --git a/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseSchedulerDefault.java b/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseSchedulerDefault.java index 950ff5b..bc6c367 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseSchedulerDefault.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/executor/PromiseSchedulerDefault.java @@ -2,17 +2,18 @@ package dev.tommyjs.futur.executor; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; class PromiseSchedulerDefault implements PromiseScheduler> { static final PromiseSchedulerDefault INSTANCE = new PromiseSchedulerDefault(); - private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( - Thread.ofPlatform().name("promise-scheduler").daemon(true).factory()); + private final ScheduledExecutorService executor; + + PromiseSchedulerDefault() { + ThreadFactory factory = Thread.ofPlatform().name("promise-scheduler").daemon(true).factory(); + this.executor = Executors.newSingleThreadScheduledExecutor(factory); + } @Override public @NotNull ScheduledFuture schedule(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) { diff --git a/futur-api/src/main/java/dev/tommyjs/futur/function/FunctionAdapter.java b/futur-api/src/main/java/dev/tommyjs/futur/function/FunctionAdapter.java index 33905e5..fcbc009 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/function/FunctionAdapter.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/function/FunctionAdapter.java @@ -5,21 +5,21 @@ import org.jetbrains.annotations.NotNull; public final class FunctionAdapter { public static @NotNull ExceptionalFunction adapt(@NotNull ExceptionalConsumer consumer) { - return (value) -> { + return value -> { consumer.accept(value); return null; }; } public static @NotNull ExceptionalFunction adapt(@NotNull ExceptionalRunnable runnable) { - return (_) -> { + return _ -> { runnable.run(); return null; }; } public static @NotNull ExceptionalFunction adapt(@NotNull ExceptionalSupplier supplier) { - return (_) -> supplier.get(); + return _ -> supplier.get(); } } diff --git a/futur-api/src/main/java/dev/tommyjs/futur/joiner/CompletionJoiner.java b/futur-api/src/main/java/dev/tommyjs/futur/joiner/CompletionJoiner.java index 82f9539..2faeaf7 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/joiner/CompletionJoiner.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/joiner/CompletionJoiner.java @@ -13,11 +13,7 @@ public class CompletionJoiner extends PromiseJoiner, Void, Void, List private final ConcurrentResultArray> results; - public CompletionJoiner( - @NotNull PromiseFactory factory, - @NotNull Iterator> promises, - int expectedSize - ) { + public CompletionJoiner(@NotNull PromiseFactory factory, @NotNull Iterator> promises, int expectedSize) { super(factory); results = new ConcurrentResultArray<>(expectedSize); join(promises); diff --git a/futur-api/src/main/java/dev/tommyjs/futur/joiner/MappedResultJoiner.java b/futur-api/src/main/java/dev/tommyjs/futur/joiner/MappedResultJoiner.java index ee64b0e..a2a5ad9 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/joiner/MappedResultJoiner.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/joiner/MappedResultJoiner.java @@ -12,11 +12,8 @@ public class MappedResultJoiner extends PromiseJoiner> results; - public MappedResultJoiner( - @NotNull PromiseFactory factory, - @NotNull Iterator>> promises, - int expectedSize - ) { + public MappedResultJoiner(@NotNull PromiseFactory factory, @NotNull Iterator>> promises, + int expectedSize) { super(factory); this.results = new ConcurrentResultArray<>(expectedSize); join(promises); diff --git a/futur-api/src/main/java/dev/tommyjs/futur/joiner/ResultJoiner.java b/futur-api/src/main/java/dev/tommyjs/futur/joiner/ResultJoiner.java index b4e1a2d..3f53887 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/joiner/ResultJoiner.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/joiner/ResultJoiner.java @@ -13,11 +13,7 @@ public class ResultJoiner extends PromiseJoiner, Void, T, List> private final ConcurrentResultArray results; - public ResultJoiner( - @NotNull PromiseFactory factory, - @NotNull Iterator> promises, - int expectedSize - ) { + public ResultJoiner(@NotNull PromiseFactory factory, @NotNull Iterator> promises, int expectedSize) { super(factory); this.results = new ConcurrentResultArray<>(expectedSize); join(promises); diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromise.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromise.java index 620af47..c05f705 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromise.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromise.java @@ -39,7 +39,7 @@ public abstract class AbstractPromise implements Promise { try { return supplier.get(); } catch (Error error) { - // Rethrow error so the Thread can shut down or whatever + // rethrow unrecoverable errors throw error; } catch (Throwable e) { return handler.apply(e); @@ -51,7 +51,7 @@ public abstract class AbstractPromise implements Promise { runnable.run(); } catch (Error error) { handler.accept(error); - // Rethrow error so the Thread can shut down or whatever + // rethrow unrecoverable errors throw error; } catch (Throwable e) { handler.accept(e); @@ -64,9 +64,13 @@ public abstract class AbstractPromise implements Promise { protected V useCompletion(Supplier unresolved, Function completed, Function failed) { PromiseCompletion completion = getCompletion(); - if (completion == null) return unresolved.get(); - else if (completion.isSuccess()) return completed.apply(completion.getResult()); - else return failed.apply(completion.getException()); + if (completion == null) { + return unresolved.get(); + } else if (completion.isSuccess()) { + return completed.apply(completion.getResult()); + } else { + return failed.apply(completion.getException()); + } } protected @NotNull Runnable createCompleter(T result, @NotNull CompletablePromise promise, @@ -124,7 +128,9 @@ public abstract class AbstractPromise implements Promise { @Override public @NotNull Promise fork() { - if (isCompleted()) return this; + if (isCompleted()) { + return this; + } CompletablePromise fork = getFactory().unresolved(); PromiseUtil.propagateCompletion(this, fork); @@ -154,130 +160,94 @@ public abstract class AbstractPromise implements Promise { @Override public @NotNull Promise thenApply(@NotNull ExceptionalFunction task) { - return useCompletion( - () -> { - CompletablePromise promise = createLinked(); - addDirectListener( - res -> createCompleter(res, promise, task).run(), - promise::completeExceptionally - ); + return useCompletion(() -> { + CompletablePromise promise = createLinked(); + addDirectListener(res -> createCompleter(res, promise, task).run(), promise::completeExceptionally); - return promise; - }, - result -> supplySafe( - () -> getFactory().resolve(task.apply(result)), - getFactory()::error - ), - getFactory()::error - ); + return promise; + }, result -> supplySafe(() -> getFactory().resolve(task.apply(result)), getFactory()::error), getFactory()::error); } @Override public @NotNull Promise thenCompose(@NotNull ExceptionalFunction> task) { - return useCompletion( - () -> { - CompletablePromise promise = createLinked(); - thenApply(task).addDirectListener( - result -> { - if (result == null) { - promise.complete(null); - } else { - PromiseUtil.propagateCompletion(result, promise); - PromiseUtil.propagateCancel(promise, result); - } - }, - promise::completeExceptionally - ); - - return promise; - }, - result -> supplySafe( - () -> { - Promise nested = task.apply(result); - if (nested == null) { - return getFactory().resolve(null); - } else if (nested.isCompleted()) { - return nested; - } else { - CompletablePromise promise = createLinked(); - PromiseUtil.propagateCompletion(nested, promise); - PromiseUtil.propagateCancel(promise, nested); - return promise; - } - }, - getFactory()::error - ), - getFactory()::error - ); - } - - private @NotNull Promise thenApply(@NotNull ExceptionalFunction task, @NotNull PromiseExecutor executor) { - CompletablePromise promise = createLinked(); - addDirectListener( - res -> runCompleter(promise, () -> { - Runnable completer = createCompleter(res, promise, task); - execute(promise, completer, executor); - }), - promise::completeExceptionally - ); - - return promise; - } - - private @NotNull Promise thenApplyDelayed( - @NotNull ExceptionalFunction task, long delay, - @NotNull TimeUnit unit, @NotNull PromiseExecutor executor - ) { - CompletablePromise promise = createLinked(); - addDirectListener( - res -> runCompleter(promise, () -> { - Runnable completer = createCompleter(res, promise, task); - PromiseScheduler scheduler = executor.scheduler(); - if (scheduler == null) { - schedule( - promise, - () -> runCompleter(promise, () -> execute(promise, completer, executor)), - delay, unit, PromiseScheduler.getDefault() - ); + return useCompletion(() -> { + CompletablePromise promise = createLinked(); + thenApply(task).addDirectListener(result -> { + if (result == null) { + promise.complete(null); } else { - schedule(promise, completer, delay, unit, scheduler); + PromiseUtil.propagateCompletion(result, promise); + PromiseUtil.propagateCancel(promise, result); } - }), - promise::completeExceptionally - ); + }, promise::completeExceptionally); + + return promise; + }, result -> supplySafe(() -> { + Promise nested = task.apply(result); + if (nested == null) { + return getFactory().resolve(null); + } else if (nested.isCompleted()) { + return nested; + } else { + CompletablePromise promise = createLinked(); + PromiseUtil.propagateCompletion(nested, promise); + PromiseUtil.propagateCancel(promise, nested); + return promise; + } + }, getFactory()::error), getFactory()::error); + } + + private @NotNull Promise thenApply(@NotNull ExceptionalFunction task, + @NotNull PromiseExecutor executor) { + CompletablePromise promise = createLinked(); + addDirectListener(res -> runCompleter(promise, () -> { + Runnable completer = createCompleter(res, promise, task); + execute(promise, completer, executor); + }), promise::completeExceptionally); return promise; } - private void execute(@NotNull Promise promise, @NotNull Runnable task, @NotNull PromiseExecutorexecutor) throws Exception { + private @NotNull Promise thenApplyDelayed(@NotNull ExceptionalFunction task, long delay, + @NotNull TimeUnit unit, @NotNull PromiseExecutor executor) { + CompletablePromise promise = createLinked(); + addDirectListener(res -> runCompleter(promise, () -> { + Runnable completer = createCompleter(res, promise, task); + PromiseScheduler scheduler = executor.scheduler(); + if (scheduler == null) { + schedule(promise, () -> runCompleter(promise, () -> execute(promise, completer, executor)), delay, unit, + PromiseScheduler.getDefault()); + } else { + schedule(promise, completer, delay, unit, scheduler); + } + }), promise::completeExceptionally); + + return promise; + } + + private void execute(@NotNull Promise promise, @NotNull Runnable task, @NotNull PromiseExecutor executor) + throws Exception { F future = executor.run(task); promise.addDirectListener(_ -> executor.cancel(future)); } - private void schedule( - @NotNull Promise promise, @NotNull Runnable task, - long delay, @NotNull TimeUnit unit, @NotNull PromiseScheduler scheduler - ) throws Exception { + private void schedule(@NotNull Promise promise, @NotNull Runnable task, long delay, @NotNull TimeUnit unit, + @NotNull PromiseScheduler scheduler) throws Exception { F future = scheduler.schedule(task, delay, unit); promise.addDirectListener(_ -> scheduler.cancel(future)); } - private @NotNull Promise thenCompose( - @NotNull ExceptionalFunction> task, - @NotNull PromiseExecutor executor - ) { + private @NotNull Promise thenCompose(@NotNull ExceptionalFunction> task, + @NotNull PromiseExecutor executor) { CompletablePromise promise = createLinked(); - thenApply(task, executor).addDirectListener( - nestedPromise -> { - if (nestedPromise == null) { - promise.complete(null); - } else { - PromiseUtil.propagateCompletion(nestedPromise, promise); - PromiseUtil.propagateCancel(promise, nestedPromise); - } - }, - promise::completeExceptionally - ); + thenApply(task, executor).addDirectListener(nestedPromise -> { + if (nestedPromise == null) { + promise.complete(null); + } else { + PromiseUtil.propagateCompletion(nestedPromise, promise); + PromiseUtil.propagateCancel(promise, nestedPromise); + } + }, promise::completeExceptionally); return promise; } @@ -288,7 +258,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenRunDelayedSync(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenRunDelayedSync(@NotNull ExceptionalRunnable task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getSyncExecutor()); } @@ -298,7 +269,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenConsumeDelayedSync(@NotNull ExceptionalConsumer task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenConsumeDelayedSync(@NotNull ExceptionalConsumer task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getSyncExecutor()); } @@ -308,7 +280,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenSupplyDelayedSync(@NotNull ExceptionalSupplier task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenSupplyDelayedSync(@NotNull ExceptionalSupplier task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getSyncExecutor()); } @@ -318,7 +291,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenApplyDelayedSync(@NotNull ExceptionalFunction task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenApplyDelayedSync(@NotNull ExceptionalFunction task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(task, delay, unit, getFactory().getSyncExecutor()); } @@ -333,7 +307,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenRunDelayedAsync(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenRunDelayedAsync(@NotNull ExceptionalRunnable task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getAsyncExecutor()); } @@ -343,7 +318,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenConsumeDelayedAsync(@NotNull ExceptionalConsumer task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenConsumeDelayedAsync(@NotNull ExceptionalConsumer task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getAsyncExecutor()); } @@ -353,7 +329,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenSupplyDelayedAsync(@NotNull ExceptionalSupplier task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenSupplyDelayedAsync(@NotNull ExceptionalSupplier task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getAsyncExecutor()); } @@ -363,7 +340,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenApplyDelayedAsync(@NotNull ExceptionalFunction task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenApplyDelayedAsync(@NotNull ExceptionalFunction task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(task, delay, unit, getFactory().getAsyncExecutor()); } @@ -378,7 +356,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenRunDelayedVirtual(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenRunDelayedVirtual(@NotNull ExceptionalRunnable task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getVirtualExecutor()); } @@ -388,7 +367,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenConsumeDelayedVirtual(@NotNull ExceptionalConsumer task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenConsumeDelayedVirtual(@NotNull ExceptionalConsumer task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getVirtualExecutor()); } @@ -398,7 +378,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenSupplyDelayedVirtual(@NotNull ExceptionalSupplier task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenSupplyDelayedVirtual(@NotNull ExceptionalSupplier task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getVirtualExecutor()); } @@ -408,7 +389,8 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise thenApplyDelayedVirtual(@NotNull ExceptionalFunction task, long delay, @NotNull TimeUnit unit) { + public @NotNull Promise thenApplyDelayedVirtual(@NotNull ExceptionalFunction task, long delay, + @NotNull TimeUnit unit) { return thenApplyDelayed(task, delay, unit, getFactory().getVirtualExecutor()); } @@ -436,12 +418,17 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise addAsyncListener(@Nullable Consumer successListener, @Nullable Consumer errorListener) { + public @NotNull Promise addAsyncListener(@Nullable Consumer successListener, + @Nullable Consumer errorListener) { return addAsyncListener(res -> { if (res.isSuccess()) { - if (successListener != null) successListener.accept(res.getResult()); + if (successListener != null) { + successListener.accept(res.getResult()); + } } else { - if (errorListener != null) errorListener.accept(res.getException()); + if (errorListener != null) { + errorListener.accept(res.getException()); + } } }); } @@ -452,12 +439,17 @@ public abstract class AbstractPromise implements Promise { } @Override - public @NotNull Promise addDirectListener(@Nullable Consumer successListener, @Nullable Consumer errorListener) { + public @NotNull Promise addDirectListener(@Nullable Consumer successListener, + @Nullable Consumer errorListener) { return addDirectListener(res -> { if (res.isSuccess()) { - if (successListener != null) successListener.accept(res.getResult()); + if (successListener != null) { + successListener.accept(res.getResult()); + } } else { - if (errorListener != null) errorListener.accept(res.getException()); + if (errorListener != null) { + errorListener.accept(res.getException()); + } } }); } @@ -477,7 +469,7 @@ public abstract class AbstractPromise implements Promise { Exception wrapper = new DeferredExecutionException(); return onError(e -> { if (e instanceof CancellationException && e.getMessage() == null && e.getCause() == null) { - // Ignore cancellation exceptions without a message or cause + // ignore cancellation exceptions without a message or cause return; } @@ -512,15 +504,11 @@ public abstract class AbstractPromise implements Promise { @Override public @NotNull Promise orDefault(@NotNull ExceptionalFunction function) { - return useCompletion( - () -> { - CompletablePromise promise = createLinked(); - addDirectListener(promise::complete, e -> runCompleter(promise, () -> promise.complete(function.apply(e)))); - return promise; - }, - getFactory()::resolve, - getFactory()::error - ); + return useCompletion(() -> { + CompletablePromise promise = createLinked(); + addDirectListener(promise::complete, e -> runCompleter(promise, () -> promise.complete(function.apply(e)))); + return promise; + }, getFactory()::resolve, getFactory()::error); } private static class DeferredExecutionException extends ExecutionException { diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromiseFactory.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromiseFactory.java index 3d78691..c38af99 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromiseFactory.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/AbstractPromiseFactory.java @@ -47,9 +47,7 @@ public abstract class AbstractPromiseFactory implements PromiseFactory { } @Override - public @NotNull Promise> combine( - @NotNull Promise p1, @NotNull Promise p2 - ) { + public @NotNull Promise> combine(@NotNull Promise p1, @NotNull Promise p2) { return all(p1, p2).thenApply(_ -> new AbstractMap.SimpleImmutableEntry<>( Objects.requireNonNull(p1.getCompletion()).getResult(), Objects.requireNonNull(p2.getCompletion()).getResult() @@ -57,43 +55,45 @@ public abstract class AbstractPromiseFactory implements PromiseFactory { } @Override - public @NotNull Promise> combineMapped( - @NotNull Iterator>> promises, - int expectedSize - ) { - if (!promises.hasNext()) return resolve(Collections.emptyMap()); + public @NotNull Promise> combineMapped(@NotNull Iterator>> promises, + int expectedSize) { + if (!promises.hasNext()) { + return resolve(Collections.emptyMap()); + } + return new MappedResultJoiner<>(this, promises, expectedSize).joined(); } @Override - public @NotNull Promise> combine( - @NotNull Iterator> promises, - int expectedSize - ) { - if (!promises.hasNext()) return resolve(Collections.emptyList()); + public @NotNull Promise> combine(@NotNull Iterator> promises, int expectedSize) { + if (!promises.hasNext()) { + return resolve(Collections.emptyList()); + } + return new ResultJoiner<>(this, promises, expectedSize).joined(); } @Override - public @NotNull Promise>> allSettled( - @NotNull Iterator> promises, - int expectedSize - ) { - if (!promises.hasNext()) return resolve(Collections.emptyList()); + public @NotNull Promise>> allSettled(@NotNull Iterator> promises, + int expectedSize) { + if (!promises.hasNext()) { + return resolve(Collections.emptyList()); + } + return new CompletionJoiner(this, promises, expectedSize).joined(); } @Override public @NotNull Promise all(@NotNull Iterator> promises) { - if (!promises.hasNext()) return resolve(null); + if (!promises.hasNext()) { + return resolve(null); + } + return new VoidJoiner(this, promises).joined(); } @Override - public @NotNull Promise race( - @NotNull Iterator> promises, - boolean ignoreErrors - ) { + public @NotNull Promise race(@NotNull Iterator> promises, boolean ignoreErrors) { CompletablePromise promise = unresolved(); while (promises.hasNext()) { if (promise.isCompleted()) { diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/AsyncPromiseListener.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/AsyncPromiseListener.java index eb3974b..799b6be 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/AsyncPromiseListener.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/AsyncPromiseListener.java @@ -5,5 +5,4 @@ package dev.tommyjs.futur.promise; * executed asynchronously by the {@link PromiseFactory} that created the completed promise. */ public interface AsyncPromiseListener extends PromiseListener { - } diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/BasePromise.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/BasePromise.java index e630fe2..c607534 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/BasePromise.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/BasePromise.java @@ -8,7 +8,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; import java.util.Objects; import java.util.concurrent.*; import java.util.concurrent.locks.AbstractQueuedSynchronizer; @@ -44,12 +43,16 @@ public abstract class BasePromise extends AbstractPromise implements Compl } protected void handleCompletion(@NotNull PromiseCompletion cmp) { - if (!COMPLETION_HANDLE.compareAndSet(this, null, cmp)) return; + if (!COMPLETION_HANDLE.compareAndSet(this, null, cmp)) { + return; + } + sync.releaseShared(1); callListeners(cmp); } - protected Promise completeExceptionallyDelayed(Throwable e, long delay, TimeUnit unit, PromiseScheduler scheduler) { + protected Promise completeExceptionallyDelayed(Throwable e, long delay, TimeUnit unit, + PromiseScheduler scheduler) { runCompleter(this, () -> { F future = scheduler.schedule(() -> completeExceptionally(e), delay, unit); addDirectListener(_ -> scheduler.cancel(future)); @@ -60,7 +63,7 @@ public abstract class BasePromise extends AbstractPromise implements Compl @SuppressWarnings("unchecked") protected void callListeners(@NotNull PromiseCompletion cmp) { - Iterator> iter = ((Iterable>) LISTENERS_HANDLE.getAndSet(this, null)).iterator(); + var iter = ((Iterable>) LISTENERS_HANDLE.getAndSet(this, null)).iterator(); try { while (iter.hasNext()) { callListener(iter.next(), cmp); @@ -76,11 +79,14 @@ public abstract class BasePromise extends AbstractPromise implements Compl for (boolean haveNext = false; ; ) { if (!haveNext) { next = prev == Collections.EMPTY_LIST ? new ConcurrentLinkedQueue<>() : prev; - if (next != null) next.add(listener); + if (next != null) { + next.add(listener); + } } - if (LISTENERS_HANDLE.weakCompareAndSet(this, prev, next)) + if (LISTENERS_HANDLE.weakCompareAndSet(this, prev, next)) { break; + } haveNext = (prev == (prev = listeners)); } @@ -133,13 +139,15 @@ public abstract class BasePromise extends AbstractPromise implements Compl @Override public @NotNull Promise timeout(long time, @NotNull TimeUnit unit) { - Exception e = new CancellationException("Promise timed out after " + time + " " + unit.toString().toLowerCase()); + Exception e = new CancellationException( + "Promise timed out after " + time + " " + unit.toString().toLowerCase()); return completeExceptionallyDelayed(e, time, unit, PromiseScheduler.getDefault()); } @Override public @NotNull Promise maxWaitTime(long time, @NotNull TimeUnit unit) { - Exception e = new TimeoutException("Promise stopped waiting after " + time + " " + unit.toString().toLowerCase()); + Exception e = new TimeoutException( + "Promise stopped waiting after " + time + " " + unit.toString().toLowerCase()); return completeExceptionallyDelayed(e, time, unit, PromiseScheduler.getDefault()); } @@ -170,36 +178,28 @@ public abstract class BasePromise extends AbstractPromise implements Compl @Override public @NotNull CompletableFuture toFuture() { - return useCompletion( - () -> { - CompletableFuture future = new CompletableFuture<>(); - addDirectListener(future::complete, future::completeExceptionally); - future.whenComplete((result, error) -> { - if (error == null) { - complete(result); - } else { - completeExceptionally(error); - } - }); + return useCompletion(() -> { + CompletableFuture future = new CompletableFuture<>(); + addDirectListener(future::complete, future::completeExceptionally); + future.whenComplete((result, error) -> { + if (error == null) { + complete(result); + } else { + completeExceptionally(error); + } + }); - return future; - }, - CompletableFuture::completedFuture, - CompletableFuture::failedFuture - ); + return future; + }, CompletableFuture::completedFuture, CompletableFuture::failedFuture); } @Override public @NotNull CompletionStage toCompletionStage() { - return useCompletion( - () -> { - CompletableFuture future = new CompletableFuture<>(); - addDirectListener(future::complete, future::completeExceptionally); - return future; - }, - CompletableFuture::completedStage, - CompletableFuture::failedStage - ); + return useCompletion(() -> { + CompletableFuture future = new CompletableFuture<>(); + addDirectListener(future::complete, future::completeExceptionally); + return future; + }, CompletableFuture::completedStage, CompletableFuture::failedStage); } private static final class Sync extends AbstractQueuedSynchronizer { diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/Promise.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/Promise.java index cf31667..181c7ae 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/Promise.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/Promise.java @@ -135,7 +135,8 @@ public interface Promise { * @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); + @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 @@ -159,7 +160,8 @@ public interface Promise { * @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); + @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 @@ -185,7 +187,8 @@ public interface Promise { * @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); + @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 @@ -245,7 +248,8 @@ public interface Promise { * @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); + @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 @@ -269,7 +273,8 @@ public interface Promise { * @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); + @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 @@ -295,7 +300,8 @@ public interface Promise { * @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); + @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 @@ -355,7 +361,8 @@ public interface Promise { * @param unit the time unit of the delay * @return a new promise that completes after the task is executed */ - @NotNull Promise thenConsumeDelayedVirtual(@NotNull ExceptionalConsumer task, long delay, @NotNull TimeUnit unit); + @NotNull Promise thenConsumeDelayedVirtual(@NotNull ExceptionalConsumer task, long delay, + @NotNull TimeUnit unit); /** * Chains a task to be executed after this promise completes. The task will be executed @@ -379,7 +386,8 @@ public interface Promise { * @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 thenSupplyDelayedVirtual(@NotNull ExceptionalSupplier task, long delay, @NotNull TimeUnit unit); + @NotNull Promise thenSupplyDelayedVirtual(@NotNull ExceptionalSupplier task, long delay, + @NotNull TimeUnit unit); /** * Chains a task to be executed after this promise completes. The task will be executed @@ -405,7 +413,8 @@ public interface Promise { * @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 thenApplyDelayedVirtual(@NotNull ExceptionalFunction task, long delay, @NotNull TimeUnit unit); + @NotNull Promise thenApplyDelayedVirtual(@NotNull ExceptionalFunction task, long delay, + @NotNull TimeUnit unit); /** * Chains a task to be executed after this promise completes. The task will be executed @@ -475,7 +484,8 @@ public interface Promise { * @param errorHandler the function to call on error * @return continuation of the promise chain */ - @NotNull Promise addDirectListener(@Nullable Consumer successHandler, @Nullable Consumer errorHandler); + @NotNull Promise addDirectListener(@Nullable Consumer successHandler, + @Nullable Consumer errorHandler); /** * Adds a listener to this promise that will be executed immediately when this promise completes, @@ -504,7 +514,8 @@ public interface Promise { * @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); + @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. diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseCompletion.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseCompletion.java index 9628a7e..f16938b 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseCompletion.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseCompletion.java @@ -60,7 +60,7 @@ public record PromiseCompletion(@Nullable T result, @Nullable Throwable excep * * @return {@code true} if the completion was cancelled, {@code false} otherwise */ - public boolean wasCancelled() { + public boolean isCancelled() { return exception instanceof CancellationException; } @@ -89,8 +89,11 @@ public record PromiseCompletion(@Nullable T result, @Nullable Throwable excep * @throws CompletionException if the completion was exceptional */ public T get() { - if (isSuccess()) return getResult(); - throw new CompletionException(getException()); + if (isSuccess()) { + return getResult(); + } else { + throw new CompletionException(getException()); + } } /** @@ -100,8 +103,11 @@ public record PromiseCompletion(@Nullable T result, @Nullable Throwable excep * @throws ExecutionException if the completion was exceptional */ public T getChecked() throws ExecutionException { - if (isSuccess()) return getResult(); - throw new ExecutionException(getException()); + if (isSuccess()) { + return getResult(); + } else { + throw new ExecutionException(getException()); + } } } diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactory.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactory.java index ff569d3..6780e16 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactory.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactory.java @@ -93,7 +93,7 @@ public interface PromiseFactory { * and the {@link Future} will be cancelled upon cancellation of the promise. * * @param completion the completion stage to wrap - * @param future the future to wrap + * @param future the future to wrap * @return the new promise */ @NotNull Promise wrap(@NotNull CompletionStage completion, @Nullable Future future); @@ -108,15 +108,15 @@ public interface PromiseFactory { */ default @NotNull Promise wrap(@NotNull CompletableFuture future) { return wrap(future, future); - }; + } /** * Combines two promises into a single promise that resolves when both promises are completed. * If either input promise completes exceptionally, the other promise will be cancelled * and the output promise will complete exceptionally. * - * @param p1 the first promise - * @param p2 the second promise + * @param p1 the first promise + * @param p2 the second promise * @return the combined promise */ @NotNull Promise> combine(@NotNull Promise p1, @NotNull Promise p2); @@ -128,7 +128,7 @@ public interface PromiseFactory { * If any promise completes exceptionally, the other promises will be cancelled * and the combined promise will complete exceptionally. * - * @param promises the input promises + * @param promises the input promises * @param expectedSize the expected size of the iterator (used for optimization) * @return the combined promise */ @@ -206,7 +206,7 @@ public interface PromiseFactory { * If any promise completes exceptionally, the other promises will be cancelled * and the combined promise will complete exceptionally. * - * @param keys the keys to map to promises + * @param keys the keys to map to promises * @param mapper the function to map keys to promises * @return the combined promise */ @@ -221,7 +221,7 @@ public interface PromiseFactory { * If any promise completes exceptionally, the other promises will be cancelled * and the combined promise will complete exceptionally. * - * @param keys the keys to map to promises + * @param keys the keys to map to promises * @param mapper the function to map keys to promises * @return the combined promise */ @@ -244,7 +244,7 @@ public interface PromiseFactory { * If any promise completes exceptionally, all other promises will be cancelled * and the combined promise will complete exceptionally. * - * @param promises the input promises + * @param promises the input promises * @param expectedSize the expected size of the iterator (used for optimization) * @return the combined promise */ @@ -306,12 +306,11 @@ public interface PromiseFactory { * Combines multiple promises into a single promise that completes when all promises * are completed, with a list of completions in the original order. * - * @param promises the input promises + * @param promises the input promises * @param expectedSize the expected size of the iterator (used for optimization) * @return the combined promise */ - @NotNull Promise>> allSettled(@NotNull Iterator> promises, - int expectedSize); + @NotNull Promise>> allSettled(@NotNull Iterator> promises, int expectedSize); /** * Combines multiple promises into a single promise that completes when all promises @@ -411,7 +410,7 @@ public interface PromiseFactory { * Additionally, if {@code cancelLosers} is {@code true}, the other promises will be cancelled * once the combined promise is completed. * - * @param promises the input promises + * @param promises the input promises * @param ignoreErrors whether to ignore promises that complete exceptionally * @return the combined promise */ @@ -425,7 +424,7 @@ public interface PromiseFactory { * successful completion or complete with {@code null} if all promises complete exceptionally. * Additionally, The other promises will be cancelled once the combined promise is completed. * - * @param promises the input promises + * @param promises the input promises * @param ignoreErrors whether to ignore promises that complete exceptionally * @return the combined promise */ @@ -452,7 +451,7 @@ public interface PromiseFactory { * successful completion or complete with {@code null} if all promises complete exceptionally. * Additionally, The other promises will be cancelled once the combined promise is completed. * - * @param promises the input promises + * @param promises the input promises * @param ignoreErrors whether to ignore promises that complete exceptionally * @return the combined promise */ @@ -479,7 +478,7 @@ public interface PromiseFactory { * successful completion or complete with {@code null} if all promises complete exceptionally. * Additionally, The other promises will be cancelled once the combined promise is completed. * - * @param promises the input promises + * @param promises the input promises * @param ignoreErrors whether to ignore promises that complete exceptionally * @return the combined promise */ diff --git a/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactoryImpl.java b/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactoryImpl.java index 6450ba1..e0e7b39 100644 --- a/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactoryImpl.java +++ b/futur-api/src/main/java/dev/tommyjs/futur/promise/PromiseFactoryImpl.java @@ -11,11 +11,8 @@ public class PromiseFactoryImpl extends AbstractPromiseFactory { private final @NotNull PromiseExecutor syncExecutor; private final @NotNull PromiseExecutor asyncExecutor; - public PromiseFactoryImpl( - @NotNull Logger logger, - @NotNull PromiseExecutor syncExecutor, - @NotNull PromiseExecutor asyncExecutor - ) { + public PromiseFactoryImpl(@NotNull Logger logger, @NotNull PromiseExecutor syncExecutor, + @NotNull PromiseExecutor asyncExecutor) { this.logger = logger; this.syncExecutor = syncExecutor; this.asyncExecutor = asyncExecutor; @@ -58,6 +55,9 @@ public class PromiseFactoryImpl extends AbstractPromiseFactory { private class PromiseImpl extends BasePromise { + PromiseImpl() { + } + @Override public @NotNull AbstractPromiseFactory getFactory() { return PromiseFactoryImpl.this; @@ -67,15 +67,15 @@ public class PromiseFactoryImpl extends AbstractPromiseFactory { private class CompletedPromiseImpl extends CompletedPromise { - public CompletedPromiseImpl(@Nullable T result) { + CompletedPromiseImpl(@Nullable T result) { super(new PromiseCompletion<>(result)); } - public CompletedPromiseImpl(@NotNull Throwable exception) { + CompletedPromiseImpl(@NotNull Throwable exception) { super(new PromiseCompletion<>(exception)); } - public CompletedPromiseImpl() { + CompletedPromiseImpl() { super(); }