return Promise from AppUIExecutor

This commit is contained in:
peter
2018-04-26 10:17:07 +02:00
parent 0293e1a878
commit e5f6093e08
2 changed files with 39 additions and 17 deletions
@@ -6,7 +6,9 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.CancellablePromise;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
/**
@@ -73,5 +75,17 @@ public interface AppUIExecutor extends Executor {
@NotNull
@Contract(pure=true)
AppUIExecutor expireWith(@NotNull Disposable parentDisposable);
/**
* Schedule the given task's execution and return a Promise that allows to get the result when the task is complete,
* or cancel the task if it's no longer needed.
*/
<T> CancellablePromise<T> submit(Callable<T> task);
/**
* Schedule the given task's execution and return a Promise that allows to check if the task is complete,
* or cancel the task if it's no longer needed.
*/
CancellablePromise<?> submit(Runnable task);
}
@@ -12,12 +12,14 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.AsyncPromise;
import org.jetbrains.concurrency.CancellablePromise;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Callable;
/**
* @author peter
@@ -163,31 +165,37 @@ class AppUIExecutorImpl implements AppUIExecutor {
}
@Override
public void execute(@NotNull Runnable runnable) {
CompletableFuture<Void> future = new CompletableFuture<>();
public CancellablePromise<?> submit(Runnable task) {
return submit(() -> { task.run(); return null; });
}
@Override
public void execute(@NotNull Runnable command) {
submit(command);
}
@Override
public <T> CancellablePromise<T> submit(Callable<T> task) {
AsyncPromise<T> promise = new AsyncPromise<>();
if (!myDisposables.isEmpty()) {
List<Disposable> children = new ArrayList<>();
for (Disposable parent : myDisposables) {
Disposable child = new Disposable() {
@Override
public void dispose() {
future.cancel(false);
}
};
Disposable child = promise::cancel;
children.add(child);
Disposer.register(parent, child);
}
future.whenComplete((v, t) -> children.forEach(Disposer::dispose));
promise.onProcessed(__ -> children.forEach(Disposer::dispose));
}
checkConstraints(runnable, future, new ArrayList<>());
checkConstraints(task, promise, new ArrayList<>());
return promise;
}
private void checkConstraints(@NotNull Runnable runnable, CompletableFuture<Void> future, List<ConstrainedExecutor> log) {
private <T> void checkConstraints(@NotNull Callable<T> task, AsyncPromise<T> future, List<ConstrainedExecutor> log) {
Application app = ApplicationManager.getApplication();
if (!app.isDispatchThread()) {
app.invokeLater(() -> checkConstraints(runnable, future, log), myModality);
app.invokeLater(() -> checkConstraints(task, future, log), myModality);
return;
}
@@ -199,17 +207,17 @@ class AppUIExecutorImpl implements AppUIExecutor {
if (log.size() > 1000) {
LOG.error("Too many reschedule requests, probably constraints can't be satisfied all together: " + log.subList(100, 120));
}
constraint.rescheduleInCorrectContext(() -> checkConstraints(runnable, future, log));
constraint.rescheduleInCorrectContext(() -> checkConstraints(task, future, log));
return;
}
}
try {
runnable.run();
future.complete(null);
T result = task.call();
future.setResult(result);
}
catch (Throwable e) {
future.completeExceptionally(e);
future.setError(e);
}
}