package io.trane.future;
import java.time.Duration;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
final class ValueFuture<T> implements SatisfiedFuture<T> {
private static final Logger logger = Logger.getLogger(ExceptionFuture.class.getName());
final T value;
protected ValueFuture(final T value) {
this.value = value;
}
@Override
public final <R> Future<R> map(final Function<? super T, ? extends R> f) {
try {
return new ValueFuture<>(f.apply(value));
} catch (final Throwable ex) {
return new ExceptionFuture<>(ex);
}
}
@Override
public final <R> Future<R> flatMap(final Function<? super T, ? extends Future<R>> f) {
try {
return f.apply(value);
} catch (final Throwable ex) {
return new ExceptionFuture<>(ex);
}
}
@Override
public <R> Future<R> transform(final Transformer<? super T, ? extends R> t) {
try {
return new ValueFuture<>(t.onValue(value));
} catch (final Throwable ex) {
return new ExceptionFuture<>(ex);
}
}
@Override
public <R> Future<R> transformWith(final Transformer<? super T, ? extends Future<R>> t) {
try {
return t.onValue(value);
} catch (final Throwable ex) {
return new ExceptionFuture<>(ex);
}
}
@Override
public <U, R> Future<R> biMap(final Future<U> other, final BiFunction<? super T, ? super U, ? extends R> f) {
return other.map(u -> f.apply(value, u));
}
@Override
public <U, R> Future<R> biFlatMap(final Future<U> other,
final BiFunction<? super T, ? super U, ? extends Future<R>> f) {
return other.flatMap(u -> f.apply(value, u));
}
@Override
public final Future<T> onSuccess(final Consumer<? super T> c) {
try {
c.accept(value);
} catch (final Throwable ex) {
logger.log(Level.WARNING, "Error executing `onSuccess` callback " + c + "for" + this, ex);
NonFatalException.verify(ex);
}
return this;
}
@Override
public final Future<T> onFailure(final Consumer<Throwable> c) {
return this;
}
@Override
public final Future<T> respond(final Responder<? super T> r) {
try {
r.onValue(value);
} catch (final Throwable ex) {
logger.log(Level.WARNING, "Error when executing `respond` callback " + r + "for" + this, ex);
NonFatalException.verify(ex);
}
return this;
}
@Override
public final Future<T> rescue(final Function<Throwable, ? extends Future<T>> f) {
return this;
}
@Override
public final Future<Void> voided() {
return VOID;
}
@Override
public final T get(final Duration timeout) {
return value;
}
@Override
public final String toString() {
return String.format("ValueFuture(%s)", value);
}
@Override
public final int hashCode() {
return (value == null) ? 0 : value.hashCode();
}
@Override
public final boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ValueFuture<?> other = (ValueFuture<?>) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}