
net.cassite.f.Try Maven / Gradle / Ivy
package net.cassite.f;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
public class Try {
private Try() {
}
public static TryCode code(@NotNull Supplier> c) {
if (c == null)
throw new NullPointerException();
return new TryCode<>(c);
}
public static class TryCode {
private final Supplier> c;
TryCode(Supplier> c) {
this.c = c;
}
public TryCatch except(@NotNull Class exType, @NotNull Function> exHandler) {
if (exType == null)
throw new NullPointerException();
if (exHandler == null)
throw new NullPointerException();
return new TryCatch(exType, exHandler);
}
public Monad composeFinally(@NotNull Supplier> func) {
if (func == null)
throw new NullPointerException();
return except(Throwable.class, Future::failedFuture).composeFinally(func);
}
public class TryCatch {
private final LinkedHashMap, Function>> handlers = new LinkedHashMap<>();
TryCatch(Class exType, Function> exHandler) {
//noinspection unchecked
handlers.put(exType, (Function>) exHandler);
}
public TryCatch except(@NotNull Class exType, @NotNull Function> exHandler) {
if (exType == null)
throw new NullPointerException();
if (exHandler == null)
throw new NullPointerException();
if (handlers.containsKey(exType))
throw new Error("try-expression already has handler for " + exType.getName());
//noinspection unchecked
handlers.put(exType, (Function>) exHandler);
return this;
}
public Monad map(@NotNull Function f) {
if (f == null)
throw new NullPointerException();
return compose(t -> F.unit(f.apply(t)));
}
public void setHandler(@NotNull Handler> handler) {
if (handler == null)
throw new NullPointerException();
compose(Future::succeededFuture).setHandler(handler);
}
public Monad composeFinally(@NotNull Supplier> func) {
if (func == null)
throw new NullPointerException();
Monad fu = F.tbd();
setHandler(r -> {
// always try to run finally code
Future> f;
try {
f = func.get();
} catch (Throwable t) {
// exception thrown in finally scope
fu.fail(t);
return;
}
f.setHandler(r2 -> {
if (r2.failed()) {
fu.fail(r2.cause());
} else {
// then check the actual result
if (r.failed()) {
fu.fail(r.cause());
} else {
T t = r.result();
if (t == null) {
fu.complete();
} else {
fu.complete(t);
}
}
}
});
});
return fu;
}
private void handleFailed(Function> f, Future fu, Throwable ex) {
boolean found = false;
for (Map.Entry, Function>> entry : handlers.entrySet()) {
Class extends Throwable> type = entry.getKey();
if (type.isInstance(ex)) {
found = true;
Future fuT;
try {
fuT = entry.getValue().apply(ex);
} catch (Throwable t) {
// exception thrown in handler function
fu.fail(t);
return;
}
fuT.compose(f).setHandler(fu);
break;
}
}
if (!found) {
fu.fail(ex);
}
}
public Monad compose(@NotNull Function> f) {
if (f == null)
throw new NullPointerException();
Monad fu = F.tbd();
try {
c.get().setHandler(res -> {
if (res.succeeded()) {
T t = res.result();
f.apply(t).setHandler(fu);
return;
}
Throwable ex = res.cause();
handleFailed(f, fu, ex);
});
} catch (Throwable ex) {
// exception thrown in code function
handleFailed(f, fu, ex);
}
return fu;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy