mirror of
https://github.com/tommyskeff/futur4j.git
synced 2026-01-17 23:16:01 +00:00
Merge pull request #11 from tommyskeff/release/2.5
seperate scheduler and virtual executor promise chain methods
This commit is contained in:
26
.github/workflows/publish.yml
vendored
Normal file
26
.github/workflows/publish.yml
vendored
Normal file
@@ -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 }}
|
||||
12
README.md
12
README.md
@@ -14,8 +14,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'dev.tommyjs:futur-api:2.4.0'
|
||||
compile 'dev.tommyjs:futur-lazy:2.4.0'
|
||||
compile 'dev.tommyjs:futur-api:2.5.0'
|
||||
compile 'dev.tommyjs:futur-lazy:2.5.0'
|
||||
}
|
||||
```
|
||||
### Gradle DSL
|
||||
@@ -25,8 +25,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("dev.tommyjs:futur-api:2.4.0")
|
||||
implementation("dev.tommyjs:futur-lazy:2.4.0")
|
||||
implementation("dev.tommyjs:futur-api:2.5.0")
|
||||
implementation("dev.tommyjs:futur-lazy:2.5.0")
|
||||
}
|
||||
```
|
||||
### Maven
|
||||
@@ -42,12 +42,12 @@ dependencies {
|
||||
<dependency>
|
||||
<groupId>dev.tommyjs</groupId>
|
||||
<artifactId>futur-api</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<version>2.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.tommyjs</groupId>
|
||||
<artifactId>futur-lazy</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<version>2.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
39
build.gradle
39
build.gradle
@@ -1,23 +1,38 @@
|
||||
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 {
|
||||
group = 'dev.tommyjs'
|
||||
version = '2.4.1'
|
||||
version = '2.5.0'
|
||||
|
||||
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 {
|
||||
@@ -48,8 +63,8 @@ subprojects {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_22
|
||||
targetCompatibility = JavaVersion.VERSION_22
|
||||
sourceCompatibility = JavaVersion.VERSION_23
|
||||
targetCompatibility = JavaVersion.VERSION_23
|
||||
withSourcesJar()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package dev.tommyjs.futur.executor;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
class ExecutorImpl implements PromiseExecutor<Void> {
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
public ExecutorImpl(@NotNull Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Void run(@NotNull Runnable task) {
|
||||
executor.execute(task);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(@NotNull Void task) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PromiseScheduler<?> scheduler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +1,32 @@
|
||||
package dev.tommyjs.futur.executor;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class ExecutorServiceImpl implements PromiseExecutor<Future<?>> {
|
||||
|
||||
private final ScheduledExecutorService service;
|
||||
private final ExecutorService executor;
|
||||
|
||||
public ExecutorServiceImpl(@NotNull ScheduledExecutorService service) {
|
||||
this.service = service;
|
||||
public ExecutorServiceImpl(@NotNull ExecutorService executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> run(@NotNull Runnable task) {
|
||||
return service.submit(task);
|
||||
public @NotNull Future<?> run(@NotNull Runnable task) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> run(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
|
||||
return service.schedule(task, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(Future<?> task) {
|
||||
public boolean cancel(@NotNull Future<?> task) {
|
||||
return task.cancel(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PromiseScheduler<?> scheduler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package dev.tommyjs.futur.executor;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* An executor that can run tasks and schedule tasks to run in the future.
|
||||
@@ -42,11 +43,21 @@ public interface PromiseExecutor<T> {
|
||||
/**
|
||||
* Creates a new {@link PromiseExecutor} that runs tasks on the given executor service.
|
||||
*
|
||||
* @param service the executor service
|
||||
* @param executor the executor service
|
||||
* @return the new executor
|
||||
*/
|
||||
static PromiseExecutor<?> of(@NotNull ScheduledExecutorService service) {
|
||||
return new ExecutorServiceImpl(service);
|
||||
static PromiseExecutor<?> of(@NotNull ScheduledExecutorService executor) {
|
||||
return new ScheduledExecutorImpl(executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PromiseExecutor} that runs tasks on the given executor service.
|
||||
*
|
||||
* @param executor the executor service
|
||||
* @return the new executor
|
||||
*/
|
||||
static PromiseExecutor<?> of(@NotNull ExecutorService executor) {
|
||||
return new ExecutorServiceImpl(executor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,26 +67,17 @@ public interface PromiseExecutor<T> {
|
||||
* @return the task
|
||||
* @throws Exception if scheduling the task failed
|
||||
*/
|
||||
T run(@NotNull Runnable task) throws Exception;
|
||||
|
||||
/**
|
||||
* Runs the given task after the given delay.
|
||||
*
|
||||
* @param task the task
|
||||
* @param delay the delay
|
||||
* @param unit the time unit
|
||||
* @return the task
|
||||
* @throws Exception if scheduling the task failed
|
||||
*/
|
||||
T run(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) throws Exception;
|
||||
@NotNull T run(@NotNull Runnable task) throws Exception;
|
||||
|
||||
/**
|
||||
* 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(T task);
|
||||
boolean cancel(@NotNull T task);
|
||||
|
||||
@Nullable PromiseScheduler<?> scheduler();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.tommyjs.futur.executor;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A scheduler for running tasks after a delay.
|
||||
*/
|
||||
public interface PromiseScheduler<T> {
|
||||
|
||||
static @NotNull PromiseScheduler<?> getDefault() {
|
||||
return PromiseSchedulerDefault.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given task after the given delay.
|
||||
*
|
||||
* @param task the task
|
||||
* @param delay the delay
|
||||
* @param unit the time unit
|
||||
* @return the task
|
||||
* @throws Exception if scheduling the task failed
|
||||
*/
|
||||
@NotNull T schedule(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) throws Exception;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
boolean cancel(@NotNull T task);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package dev.tommyjs.futur.executor;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
class PromiseSchedulerDefault implements PromiseScheduler<ScheduledFuture<?>> {
|
||||
|
||||
static final PromiseSchedulerDefault INSTANCE = new PromiseSchedulerDefault();
|
||||
|
||||
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) {
|
||||
return executor.schedule(task, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(@NotNull ScheduledFuture<?> task) {
|
||||
return task.cancel(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package dev.tommyjs.futur.executor;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class ScheduledExecutorImpl implements PromiseExecutor<Future<?>>, PromiseScheduler<Future<?>> {
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
public ScheduledExecutorImpl(@NotNull ScheduledExecutorService executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Future<?> run(@NotNull Runnable task) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Future<?> schedule(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
|
||||
return executor.schedule(task, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(@NotNull Future<?> task) {
|
||||
return task.cancel(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PromiseScheduler<Future<?>> scheduler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,15 +4,15 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class VirtualThreadImpl implements PromiseExecutor<Thread> {
|
||||
class VirtualThreadImpl implements PromiseExecutor<Thread>, PromiseScheduler<Thread> {
|
||||
|
||||
@Override
|
||||
public Thread run(@NotNull Runnable task) {
|
||||
public @NotNull Thread run(@NotNull Runnable task) {
|
||||
return Thread.ofVirtual().start(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread run(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
|
||||
public @NotNull Thread schedule(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
|
||||
return Thread.ofVirtual().start(() -> {
|
||||
try {
|
||||
Thread.sleep(unit.toMillis(delay));
|
||||
@@ -24,7 +24,7 @@ class VirtualThreadImpl implements PromiseExecutor<Thread> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(Thread task) {
|
||||
public boolean cancel(@NotNull Thread task) {
|
||||
if (task.isAlive()) {
|
||||
task.interrupt();
|
||||
return true;
|
||||
@@ -33,4 +33,9 @@ class VirtualThreadImpl implements PromiseExecutor<Thread> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PromiseScheduler<Thread> scheduler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.tommyjs.futur.function;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class FunctionAdapter {
|
||||
|
||||
public static <T, V> @NotNull ExceptionalFunction<T, V> adapt(@NotNull ExceptionalConsumer<T> consumer) {
|
||||
return value -> {
|
||||
consumer.accept(value);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
public static <K, V> @NotNull ExceptionalFunction<K, V> adapt(@NotNull ExceptionalRunnable runnable) {
|
||||
return _ -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
public static <K, T> @NotNull ExceptionalFunction<K, T> adapt(@NotNull ExceptionalSupplier<T> supplier) {
|
||||
return _ -> supplier.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,11 +13,7 @@ public class CompletionJoiner extends PromiseJoiner<Promise<?>, Void, Void, List
|
||||
|
||||
private final ConcurrentResultArray<PromiseCompletion<?>> results;
|
||||
|
||||
public CompletionJoiner(
|
||||
@NotNull PromiseFactory factory,
|
||||
@NotNull Iterator<Promise<?>> promises,
|
||||
int expectedSize
|
||||
) {
|
||||
public CompletionJoiner(@NotNull PromiseFactory factory, @NotNull Iterator<Promise<?>> promises, int expectedSize) {
|
||||
super(factory);
|
||||
results = new ConcurrentResultArray<>(expectedSize);
|
||||
join(promises);
|
||||
|
||||
@@ -12,11 +12,8 @@ public class MappedResultJoiner<K, V> extends PromiseJoiner<Map.Entry<K, Promise
|
||||
|
||||
private final @NotNull ConcurrentResultArray<Map.Entry<K, V>> results;
|
||||
|
||||
public MappedResultJoiner(
|
||||
@NotNull PromiseFactory factory,
|
||||
@NotNull Iterator<Map.Entry<K, Promise<V>>> promises,
|
||||
int expectedSize
|
||||
) {
|
||||
public MappedResultJoiner(@NotNull PromiseFactory factory, @NotNull Iterator<Map.Entry<K, Promise<V>>> promises,
|
||||
int expectedSize) {
|
||||
super(factory);
|
||||
this.results = new ConcurrentResultArray<>(expectedSize);
|
||||
join(promises);
|
||||
|
||||
@@ -13,11 +13,7 @@ public class ResultJoiner<T> extends PromiseJoiner<Promise<T>, Void, T, List<T>>
|
||||
|
||||
private final ConcurrentResultArray<T> results;
|
||||
|
||||
public ResultJoiner(
|
||||
@NotNull PromiseFactory factory,
|
||||
@NotNull Iterator<Promise<T>> promises,
|
||||
int expectedSize
|
||||
) {
|
||||
public ResultJoiner(@NotNull PromiseFactory factory, @NotNull Iterator<Promise<T>> promises, int expectedSize) {
|
||||
super(factory);
|
||||
this.results = new ConcurrentResultArray<>(expectedSize);
|
||||
join(promises);
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
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 dev.tommyjs.futur.executor.PromiseExecutor;
|
||||
import dev.tommyjs.futur.executor.PromiseScheduler;
|
||||
import dev.tommyjs.futur.function.*;
|
||||
import dev.tommyjs.futur.util.PromiseUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
public abstract class AbstractPromise<T> implements Promise<T> {
|
||||
|
||||
public abstract @NotNull AbstractPromiseFactory<FS, FA> getFactory();
|
||||
public abstract @NotNull AbstractPromiseFactory getFactory();
|
||||
|
||||
protected abstract @NotNull Promise<T> addAnyListener(@NotNull PromiseListener<T> listener);
|
||||
|
||||
@@ -37,7 +39,7 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (Error error) {
|
||||
// Rethrow error so the Thread can shut down
|
||||
// rethrow unrecoverable errors
|
||||
throw error;
|
||||
} catch (Throwable e) {
|
||||
return handler.apply(e);
|
||||
@@ -49,7 +51,7 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
runnable.run();
|
||||
} catch (Error error) {
|
||||
handler.accept(error);
|
||||
// Rethrow error so the Thread can shut down
|
||||
// rethrow unrecoverable errors
|
||||
throw error;
|
||||
} catch (Throwable e) {
|
||||
handler.accept(e);
|
||||
@@ -62,9 +64,13 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
|
||||
protected <V> V useCompletion(Supplier<V> unresolved, Function<T, V> completed, Function<Throwable, V> failed) {
|
||||
PromiseCompletion<T> 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 <V> @NotNull Runnable createCompleter(T result, @NotNull CompletablePromise<V> promise,
|
||||
@@ -104,21 +110,27 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
|
||||
protected T joinCompletionChecked() throws ExecutionException {
|
||||
PromiseCompletion<T> completion = getCompletion();
|
||||
assert completion != null;
|
||||
if (completion.isSuccess()) return completion.getResult();
|
||||
throw new ExecutionException(completion.getException());
|
||||
if (completion == null) {
|
||||
throw new IllegalStateException("Promise is not completed yet.");
|
||||
}
|
||||
|
||||
return completion.getChecked();
|
||||
}
|
||||
|
||||
protected T joinCompletionUnchecked() {
|
||||
PromiseCompletion<T> completion = getCompletion();
|
||||
assert completion != null;
|
||||
if (completion.isSuccess()) return completion.getResult();
|
||||
throw new CompletionException(completion.getException());
|
||||
if (completion == null) {
|
||||
throw new IllegalStateException("Promise is not completed yet.");
|
||||
}
|
||||
|
||||
return completion.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<T> fork() {
|
||||
if (isCompleted()) return this;
|
||||
if (isCompleted()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
CompletablePromise<T> fork = getFactory().unresolved();
|
||||
PromiseUtil.propagateCompletion(this, fork);
|
||||
@@ -148,45 +160,29 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApply(@NotNull ExceptionalFunction<T, V> task) {
|
||||
return useCompletion(
|
||||
() -> {
|
||||
return useCompletion(() -> {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
addDirectListener(
|
||||
res -> createCompleter(res, promise, task).run(),
|
||||
promise::completeExceptionally
|
||||
);
|
||||
addDirectListener(res -> createCompleter(res, promise, task).run(), promise::completeExceptionally);
|
||||
|
||||
return promise;
|
||||
},
|
||||
result -> supplySafe(
|
||||
() -> getFactory().resolve(task.apply(result)),
|
||||
getFactory()::error
|
||||
),
|
||||
getFactory()::error
|
||||
);
|
||||
}, result -> supplySafe(() -> getFactory().resolve(task.apply(result)), getFactory()::error), getFactory()::error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenCompose(@NotNull ExceptionalFunction<T, Promise<V>> task) {
|
||||
return useCompletion(
|
||||
() -> {
|
||||
return useCompletion(() -> {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
thenApply(task).addDirectListener(
|
||||
result -> {
|
||||
thenApply(task).addDirectListener(result -> {
|
||||
if (result == null) {
|
||||
promise.complete(null);
|
||||
} else {
|
||||
PromiseUtil.propagateCompletion(result, promise);
|
||||
PromiseUtil.propagateCancel(promise, result);
|
||||
}
|
||||
},
|
||||
promise::completeExceptionally
|
||||
);
|
||||
}, promise::completeExceptionally);
|
||||
|
||||
return promise;
|
||||
},
|
||||
result -> supplySafe(
|
||||
() -> {
|
||||
}, result -> supplySafe(() -> {
|
||||
Promise<V> nested = task.apply(result);
|
||||
if (nested == null) {
|
||||
return getFactory().resolve(null);
|
||||
@@ -198,191 +194,209 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
PromiseUtil.propagateCancel(promise, nested);
|
||||
return promise;
|
||||
}
|
||||
},
|
||||
getFactory()::error
|
||||
),
|
||||
getFactory()::error
|
||||
);
|
||||
}, getFactory()::error), getFactory()::error);
|
||||
}
|
||||
|
||||
private <F, V> @NotNull Promise<V> thenApply(@NotNull ExceptionalFunction<T, V> task,
|
||||
@NotNull PromiseExecutor<F> executor) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
addDirectListener(res -> runCompleter(promise, () -> {
|
||||
Runnable completer = createCompleter(res, promise, task);
|
||||
execute(promise, completer, executor);
|
||||
}), promise::completeExceptionally);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
private <F, V> @NotNull Promise<V> thenApplyDelayed(@NotNull ExceptionalFunction<T, V> task, long delay,
|
||||
@NotNull TimeUnit unit, @NotNull PromiseExecutor<F> executor) {
|
||||
CompletablePromise<V> 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 <F> void execute(@NotNull Promise<?> promise, @NotNull Runnable task, @NotNull PromiseExecutor<F> executor)
|
||||
throws Exception {
|
||||
F future = executor.run(task);
|
||||
promise.addDirectListener(_ -> executor.cancel(future));
|
||||
}
|
||||
|
||||
private <F> void schedule(@NotNull Promise<?> promise, @NotNull Runnable task, long delay, @NotNull TimeUnit unit,
|
||||
@NotNull PromiseScheduler<F> scheduler) throws Exception {
|
||||
F future = scheduler.schedule(task, delay, unit);
|
||||
promise.addDirectListener(_ -> scheduler.cancel(future));
|
||||
}
|
||||
|
||||
private <V> @NotNull Promise<V> thenCompose(@NotNull ExceptionalFunction<T, Promise<V>> task,
|
||||
@NotNull PromiseExecutor<?> executor) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
thenApply(task, executor).addDirectListener(nestedPromise -> {
|
||||
if (nestedPromise == null) {
|
||||
promise.complete(null);
|
||||
} else {
|
||||
PromiseUtil.propagateCompletion(nestedPromise, promise);
|
||||
PromiseUtil.propagateCancel(promise, nestedPromise);
|
||||
}
|
||||
}, promise::completeExceptionally);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenRunSync(@NotNull ExceptionalRunnable task) {
|
||||
return thenApplySync(_ -> {
|
||||
task.run();
|
||||
return null;
|
||||
});
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenRunDelayedSync(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit) {
|
||||
return thenApplyDelayedSync(_ -> {
|
||||
task.run();
|
||||
return null;
|
||||
}, delay, unit);
|
||||
public @NotNull Promise<Void> thenRunDelayedSync(@NotNull ExceptionalRunnable task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenConsumeSync(@NotNull ExceptionalConsumer<T> task) {
|
||||
return thenApplySync(result -> {
|
||||
task.accept(result);
|
||||
return null;
|
||||
});
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenConsumeDelayedSync(@NotNull ExceptionalConsumer<T> task, long delay, @NotNull TimeUnit unit) {
|
||||
return thenApplyDelayedSync(result -> {
|
||||
task.accept(result);
|
||||
return null;
|
||||
}, delay, unit);
|
||||
public @NotNull Promise<Void> thenConsumeDelayedSync(@NotNull ExceptionalConsumer<T> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenSupplySync(@NotNull ExceptionalSupplier<V> task) {
|
||||
return thenApplySync(_ -> task.get());
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenSupplyDelayedSync(@NotNull ExceptionalSupplier<V> task, long delay, @NotNull TimeUnit unit) {
|
||||
return thenApplyDelayedSync(_ -> task.get(), delay, unit);
|
||||
public <V> @NotNull Promise<V> thenSupplyDelayedSync(@NotNull ExceptionalSupplier<V> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApplySync(@NotNull ExceptionalFunction<T, V> task) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
addDirectListener(
|
||||
res -> runCompleter(promise, () -> {
|
||||
Runnable runnable = createCompleter(res, promise, task);
|
||||
FS future = getFactory().getSyncExecutor().run(runnable);
|
||||
promise.addDirectListener(_ -> getFactory().getSyncExecutor().cancel(future));
|
||||
}),
|
||||
promise::completeExceptionally
|
||||
);
|
||||
|
||||
return promise;
|
||||
return thenApply(task, getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApplyDelayedSync(@NotNull ExceptionalFunction<T, V> task, long delay, @NotNull TimeUnit unit) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
addDirectListener(
|
||||
res -> runCompleter(promise, () -> {
|
||||
Runnable runnable = createCompleter(res, promise, task);
|
||||
FS future = getFactory().getSyncExecutor().run(runnable, delay, unit);
|
||||
promise.addDirectListener(_ -> getFactory().getSyncExecutor().cancel(future));
|
||||
}),
|
||||
promise::completeExceptionally
|
||||
);
|
||||
|
||||
return promise;
|
||||
public <V> @NotNull Promise<V> thenApplyDelayedSync(@NotNull ExceptionalFunction<T, V> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(task, delay, unit, getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenComposeSync(@NotNull ExceptionalFunction<T, Promise<V>> task) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
thenApplySync(task).addDirectListener(
|
||||
nestedPromise -> {
|
||||
if (nestedPromise == null) {
|
||||
promise.complete(null);
|
||||
} else {
|
||||
PromiseUtil.propagateCompletion(nestedPromise, promise);
|
||||
PromiseUtil.propagateCancel(promise, nestedPromise);
|
||||
}
|
||||
},
|
||||
promise::completeExceptionally
|
||||
);
|
||||
|
||||
return promise;
|
||||
return thenCompose(task, getFactory().getSyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenRunAsync(@NotNull ExceptionalRunnable task) {
|
||||
return thenApplyAsync(_ -> {
|
||||
task.run();
|
||||
return null;
|
||||
});
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenRunDelayedAsync(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit) {
|
||||
return thenApplyDelayedAsync(_ -> {
|
||||
task.run();
|
||||
return null;
|
||||
}, delay, unit);
|
||||
public @NotNull Promise<Void> thenRunDelayedAsync(@NotNull ExceptionalRunnable task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenConsumeAsync(@NotNull ExceptionalConsumer<T> task) {
|
||||
return thenApplyAsync(result -> {
|
||||
task.accept(result);
|
||||
return null;
|
||||
});
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenConsumeDelayedAsync(@NotNull ExceptionalConsumer<T> task, long delay, @NotNull TimeUnit unit) {
|
||||
return thenApplyDelayedAsync(result -> {
|
||||
task.accept(result);
|
||||
return null;
|
||||
}, delay, unit);
|
||||
public @NotNull Promise<Void> thenConsumeDelayedAsync(@NotNull ExceptionalConsumer<T> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenSupplyAsync(@NotNull ExceptionalSupplier<V> task) {
|
||||
return thenApplyAsync(_ -> task.get());
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenSupplyDelayedAsync(@NotNull ExceptionalSupplier<V> task, long delay, @NotNull TimeUnit unit) {
|
||||
return thenApplyDelayedAsync(_ -> task.get(), delay, unit);
|
||||
public <V> @NotNull Promise<V> thenSupplyDelayedAsync(@NotNull ExceptionalSupplier<V> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApplyAsync(@NotNull ExceptionalFunction<T, V> task) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
addDirectListener(
|
||||
(res) -> runCompleter(promise, () -> {
|
||||
Runnable runnable = createCompleter(res, promise, task);
|
||||
FA future = getFactory().getAsyncExecutor().run(runnable);
|
||||
promise.addDirectListener(_ -> getFactory().getAsyncExecutor().cancel(future));
|
||||
}),
|
||||
promise::completeExceptionally
|
||||
);
|
||||
|
||||
return promise;
|
||||
return thenApply(task, getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApplyDelayedAsync(@NotNull ExceptionalFunction<T, V> task, long delay, @NotNull TimeUnit unit) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
addDirectListener(
|
||||
res -> runCompleter(promise, () -> {
|
||||
Runnable runnable = createCompleter(res, promise, task);
|
||||
FA future = getFactory().getAsyncExecutor().run(runnable, delay, unit);
|
||||
promise.addDirectListener(_ -> getFactory().getAsyncExecutor().cancel(future));
|
||||
}),
|
||||
promise::completeExceptionally
|
||||
);
|
||||
|
||||
return promise;
|
||||
public <V> @NotNull Promise<V> thenApplyDelayedAsync(@NotNull ExceptionalFunction<T, V> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(task, delay, unit, getFactory().getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenComposeAsync(@NotNull ExceptionalFunction<T, Promise<V>> task) {
|
||||
CompletablePromise<V> promise = createLinked();
|
||||
thenApplyAsync(task).addDirectListener(
|
||||
nestedPromise -> {
|
||||
if (nestedPromise == null) {
|
||||
promise.complete(null);
|
||||
} else {
|
||||
PromiseUtil.propagateCompletion(nestedPromise, promise);
|
||||
PromiseUtil.propagateCancel(promise, nestedPromise);
|
||||
return thenCompose(task, getFactory().getAsyncExecutor());
|
||||
}
|
||||
},
|
||||
promise::completeExceptionally
|
||||
);
|
||||
|
||||
return promise;
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenRunVirtual(@NotNull ExceptionalRunnable task) {
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenRunDelayedVirtual(@NotNull ExceptionalRunnable task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenConsumeVirtual(@NotNull ExceptionalConsumer<T> task) {
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> thenConsumeDelayedVirtual(@NotNull ExceptionalConsumer<T> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenSupplyVirtual(@NotNull ExceptionalSupplier<V> task) {
|
||||
return thenApply(FunctionAdapter.adapt(task), getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenSupplyDelayedVirtual(@NotNull ExceptionalSupplier<V> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(FunctionAdapter.adapt(task), delay, unit, getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApplyVirtual(@NotNull ExceptionalFunction<T, V> task) {
|
||||
return thenApply(task, getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenApplyDelayedVirtual(@NotNull ExceptionalFunction<T, V> task, long delay,
|
||||
@NotNull TimeUnit unit) {
|
||||
return thenApplyDelayed(task, delay, unit, getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> thenComposeVirtual(@NotNull ExceptionalFunction<T, Promise<V>> task) {
|
||||
return thenCompose(task, getFactory().getVirtualExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -404,12 +418,17 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<T> addAsyncListener(@Nullable Consumer<T> successListener, @Nullable Consumer<Throwable> errorListener) {
|
||||
public @NotNull Promise<T> addAsyncListener(@Nullable Consumer<T> successListener,
|
||||
@Nullable Consumer<Throwable> 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());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -420,12 +439,17 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<T> addDirectListener(@Nullable Consumer<T> successListener, @Nullable Consumer<Throwable> errorListener) {
|
||||
public @NotNull Promise<T> addDirectListener(@Nullable Consumer<T> successListener,
|
||||
@Nullable Consumer<Throwable> 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());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -445,7 +469,7 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -480,34 +504,11 @@ public abstract class AbstractPromise<T, FS, FA> implements Promise<T> {
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<T> orDefault(@NotNull ExceptionalFunction<Throwable, T> function) {
|
||||
return useCompletion(
|
||||
() -> {
|
||||
return useCompletion(() -> {
|
||||
CompletablePromise<T> promise = createLinked();
|
||||
addDirectListener(promise::complete, e -> runCompleter(promise, () -> promise.complete(function.apply(e))));
|
||||
return promise;
|
||||
},
|
||||
getFactory()::resolve,
|
||||
getFactory()::error
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<T> toFuture() {
|
||||
return useCompletion(
|
||||
() -> {
|
||||
CompletableFuture<T> future = new CompletableFuture<>();
|
||||
addDirectListener(future::complete, future::completeExceptionally);
|
||||
future.whenComplete((_, e) -> {
|
||||
if (e instanceof CancellationException) {
|
||||
cancel();
|
||||
}
|
||||
});
|
||||
|
||||
return future;
|
||||
},
|
||||
CompletableFuture::completedFuture,
|
||||
CompletableFuture::failedFuture
|
||||
);
|
||||
}, getFactory()::resolve, getFactory()::error);
|
||||
}
|
||||
|
||||
private static class DeferredExecutionException extends ExecutionException {
|
||||
|
||||
@@ -14,22 +14,28 @@ import java.util.*;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public abstract class AbstractPromiseFactory<FS, FA> implements PromiseFactory {
|
||||
public abstract class AbstractPromiseFactory implements PromiseFactory {
|
||||
|
||||
private static final PromiseExecutor<?> VIRTUAL = PromiseExecutor.virtualThreaded();
|
||||
|
||||
public abstract @NotNull Logger getLogger();
|
||||
|
||||
public abstract @NotNull PromiseExecutor<FS> getSyncExecutor();
|
||||
public abstract @NotNull PromiseExecutor<?> getSyncExecutor();
|
||||
|
||||
public abstract @NotNull PromiseExecutor<FA> getAsyncExecutor();
|
||||
public abstract @NotNull PromiseExecutor<?> getAsyncExecutor();
|
||||
|
||||
public @NotNull PromiseExecutor<?> getVirtualExecutor() {
|
||||
return VIRTUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @NotNull Promise<T> wrap(@NotNull CompletionStage<T> completion, @Nullable Future<T> future) {
|
||||
CompletablePromise<T> promise = unresolved();
|
||||
completion.whenComplete((v, e) -> {
|
||||
if (e != null) {
|
||||
promise.completeExceptionally(e);
|
||||
} else {
|
||||
if (e == null) {
|
||||
promise.complete(v);
|
||||
} else {
|
||||
promise.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -41,9 +47,7 @@ public abstract class AbstractPromiseFactory<FS, FA> implements PromiseFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> @NotNull Promise<Map.Entry<K, V>> combine(
|
||||
@NotNull Promise<K> p1, @NotNull Promise<V> p2
|
||||
) {
|
||||
public <K, V> @NotNull Promise<Map.Entry<K, V>> combine(@NotNull Promise<K> p1, @NotNull Promise<V> p2) {
|
||||
return all(p1, p2).thenApply(_ -> new AbstractMap.SimpleImmutableEntry<>(
|
||||
Objects.requireNonNull(p1.getCompletion()).getResult(),
|
||||
Objects.requireNonNull(p2.getCompletion()).getResult()
|
||||
@@ -51,43 +55,45 @@ public abstract class AbstractPromiseFactory<FS, FA> implements PromiseFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <K, V> Promise<Map<K, V>> combineMapped(
|
||||
@NotNull Iterator<Map.Entry<K, Promise<V>>> promises,
|
||||
int expectedSize
|
||||
) {
|
||||
if (!promises.hasNext()) return resolve(Collections.emptyMap());
|
||||
public @NotNull <K, V> Promise<Map<K, V>> combineMapped(@NotNull Iterator<Map.Entry<K, Promise<V>>> promises,
|
||||
int expectedSize) {
|
||||
if (!promises.hasNext()) {
|
||||
return resolve(Collections.emptyMap());
|
||||
}
|
||||
|
||||
return new MappedResultJoiner<>(this, promises, expectedSize).joined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<List<V>> combine(
|
||||
@NotNull Iterator<Promise<V>> promises,
|
||||
int expectedSize
|
||||
) {
|
||||
if (!promises.hasNext()) return resolve(Collections.emptyList());
|
||||
public <V> @NotNull Promise<List<V>> combine(@NotNull Iterator<Promise<V>> promises, int expectedSize) {
|
||||
if (!promises.hasNext()) {
|
||||
return resolve(Collections.emptyList());
|
||||
}
|
||||
|
||||
return new ResultJoiner<>(this, promises, expectedSize).joined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<List<PromiseCompletion<?>>> allSettled(
|
||||
@NotNull Iterator<Promise<?>> promises,
|
||||
int expectedSize
|
||||
) {
|
||||
if (!promises.hasNext()) return resolve(Collections.emptyList());
|
||||
public @NotNull Promise<List<PromiseCompletion<?>>> allSettled(@NotNull Iterator<Promise<?>> promises,
|
||||
int expectedSize) {
|
||||
if (!promises.hasNext()) {
|
||||
return resolve(Collections.emptyList());
|
||||
}
|
||||
|
||||
return new CompletionJoiner(this, promises, expectedSize).joined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Void> all(@NotNull Iterator<Promise<?>> promises) {
|
||||
if (!promises.hasNext()) return resolve(null);
|
||||
if (!promises.hasNext()) {
|
||||
return resolve(null);
|
||||
}
|
||||
|
||||
return new VoidJoiner(this, promises).joined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull Promise<V> race(
|
||||
@NotNull Iterator<Promise<V>> promises,
|
||||
boolean ignoreErrors
|
||||
) {
|
||||
public <V> @NotNull Promise<V> race(@NotNull Iterator<Promise<V>> promises, boolean ignoreErrors) {
|
||||
CompletablePromise<V> promise = unresolved();
|
||||
while (promises.hasNext()) {
|
||||
if (promise.isCompleted()) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.tommyjs.futur.promise;
|
||||
|
||||
import dev.tommyjs.futur.executor.PromiseScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -7,13 +8,12 @@ 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;
|
||||
|
||||
@SuppressWarnings({"FieldMayBeFinal"})
|
||||
public abstract class BasePromise<T, FS, FA> extends AbstractPromise<T, FS, FA> implements CompletablePromise<T> {
|
||||
public abstract class BasePromise<T> extends AbstractPromise<T> implements CompletablePromise<T> {
|
||||
|
||||
private static final VarHandle COMPLETION_HANDLE;
|
||||
private static final VarHandle LISTENERS_HANDLE;
|
||||
@@ -43,15 +43,19 @@ public abstract class BasePromise<T, FS, FA> extends AbstractPromise<T, FS, FA>
|
||||
}
|
||||
|
||||
protected void handleCompletion(@NotNull PromiseCompletion<T> cmp) {
|
||||
if (!COMPLETION_HANDLE.compareAndSet(this, null, cmp)) return;
|
||||
if (!COMPLETION_HANDLE.compareAndSet(this, null, cmp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sync.releaseShared(1);
|
||||
callListeners(cmp);
|
||||
}
|
||||
|
||||
protected Promise<T> completeExceptionallyDelayed(Throwable e, long delay, TimeUnit unit) {
|
||||
protected <F> Promise<T> completeExceptionallyDelayed(Throwable e, long delay, TimeUnit unit,
|
||||
PromiseScheduler<F> scheduler) {
|
||||
runCompleter(this, () -> {
|
||||
FA future = getFactory().getAsyncExecutor().run(() -> completeExceptionally(e), delay, unit);
|
||||
addDirectListener(_ -> getFactory().getAsyncExecutor().cancel(future));
|
||||
F future = scheduler.schedule(() -> completeExceptionally(e), delay, unit);
|
||||
addDirectListener(_ -> scheduler.cancel(future));
|
||||
});
|
||||
|
||||
return this;
|
||||
@@ -59,7 +63,7 @@ public abstract class BasePromise<T, FS, FA> extends AbstractPromise<T, FS, FA>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void callListeners(@NotNull PromiseCompletion<T> cmp) {
|
||||
Iterator<PromiseListener<T>> iter = ((Iterable<PromiseListener<T>>) LISTENERS_HANDLE.getAndSet(this, null)).iterator();
|
||||
var iter = ((Iterable<PromiseListener<T>>) LISTENERS_HANDLE.getAndSet(this, null)).iterator();
|
||||
try {
|
||||
while (iter.hasNext()) {
|
||||
callListener(iter.next(), cmp);
|
||||
@@ -75,11 +79,14 @@ public abstract class BasePromise<T, FS, FA> extends AbstractPromise<T, FS, FA>
|
||||
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));
|
||||
}
|
||||
@@ -125,16 +132,23 @@ public abstract class BasePromise<T, FS, FA> extends AbstractPromise<T, FS, FA>
|
||||
return joinCompletionUnchecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getNow() {
|
||||
return joinCompletionUnchecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<T> timeout(long time, @NotNull TimeUnit unit) {
|
||||
Exception e = new CancellationException("Promise timed out after " + time + " " + unit.toString().toLowerCase());
|
||||
return completeExceptionallyDelayed(e, time, unit);
|
||||
Exception e = new CancellationException(
|
||||
"Promise timed out after " + time + " " + unit.toString().toLowerCase());
|
||||
return completeExceptionallyDelayed(e, time, unit, PromiseScheduler.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<T> maxWaitTime(long time, @NotNull TimeUnit unit) {
|
||||
Exception e = new TimeoutException("Promise stopped waiting after " + time + " " + unit.toString().toLowerCase());
|
||||
return completeExceptionallyDelayed(e, time, unit);
|
||||
Exception e = new TimeoutException(
|
||||
"Promise stopped waiting after " + time + " " + unit.toString().toLowerCase());
|
||||
return completeExceptionallyDelayed(e, time, unit, PromiseScheduler.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,6 +176,32 @@ public abstract class BasePromise<T, FS, FA> extends AbstractPromise<T, FS, FA>
|
||||
return completion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<T> toFuture() {
|
||||
return useCompletion(() -> {
|
||||
CompletableFuture<T> 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletionStage<T> toCompletionStage() {
|
||||
return useCompletion(() -> {
|
||||
CompletableFuture<T> future = new CompletableFuture<>();
|
||||
addDirectListener(future::complete, future::completeExceptionally);
|
||||
return future;
|
||||
}, CompletableFuture::completedStage, CompletableFuture::failedStage);
|
||||
}
|
||||
|
||||
private static final class Sync extends AbstractQueuedSynchronizer {
|
||||
|
||||
private Sync() {
|
||||
|
||||
@@ -2,11 +2,9 @@ package dev.tommyjs.futur.promise;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public abstract class CompletedPromise<T, FS, FA> extends AbstractPromise<T, FS, FA> {
|
||||
public abstract class CompletedPromise<T> extends AbstractPromise<T> {
|
||||
|
||||
private static final PromiseCompletion<?> EMPTY = new PromiseCompletion<>();
|
||||
|
||||
@@ -59,6 +57,11 @@ public abstract class CompletedPromise<T, FS, FA> extends AbstractPromise<T, FS,
|
||||
return joinCompletionUnchecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getNow() {
|
||||
return joinCompletionUnchecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PromiseCompletion<T> getCompletion() {
|
||||
return completion;
|
||||
@@ -69,4 +72,19 @@ public abstract class CompletedPromise<T, FS, FA> extends AbstractPromise<T, FS,
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<T> toFuture() {
|
||||
if (completion.isSuccess()) {
|
||||
return CompletableFuture.completedFuture(completion.result());
|
||||
}
|
||||
|
||||
assert completion.exception() != null;
|
||||
return CompletableFuture.failedFuture(completion.exception());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletionStage<T> toCompletionStage() {
|
||||
return toFuture();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -135,7 +135,8 @@ public interface Promise<T> {
|
||||
* @param unit the time unit of the delay
|
||||
* @return a new promise that completes after the task is executed
|
||||
*/
|
||||
@NotNull Promise<Void> thenConsumeDelayedSync(@NotNull ExceptionalConsumer<T> task, long delay, @NotNull TimeUnit unit);
|
||||
@NotNull Promise<Void> thenConsumeDelayedSync(@NotNull ExceptionalConsumer<T> 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<T> {
|
||||
* @param unit the time unit of the delay
|
||||
* @return a new promise that completes, after the task is executed, with the task result
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenSupplyDelayedSync(@NotNull ExceptionalSupplier<V> task, long delay, @NotNull TimeUnit unit);
|
||||
<V> @NotNull Promise<V> thenSupplyDelayedSync(@NotNull ExceptionalSupplier<V> 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<T> {
|
||||
* @param unit the time unit of the delay
|
||||
* @return a new promise that completes, after the task is executed, with the task result
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenApplyDelayedSync(@NotNull ExceptionalFunction<T, V> task, long delay, @NotNull TimeUnit unit);
|
||||
<V> @NotNull Promise<V> thenApplyDelayedSync(@NotNull ExceptionalFunction<T, V> 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<T> {
|
||||
* @param unit the time unit of the delay
|
||||
* @return a new promise that completes after the task is executed
|
||||
*/
|
||||
@NotNull Promise<Void> thenConsumeDelayedAsync(@NotNull ExceptionalConsumer<T> task, long delay, @NotNull TimeUnit unit);
|
||||
@NotNull Promise<Void> thenConsumeDelayedAsync(@NotNull ExceptionalConsumer<T> 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<T> {
|
||||
* @param unit the time unit of the delay
|
||||
* @return a new promise that completes, after the task is executed, with the task result
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenSupplyDelayedAsync(@NotNull ExceptionalSupplier<V> task, long delay, @NotNull TimeUnit unit);
|
||||
<V> @NotNull Promise<V> thenSupplyDelayedAsync(@NotNull ExceptionalSupplier<V> 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<T> {
|
||||
* @param unit the time unit of the delay
|
||||
* @return a new promise that completes, after the task is executed, with the task result
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenApplyDelayedAsync(@NotNull ExceptionalFunction<T, V> task, long delay, @NotNull TimeUnit unit);
|
||||
<V> @NotNull Promise<V> thenApplyDelayedAsync(@NotNull ExceptionalFunction<T, V> task, long delay,
|
||||
@NotNull TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed by the async
|
||||
@@ -309,6 +315,119 @@ public interface Promise<T> {
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenComposeAsync(@NotNull ExceptionalFunction<T, Promise<V>> task);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes.
|
||||
* The task will be executed in a virtual thread, 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<Void> thenRunVirtual(@NotNull ExceptionalRunnable task);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes.
|
||||
* The task will be executed in a virtual thread 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<Void> thenRunDelayedVirtual(@NotNull ExceptionalRunnable task, long delay, @NotNull TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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<Void> thenConsumeVirtual(@NotNull ExceptionalConsumer<T> task);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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<Void> thenConsumeDelayedVirtual(@NotNull ExceptionalConsumer<T> task, long delay,
|
||||
@NotNull TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenSupplyVirtual(@NotNull ExceptionalSupplier<V> task);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenSupplyDelayedVirtual(@NotNull ExceptionalSupplier<V> task, long delay,
|
||||
@NotNull TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenApplyVirtual(@NotNull ExceptionalFunction<T, V> task);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenApplyDelayedVirtual(@NotNull ExceptionalFunction<T, V> task, long delay,
|
||||
@NotNull TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Chains a task to be executed after this promise completes. The task will be executed
|
||||
* in a virtual thread 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
|
||||
*/
|
||||
<V> @NotNull Promise<V> thenComposeVirtual(@NotNull ExceptionalFunction<T, Promise<V>> 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
|
||||
@@ -365,7 +484,8 @@ public interface Promise<T> {
|
||||
* @param errorHandler the function to call on error
|
||||
* @return continuation of the promise chain
|
||||
*/
|
||||
@NotNull Promise<T> addDirectListener(@Nullable Consumer<T> successHandler, @Nullable Consumer<Throwable> errorHandler);
|
||||
@NotNull Promise<T> addDirectListener(@Nullable Consumer<T> successHandler,
|
||||
@Nullable Consumer<Throwable> errorHandler);
|
||||
|
||||
/**
|
||||
* Adds a listener to this promise that will be executed immediately when this promise completes,
|
||||
@@ -394,7 +514,8 @@ public interface Promise<T> {
|
||||
* @param successHandler the function to call on success
|
||||
* @param errorHandler the function to call on error
|
||||
*/
|
||||
@NotNull Promise<T> addAsyncListener(@Nullable Consumer<T> successHandler, @Nullable Consumer<Throwable> errorHandler);
|
||||
@NotNull Promise<T> addAsyncListener(@Nullable Consumer<T> successHandler,
|
||||
@Nullable Consumer<Throwable> errorHandler);
|
||||
|
||||
/**
|
||||
* Adds a listener to this promise that will be called if the promise is completed successfully.
|
||||
@@ -592,6 +713,18 @@ public interface Promise<T> {
|
||||
*/
|
||||
@Nullable PromiseCompletion<T> getCompletion();
|
||||
|
||||
/**
|
||||
* This method does not block and will return the result immediately if available.
|
||||
* Get result and throws a {@link CompletionException} if the promise completed exceptionally.
|
||||
* If the promise has not completed yet, it will throw an {@link IllegalStateException}.
|
||||
*
|
||||
* @return the result of the promise
|
||||
* @throws IllegalStateException if the promise has not completed yet
|
||||
* @throws CancellationException if the promise was cancelled
|
||||
* @throws CompletionException if the promise completed exceptionally
|
||||
*/
|
||||
T getNow();
|
||||
|
||||
/**
|
||||
* Returns whether this promise has completed.
|
||||
*
|
||||
@@ -601,10 +734,18 @@ public interface Promise<T> {
|
||||
|
||||
/**
|
||||
* Converts this promise to a {@link CompletableFuture}. The returned future will complete with the
|
||||
* result of this promise when it completes.
|
||||
* result of this promise and the promise will complete with the result of the future.
|
||||
*
|
||||
* @return a future that will complete with the result of this promise
|
||||
* @return a future linked to this promise
|
||||
*/
|
||||
@NotNull CompletableFuture<T> toFuture();
|
||||
|
||||
/**
|
||||
* Converts this promise to a {@link CompletionStage}.
|
||||
* The returned stage will complete with the result of this promise.
|
||||
*
|
||||
* @return a completion stage linked to this promise result
|
||||
*/
|
||||
@NotNull CompletionStage<T> toCompletionStage();
|
||||
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Represents the result of a {@link Promise}, containing either an optional result or an exception.
|
||||
*/
|
||||
public class PromiseCompletion<T> {
|
||||
|
||||
private @Nullable T result;
|
||||
private @Nullable Throwable exception;
|
||||
public record PromiseCompletion<T>(@Nullable T result, @Nullable Throwable exception) {
|
||||
|
||||
/**
|
||||
* Creates a new successful completion.
|
||||
@@ -19,7 +18,7 @@ public class PromiseCompletion<T> {
|
||||
* @param result the result
|
||||
*/
|
||||
public PromiseCompletion(@Nullable T result) {
|
||||
this.result = result;
|
||||
this(result, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,14 +27,14 @@ public class PromiseCompletion<T> {
|
||||
* @param exception the exception
|
||||
*/
|
||||
public PromiseCompletion(@NotNull Throwable exception) {
|
||||
this.exception = exception;
|
||||
this(null, exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new successful completion with a result of {@code null}.
|
||||
*/
|
||||
public PromiseCompletion() {
|
||||
this((T) null);
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,15 +60,10 @@ public class PromiseCompletion<T> {
|
||||
*
|
||||
* @return {@code true} if the completion was cancelled, {@code false} otherwise
|
||||
*/
|
||||
public boolean wasCancelled() {
|
||||
public boolean isCancelled() {
|
||||
return exception instanceof CancellationException;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean wasCanceled() {
|
||||
return wasCancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of the completion.
|
||||
*
|
||||
@@ -88,4 +82,32 @@ public class PromiseCompletion<T> {
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result or throws a {@link CompletionException} if the completion was exceptional.
|
||||
*
|
||||
* @return the result of the completion
|
||||
* @throws CompletionException if the completion was exceptional
|
||||
*/
|
||||
public T get() {
|
||||
if (isSuccess()) {
|
||||
return getResult();
|
||||
} else {
|
||||
throw new CompletionException(getException());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result or throws an {@link ExecutionException} if the completion was exceptional.
|
||||
*
|
||||
* @return the result of the completion
|
||||
* @throws ExecutionException if the completion was exceptional
|
||||
*/
|
||||
public T getChecked() throws ExecutionException {
|
||||
if (isSuccess()) {
|
||||
return getResult();
|
||||
} else {
|
||||
throw new ExecutionException(getException());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface PromiseFactory {
|
||||
*/
|
||||
static @NotNull PromiseFactory of(@NotNull Logger logger, @NotNull PromiseExecutor<?> syncExecutor,
|
||||
@NotNull PromiseExecutor<?> asyncExecutor) {
|
||||
return new PromiseFactoryImpl<>(logger, syncExecutor, asyncExecutor);
|
||||
return new PromiseFactoryImpl(logger, syncExecutor, asyncExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ public interface PromiseFactory {
|
||||
* @return the new promise factory
|
||||
*/
|
||||
static @NotNull PromiseFactory of(@NotNull Logger logger, @NotNull PromiseExecutor<?> executor) {
|
||||
return new PromiseFactoryImpl<>(logger, executor, executor);
|
||||
return new PromiseFactoryImpl(logger, executor, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +108,7 @@ public interface PromiseFactory {
|
||||
*/
|
||||
default <T> @NotNull Promise<T> wrap(@NotNull CompletableFuture<T> future) {
|
||||
return wrap(future, future);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines two promises into a single promise that resolves when both promises are completed.
|
||||
@@ -310,8 +310,7 @@ public interface PromiseFactory {
|
||||
* @param expectedSize the expected size of the iterator (used for optimization)
|
||||
* @return the combined promise
|
||||
*/
|
||||
@NotNull Promise<List<PromiseCompletion<?>>> allSettled(@NotNull Iterator<Promise<?>> promises,
|
||||
int expectedSize);
|
||||
@NotNull Promise<List<PromiseCompletion<?>>> allSettled(@NotNull Iterator<Promise<?>> promises, int expectedSize);
|
||||
|
||||
/**
|
||||
* Combines multiple promises into a single promise that completes when all promises
|
||||
|
||||
@@ -5,17 +5,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class PromiseFactoryImpl<FS, FA> extends AbstractPromiseFactory<FS, FA> {
|
||||
public class PromiseFactoryImpl extends AbstractPromiseFactory {
|
||||
|
||||
private final @NotNull Logger logger;
|
||||
private final @NotNull PromiseExecutor<FS> syncExecutor;
|
||||
private final @NotNull PromiseExecutor<FA> asyncExecutor;
|
||||
private final @NotNull PromiseExecutor<?> syncExecutor;
|
||||
private final @NotNull PromiseExecutor<?> asyncExecutor;
|
||||
|
||||
public PromiseFactoryImpl(
|
||||
@NotNull Logger logger,
|
||||
@NotNull PromiseExecutor<FS> syncExecutor,
|
||||
@NotNull PromiseExecutor<FA> asyncExecutor
|
||||
) {
|
||||
public PromiseFactoryImpl(@NotNull Logger logger, @NotNull PromiseExecutor<?> syncExecutor,
|
||||
@NotNull PromiseExecutor<?> asyncExecutor) {
|
||||
this.logger = logger;
|
||||
this.syncExecutor = syncExecutor;
|
||||
this.asyncExecutor = asyncExecutor;
|
||||
@@ -47,40 +44,43 @@ public class PromiseFactoryImpl<FS, FA> extends AbstractPromiseFactory<FS, FA> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PromiseExecutor<FS> getSyncExecutor() {
|
||||
public @NotNull PromiseExecutor<?> getSyncExecutor() {
|
||||
return syncExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PromiseExecutor<FA> getAsyncExecutor() {
|
||||
public @NotNull PromiseExecutor<?> getAsyncExecutor() {
|
||||
return asyncExecutor;
|
||||
}
|
||||
|
||||
private class PromiseImpl<T> extends BasePromise<T, FS, FA> {
|
||||
private class PromiseImpl<T> extends BasePromise<T> {
|
||||
|
||||
PromiseImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull AbstractPromiseFactory<FS, FA> getFactory() {
|
||||
public @NotNull AbstractPromiseFactory getFactory() {
|
||||
return PromiseFactoryImpl.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class CompletedPromiseImpl<T> extends CompletedPromise<T, FS, FA> {
|
||||
private class CompletedPromiseImpl<T> extends CompletedPromise<T> {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull AbstractPromiseFactory<FS, FA> getFactory() {
|
||||
public @NotNull AbstractPromiseFactory getFactory() {
|
||||
return PromiseFactoryImpl.this;
|
||||
}
|
||||
|
||||
|
||||
@@ -245,14 +245,14 @@ public final class PromiseTests {
|
||||
@Test
|
||||
public void testImmediate1() {
|
||||
var promise = promises.start().thenSupply(() -> 10);
|
||||
assert promise.isCompleted() && promise instanceof CompletedPromise<?,?,?>;
|
||||
assert promise.isCompleted() && promise instanceof CompletedPromise;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImmediate2() {
|
||||
var resolved = promises.resolve(10);
|
||||
var promise = promises.start().thenCompose(_ -> resolved);
|
||||
assert promise.isCompleted() && promise instanceof CompletedPromise<?,?,?>;
|
||||
assert promise.isCompleted() && promise instanceof CompletedPromise;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Reference in New Issue
Block a user