Skip to content

Commit

Permalink
refactor: improve generic type declaration 🧬
Browse files Browse the repository at this point in the history
  • Loading branch information
oldratlee committed Apr 30, 2024
1 parent f9c2f44 commit 87afc5d
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ public static <T> CompletableFuture<Void> acceptEitherSuccessAsync(
* @see CompletionStage#applyToEither(CompletionStage, Function)
*/
public static <T, U> CompletableFuture<U> applyToEitherSuccess(
CompletionStage<? extends T> cf1, CompletionStage<? extends T> cf2, Function<? super T, U> fn) {
CompletionStage<? extends T> cf1, CompletionStage<? extends T> cf2, Function<? super T, ? extends U> fn) {
final CompletionStage<? extends T>[] css = requireCfsAndEleNonNull(cf1, cf2);
requireNonNull(fn, "fn is null");

Expand All @@ -907,7 +907,7 @@ public static <T, U> CompletableFuture<U> applyToEitherSuccess(
* @see CompletionStage#applyToEitherAsync(CompletionStage, Function)
*/
public static <T, U> CompletableFuture<U> applyToEitherSuccessAsync(
CompletionStage<? extends T> cf1, CompletionStage<? extends T> cf2, Function<? super T, U> fn) {
CompletionStage<? extends T> cf1, CompletionStage<? extends T> cf2, Function<? super T, ? extends U> fn) {
final CompletionStage<? extends T>[] css = requireCfsAndEleNonNull(cf1, cf2);
requireNonNull(fn, "fn is null");

Expand All @@ -929,7 +929,7 @@ public static <T, U> CompletableFuture<U> applyToEitherSuccessAsync(
*/
public static <T, U> CompletableFuture<U> applyToEitherSuccessAsync(
CompletionStage<? extends T> cf1, CompletionStage<? extends T> cf2,
Function<? super T, U> fn, Executor executor) {
Function<? super T, ? extends U> fn, Executor executor) {
final CompletionStage<? extends T>[] css = requireCfsAndEleNonNull(cf1, cf2);
requireNonNull(fn, "fn is null");
requireNonNull(executor, "executor is null");
Expand Down Expand Up @@ -1029,6 +1029,7 @@ public static <T> CompletableFuture<T> failedFuture(Throwable ex) {
if (IS_JAVA9_PLUS) {
return CompletableFuture.failedFuture(ex);
}
requireNonNull(ex, "ex is null");
final CompletableFuture<T> cf = new CompletableFuture<>();
cf.completeExceptionally(ex);
return cf;
Expand Down Expand Up @@ -1163,16 +1164,16 @@ public static <T> CompletableFuture<T> exceptionallyAsync(
* @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter
* @return given CompletableFuture
*/
public static <T> CompletableFuture<T> orTimeout(CompletableFuture<T> cf, long timeout, TimeUnit unit) {
public static <C extends CompletableFuture<?>> C orTimeout(C cf, long timeout, TimeUnit unit) {
if (IS_JAVA9_PLUS) {
return cf.orTimeout(timeout, unit);
}

requireNonNull(unit, "unit is null");
// below code is copied from CompletableFuture#orTimeout with small adoption
if (!cf.isDone()) {
ScheduledFuture<?> f = Delayer.delayToTimoutCf(cf, timeout, unit);
cf.whenComplete(new FutureCanceller(f));
cf.orTimeout(timeout, unit);
} else {
requireNonNull(unit, "unit is null");
// below code is copied from CompletableFuture#orTimeout with small adoption
if (!cf.isDone()) {
ScheduledFuture<?> f = Delayer.delayToTimoutCf(cf, timeout, unit);
cf.whenComplete(new FutureCanceller(f));
}
}
return cf;
}
Expand All @@ -1185,17 +1186,17 @@ public static <T> CompletableFuture<T> orTimeout(CompletableFuture<T> cf, long t
* @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter
* @return given CompletableFuture
*/
public static <T> CompletableFuture<T> completeOnTimeout(
CompletableFuture<T> cf, @Nullable T value, long timeout, TimeUnit unit) {
public static <T, C extends CompletableFuture<? super T>> C completeOnTimeout(
C cf, @Nullable T value, long timeout, TimeUnit unit) {
if (IS_JAVA9_PLUS) {
return cf.completeOnTimeout(value, timeout, unit);
}

requireNonNull(unit, "unit is null");
// below code is copied from CompletableFuture#completeOnTimeout with small adoption
if (!cf.isDone()) {
ScheduledFuture<?> f = Delayer.delayToCompleteCf(cf, value, timeout, unit);
cf.whenComplete(new FutureCanceller(f));
cf.completeOnTimeout(value, timeout, unit);
} else {
requireNonNull(unit, "unit is null");
// below code is copied from CompletableFuture#completeOnTimeout with small adoption
if (!cf.isDone()) {
ScheduledFuture<?> f = Delayer.delayToCompleteCf(cf, value, timeout, unit);
cf.whenComplete(new FutureCanceller(f));
}
}
return cf;
}
Expand All @@ -1215,7 +1216,6 @@ public static <T> CompletableFuture<T> exceptionallyCompose(
if (IS_JAVA12_PLUS) {
return cf.exceptionallyCompose(fn);
}

requireNonNull(fn, "fn is null");
// below code is copied from CompletionStage.exceptionallyCompose
return cf.handle((r, ex) -> (ex == null) ? cf : fn.apply(ex)).thenCompose(identity());
Expand Down Expand Up @@ -1249,7 +1249,6 @@ public static <T> CompletableFuture<T> exceptionallyComposeAsync(
if (IS_JAVA12_PLUS) {
return cf.exceptionallyComposeAsync(fn, executor);
}

requireNonNull(fn, "fn is null");
requireNonNull(executor, "executor is null");
// below code is copied from CompletionStage.exceptionallyComposeAsync
Expand Down Expand Up @@ -1294,7 +1293,6 @@ public static <T> CompletableFuture<T> exceptionallyComposeAsync(
@Nullable
public static <T> T join(CompletableFuture<T> cf, long timeout, TimeUnit unit) {
if (cf.isDone()) return cf.join();

return orTimeout(copy(cf), timeout, unit).join();
}

Expand All @@ -1313,7 +1311,7 @@ public static <T> T join(CompletableFuture<T> cf, long timeout, TimeUnit unit) {
*/
@Contract(pure = true)
@Nullable
public static <T> T resultNow(CompletableFuture<T> cf) {
public static <T> T resultNow(CompletableFuture<? extends T> cf) {
if (IS_JAVA19_PLUS) {
return cf.resultNow();
}
Expand Down Expand Up @@ -1350,7 +1348,7 @@ public static <T> T resultNow(CompletableFuture<T> cf) {
* @see CompletableFuture#resultNow()
*/
@Contract(pure = true)
public static <T> Throwable exceptionNow(CompletableFuture<T> cf) {
public static Throwable exceptionNow(CompletableFuture<?> cf) {
if (IS_JAVA19_PLUS) {
return cf.exceptionNow();
}
Expand Down Expand Up @@ -1388,7 +1386,7 @@ public static <T> Throwable exceptionNow(CompletableFuture<T> cf) {
* @see Future.State
*/
@Contract(pure = true)
public static <T> CffuState state(CompletableFuture<T> cf) {
public static CffuState state(CompletableFuture<?> cf) {
if (IS_JAVA19_PLUS) {
return CffuState.toCffuState(cf.state());
}
Expand Down Expand Up @@ -1424,7 +1422,7 @@ public static <T> CffuState state(CompletableFuture<T> cf) {
* @param supplier a function returning the value to be used to complete given CompletableFuture
* @return given CompletableFuture
*/
public static <T> CompletableFuture<T> completeAsync(CompletableFuture<T> cf, Supplier<? extends T> supplier) {
public static <T, C extends CompletableFuture<? super T>> C completeAsync(C cf, Supplier<? extends T> supplier) {
return completeAsync(cf, supplier, AsyncPoolHolder.ASYNC_POOL);
}

Expand All @@ -1436,15 +1434,16 @@ public static <T> CompletableFuture<T> completeAsync(CompletableFuture<T> cf, Su
* @param executor the executor to use for asynchronous execution
* @return given CompletableFuture
*/
public static <T> CompletableFuture<T> completeAsync(
CompletableFuture<T> cf, Supplier<? extends T> supplier, Executor executor) {
public static <T, C extends CompletableFuture<? super T>> C completeAsync(
C cf, Supplier<? extends T> supplier, Executor executor) {
if (IS_JAVA9_PLUS) {
return cf.completeAsync(supplier, executor);
cf.completeAsync(supplier, executor);
} else {
requireNonNull(supplier, "supplier is null");
requireNonNull(executor, "executor is null");
// below code is copied from CompletableFuture#completeAsync with small adoption
executor.execute(new CfCompleterBySupplier<>(cf, supplier));
}
requireNonNull(supplier, "supplier is null");
requireNonNull(executor, "executor is null");
// below code is copied from CompletableFuture#completeAsync with small adoption
executor.execute(new CfCompleterBySupplier<>(cf, supplier));
return cf;
}

Expand Down Expand Up @@ -1490,11 +1489,10 @@ public static <T> CompletableFuture<T> copy(CompletableFuture<T> cf) {
/**
* Returns a new incomplete CompletableFuture of the type to be returned by a CompletionStage method.
*
* @param <T> the type of the value
* @return a new CompletableFuture
*/
@Contract(pure = true)
public static <T, U> CompletableFuture<U> newIncompleteFuture(CompletableFuture<T> cf) {
public static <U> CompletableFuture<U> newIncompleteFuture(CompletableFuture<?> cf) {
if (IS_JAVA9_PLUS) {
return cf.newIncompleteFuture();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public static ScheduledFuture<?> delayToTimoutCf(CompletableFuture<?> cf, long d
* @return a Future can be used to cancel the delayed task(complete CF)
* @see FutureCanceller
*/
public static <T> ScheduledFuture<?> delayToCompleteCf(CompletableFuture<T> cf, T value, long delay, TimeUnit unit) {
public static <T> ScheduledFuture<?> delayToCompleteCf(
CompletableFuture<? super T> cf, T value, long delay, TimeUnit unit) {
return delay(new CfCompleter<>(cf, value), delay, unit);
}

Expand Down Expand Up @@ -128,11 +129,10 @@ public void run() {
* Action to complete cf
*/
final class CfCompleter<T> implements Runnable {
private final CompletableFuture<T> cf;
private final CompletableFuture<? super T> cf;
private final T value;

@SuppressWarnings("BoundedWildcard")
CfCompleter(CompletableFuture<T> cf, T value) {
CfCompleter(CompletableFuture<? super T> cf, T value) {
this.cf = cf;
this.value = value;
}
Expand Down Expand Up @@ -171,10 +171,10 @@ public void accept(Object ignore, Throwable ex) {
@SuppressFBWarnings("SE_BAD_FIELD")
final class CfCompleterBySupplier<T> extends ForkJoinTask<Void>
implements Runnable, CompletableFuture.AsynchronousCompletionTask {
CompletableFuture<T> dep;
Supplier<? extends T> fn;
private CompletableFuture<? super T> dep;
private Supplier<? extends T> fn;

CfCompleterBySupplier(CompletableFuture<T> dep, Supplier<? extends T> fn) {
CfCompleterBySupplier(CompletableFuture<? super T> dep, Supplier<? extends T> fn) {
this.dep = dep;
this.fn = fn;
}
Expand All @@ -196,7 +196,7 @@ public boolean exec() {

@Override
public void run() {
CompletableFuture<T> d;
CompletableFuture<? super T> d;
Supplier<? extends T> f;
if ((d = dep) != null && (f = fn) != null) {
dep = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;

import static io.foldright.cffu.CompletableFutureUtils.*;
import static io.foldright.test_utils.TestUtils.*;
Expand Down Expand Up @@ -1005,6 +1004,23 @@ void test_executor() {
assertSame(e, screenExecutor(e));
}

////////////////////////////////////////////////////////////////////////////////
//# check type parameter declaration, Variance(covariance/contravariance)
////////////////////////////////////////////////////////////////////////////////

@Test
@SuppressWarnings("UnnecessaryLocalVariable")
void checkTypeParameterDeclaration() throws Exception {
final CompletableFuture<Integer> f = completedFuture(42);

final CompletableFuture<? extends Integer> fe = f;
CompletableFutureUtils.peek(fe, (v, ex) -> {
}).get();

final CompletableFuture<? super Integer> fs = f;
CompletableFutureUtils.completeAsync(fs, () -> 0).complete(1);
}

////////////////////////////////////////////////////////////////////////////////
//# test helper fields
////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 87afc5d

Please sign in to comment.