Skip to content
Snippets Groups Projects
Either.java 2.42 KiB
Newer Older
import java.util.NoSuchElementException;
import java.util.Optional;

@SuppressWarnings("unused")
public sealed interface Either<L, R> permits Either.Left, Either.Right {

    static <L, R extends Throwable> Either<L, R> of(java.util.function.Supplier<L> supplier) {
        try {
            return new Either.Left<>(supplier.get());
        } catch (Throwable t) {
            try {
                @SuppressWarnings("unchecked")
                R exc = (R) t;
                return new Right<>(exc);
            } catch (ClassCastException e) {
                try {
                    @SuppressWarnings("unchecked")
                    R exc = (R) t.getCause();
                    return new Right<>(exc);
                } catch (ClassCastException ignored) {}
                throw t;
            }
        }
    }

    default boolean isLeft() {
        return (this instanceof Either.Left<L,R>);
    }
    default boolean isRight() {
        return (this instanceof Either.Right<L,R>);
    }

    default Optional<L> getLeft(){
        return switch (this) {
            case Either.Left<L, R> left -> Optional.ofNullable(left.left);
            case Either.Right<L, R> right -> Optional.empty();
        };
    }

    default Optional<R> getRight() {
        return switch (this) {
            case Either.Left<L, R> left -> Optional.empty();
            case Either.Right<L, R> right -> Optional.ofNullable(right.right);
        };
    }

    default Either<R, L> flip() {
        return switch (this) {
            case Either.Left<L, R> left -> new Right<>(left.left);
            case Either.Right<L, R> right -> new Left<>(right.right);
        };
    }

    default <L2> Either<L2, R> andThen(java.util.function.Function<L, Either<L2, R>> nextFunc) {
        return switch(this) {
            case Either.Left<L, R> left -> nextFunc.apply(left.left);
            case Either.Right<L, R> right -> new Either.Right<>(right.right);
        };
    }

    default <R2> Either<L, R2> andThenErr(java.util.function.Function<R, Either<L, R2>> nextFunc) {
        return switch(this) {
            case Either.Left<L, R> left -> new Either.Left<>(left.left);
            case Either.Right<L, R> right -> nextFunc.apply(right.right);
        };
    }

    default L unwrap() throws NoSuchElementException {
        return getLeft().orElseThrow();
    }

    record Left<L, R>(L left) implements Either<L, R> {}
    record Right<L, R>(R right) implements Either<L, R> {}
}