package io.datakernel.async;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.exception.AsyncTimeoutException;
import java.util.Arrays;
import java.util.Iterator;
public class AsyncFunctions {
public static final AsyncTimeoutException TIMEOUT_EXCEPTION = new AsyncTimeoutException();
private AsyncFunctions() {
}
private static final class DoneState {
boolean done;
}
public static <I, O> AsyncFunction<I, O> timeout(final Eventloop eventloop, final long timestamp, final AsyncFunction<I, O> function) {
return new AsyncFunction<I, O>() {
@Override
public void apply(I input, final ResultCallback<O> callback) {
final DoneState state = new DoneState();
function.apply(input, new ResultCallback<O>() {
@Override
protected void onResult(O result) {
if (!state.done) {
state.done = true;
callback.setResult(result);
}
}
@Override
protected void onException(Exception e) {
if (!state.done) {
state.done = true;
callback.setException(e);
}
}
});
if (!state.done) {
eventloop.schedule(timestamp, new Runnable() {
@Override
public void run() {
if (!state.done) {
state.done = true;
callback.setException(TIMEOUT_EXCEPTION);
}
}
});
}
}
};
}
public static <I, T, O> AsyncFunction<I, O> compose(AsyncFunction<T, O> g, AsyncFunction<I, T> f) {
return pipeline(f, g);
}
public static <I, T, O> AsyncFunction<I, O> pipeline(final AsyncFunction<I, T> f, final AsyncFunction<T, O> g) {
return new AsyncFunction<I, O>() {
@Override
public void apply(I input, final ResultCallback<O> callback) {
f.apply(input, new ForwardingResultCallback<T>(callback) {
@Override
protected void onResult(T result) {
g.apply(result, callback);
}
});
}
};
}
public static <I, O> AsyncFunction<I, O> pipeline(AsyncFunction<?, ?>... functions) {
return pipeline(Arrays.asList(functions));
}
@SuppressWarnings("unchecked")
public static <I, O> AsyncFunction<I, O> pipeline(final Iterable<AsyncFunction<?, ?>> functions) {
return new AsyncFunction<I, O>() {
@Override
public void apply(I input, ResultCallback<O> callback) {
next(input, (Iterator) functions.iterator(), callback);
}
private void next(Object item, final Iterator<AsyncFunction<Object, Object>> iterator, final ResultCallback<O> callback) {
if (iterator.hasNext()) {
AsyncFunction<Object, Object> next = iterator.next();
next.apply(item, new ForwardingResultCallback<Object>(callback) {
@Override
protected void onResult(Object result) {
next(result, iterator, callback);
}
});
} else {
callback.setResult((O) item);
}
}
};
}
}