|
5 | 5 | import com.jnape.palatable.lambda.functor.Applicative; |
6 | 6 | import com.jnape.palatable.lambda.monad.Monad; |
7 | 7 |
|
| 8 | +import java.util.concurrent.CompletableFuture; |
| 9 | +import java.util.concurrent.Executor; |
8 | 10 | import java.util.function.Function; |
| 11 | +import java.util.function.Supplier; |
9 | 12 |
|
10 | 13 | import static com.jnape.palatable.lambda.adt.Unit.UNIT; |
| 14 | +import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; |
| 15 | +import static java.util.concurrent.CompletableFuture.supplyAsync; |
11 | 16 |
|
12 | 17 | /** |
13 | 18 | * A {@link Monad} representing some effectful computation to be performed. |
|
17 | 22 | public interface IO<A> extends Monad<A, IO<?>> { |
18 | 23 |
|
19 | 24 | /** |
20 | | - * Run the effect represented by this {@link IO} instance |
| 25 | + * Run the effect represented by this {@link IO} instance, blocking the current thread until the effect terminates. |
21 | 26 | * |
22 | 27 | * @return the result of the effect |
23 | 28 | */ |
24 | 29 | A unsafePerformIO(); |
25 | 30 |
|
| 31 | + /** |
| 32 | + * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will |
| 33 | + * immediately run the effect in terms of the implicit {@link Executor} available to {@link CompletableFuture} |
| 34 | + * (usually the {@link java.util.concurrent.ForkJoinPool}). Note that specific {@link IO} constructions may allow |
| 35 | + * this method to delegate to externally-managed {@link CompletableFuture} instead of synthesizing their own. |
| 36 | + * |
| 37 | + * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result |
| 38 | + * @see IO#unsafePerformAsyncIO(Executor) |
| 39 | + */ |
| 40 | + default CompletableFuture<A> unsafePerformAsyncIO() { |
| 41 | + return supplyAsync(this::unsafePerformIO); |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will |
| 46 | + * immediately run the effect in terms of the provided {@link Executor}. Note that specific {@link IO} |
| 47 | + * constructions may allow this method to delegate to externally-managed {@link CompletableFuture} instead of |
| 48 | + * synthesizing their own. |
| 49 | + * |
| 50 | + * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result |
| 51 | + * @see IO#unsafePerformAsyncIO() |
| 52 | + */ |
| 53 | + default CompletableFuture<A> unsafePerformAsyncIO(Executor executor) { |
| 54 | + return supplyAsync(this::unsafePerformIO, executor); |
| 55 | + } |
| 56 | + |
26 | 57 | /** |
27 | 58 | * {@inheritDoc} |
28 | 59 | */ |
@@ -116,4 +147,35 @@ static IO<Unit> io(Runnable runnable) { |
116 | 147 | static <A> IO<A> io(Fn1<Unit, A> fn1) { |
117 | 148 | return io(() -> fn1.apply(UNIT)); |
118 | 149 | } |
| 150 | + |
| 151 | + /** |
| 152 | + * Static factory method for creating an {@link IO} from an externally managed source of |
| 153 | + * {@link CompletableFuture completable futures}. |
| 154 | + * <p> |
| 155 | + * Note that constructing an {@link IO} this way results in no intermediate futures being constructed by either |
| 156 | + * {@link IO#unsafePerformAsyncIO()} or {@link IO#unsafePerformAsyncIO(Executor)}, and {@link IO#unsafePerformIO()} |
| 157 | + * is synonymous with invoking {@link CompletableFuture#get()} on the externally managed future. |
| 158 | + * |
| 159 | + * @param supplier the source of externally managed {@link CompletableFuture completable futures} |
| 160 | + * @param <A> the result type |
| 161 | + * @return the {@link IO} |
| 162 | + */ |
| 163 | + static <A> IO<A> externallyManaged(Supplier<CompletableFuture<A>> supplier) { |
| 164 | + return new IO<A>() { |
| 165 | + @Override |
| 166 | + public A unsafePerformIO() { |
| 167 | + return checked(() -> unsafePerformAsyncIO().get()).get(); |
| 168 | + } |
| 169 | + |
| 170 | + @Override |
| 171 | + public CompletableFuture<A> unsafePerformAsyncIO() { |
| 172 | + return supplier.get(); |
| 173 | + } |
| 174 | + |
| 175 | + @Override |
| 176 | + public CompletableFuture<A> unsafePerformAsyncIO(Executor executor) { |
| 177 | + return supplier.get(); |
| 178 | + } |
| 179 | + }; |
| 180 | + } |
119 | 181 | } |
0 commit comments