package org.fungsi.concurrent; import org.fungsi.Either; import org.fungsi.Throwables; import java.time.Duration; import java.util.Deque; import java.util.LinkedList; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; final class PromiseImpl<T> implements Promise<T> { volatile Either<T, Throwable> result = null; final Deque<Consumer<Either<T, Throwable>>> buffer = new LinkedList<>(); @Override public Optional<Either<T, Throwable>> poll() { return Optional.ofNullable(result); } @Override public synchronized T get() { try { while (result == null) { wait(); } return Either.unsafe(result); } catch (InterruptedException e) { throw Throwables.propagate(e); } } @Override public synchronized T get(Duration timeout) { try { long millis = timeout.toMillis(); long start; while (result == null) { if (millis <= 0) { throw new TimeoutException(); } start = System.currentTimeMillis(); wait(millis); millis -= System.currentTimeMillis() - start; } return Either.unsafe(result); } catch (InterruptedException e) { throw Throwables.propagate(e); } } @Override public synchronized void set(Either<T, Throwable> e) { if (this.result != null) { return; } this.result = e; notifyAll(); while (!buffer.isEmpty()) { buffer.removeFirst().accept(e); } } @Override public synchronized void respond(Consumer<Either<T, Throwable>> fn) { Either<T, Throwable> e = this.result; if (e != null) { fn.accept(e); } else { buffer.addLast(fn); } } @Override public <TT> Future<TT> transform(Function<Either<T, Throwable>, Future<TT>> fn) { return new TransformedFuture<>(this, fn); } @Override public String toString() { Either<T, Throwable> e = this.result; String state; if (e == null) { state = "pending"; } else if (e.isRight()) { state = "failed"; } else { state = "success"; } return "Promise(" + state + ")"; } }