package scotch.util;
import static lombok.AccessLevel.PRIVATE;
import java.util.function.Function;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.ToString;
public abstract class Either<A, B> {
public static <A, B> Either<A, B> left(A left) {
return new Left<>(left);
}
public static <A, B> Either<A, B> right(B right) {
return new Right<>(right);
}
private Either() {
// intentionally empty
}
@Override
public abstract boolean equals(Object o);
public abstract A getLeft();
public abstract B getRight();
@Override
public abstract int hashCode();
public boolean isLeft() {
return !isRight();
}
public abstract boolean isRight();
public abstract <C> Either<A, C> map(Function<B, C> function);
public abstract B orElseGet(Function<A, B> function);
public abstract <T extends RuntimeException> B orElseThrow(Function<A, T> function) throws T;
@Override
public abstract String toString();
@AllArgsConstructor(access = PRIVATE)
@EqualsAndHashCode(callSuper = false)
@ToString
public static class Left<A, B> extends Either<A, B> {
private final A value;
@Override
public A getLeft() {
return value;
}
@Override
public B getRight() {
throw new IllegalStateException();
}
@Override
public boolean isRight() {
return false;
}
@SuppressWarnings("unchecked")
@Override
public <C> Either<A, C> map(Function<B, C> function) {
return (Either<A, C>) this;
}
@Override
public B orElseGet(Function<A, B> function) {
return function.apply(value);
}
@Override
public <T extends RuntimeException> B orElseThrow(Function<A, T> function) throws T {
throw function.apply(value);
}
}
@AllArgsConstructor(access = PRIVATE)
@EqualsAndHashCode(callSuper = false)
@ToString
public static class Right<A, B> extends Either<A, B> {
private final B value;
@Override
public A getLeft() {
throw new IllegalStateException();
}
@Override
public B getRight() {
return value;
}
@Override
public boolean isRight() {
return true;
}
@Override
public <C> Either<A, C> map(Function<B, C> function) {
return right(function.apply(value));
}
@Override
public B orElseGet(Function<A, B> function) {
return value;
}
@Override
public <T extends RuntimeException> B orElseThrow(Function<A, T> function) throws T {
return value;
}
}
}