All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opencredo.concourse.domain.functional.Either Maven / Gradle / Ivy

package com.opencredo.concourse.domain.functional;

import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;

@FunctionalInterface
public interface Either {

    static  Either ofLeft(L left) {
        return new Left<>(left);
    }

    static  Either ofRight(R right) {
        return new Right<>(right);
    }

    default boolean isLeft() {
        return join(l -> true, r -> false);
    }

    default boolean isRight() {
        return join(l -> false, r -> true);
    }

    default LeftProjection left() { return new ConcreteLeftProjection<>(this); }
    default RightProjection right() { return new ConcreteRightProjection<>(this); }

    default Either swap() {
        return join(Either::ofRight, Either::ofLeft);
    }

     O join(Function left, Function right);

    default  Either map(Function left, Function right) {
        return join(left.andThen(Either::ofLeft), right.andThen(Either::ofRight));
    }

    default void forEither(Consumer left, Consumer right) {
        join(
                l -> { left.accept(l); return null; },
                r -> { right.accept(r); return null; });
    }

    interface LeftProjection extends Either {
        default  LeftProjection map(Function f) {
            return join(
                    f.andThen(Either::ofLeft),
                    Either::ofRight).left();
        }
        default  LeftProjection flatMap(Function> ff) {
            return join(ff, Either::ofRight).left();
        }
        default Optional toOptional() {
            return join(Optional::of, r -> Optional.empty());
        }
        default Stream stream() {
            return join(Stream::of, r -> Stream.empty());
        }
        default void ifPresent(Consumer consumer) {
            forEither(consumer, r -> {});
        }
    }

    interface RightProjection extends Either {
        default  RightProjection map(Function f) {
            return join(
                    Either::ofLeft,
                    f.andThen(Either::ofRight)).right();
        }
        default  RightProjection flatMap(Function> ff) {
            return join(Either::ofLeft, ff).right();
        }
        default Optional toOptional() {
            return join(l -> Optional.empty(), Optional::of);
        }
        default Stream stream() {
            return join(l -> Stream.empty(), Stream::of);
        }
        default void ifPresent(Consumer consumer) {
            forEither(l -> {}, consumer);
        }
    }

    abstract class BaseProjection extends Base {
        private final Either either;
        private BaseProjection(Either either) {
            this.either = either;
        }

        @Override
        public  O join(Function left, Function right) {
            return either.join(left, right);
        }
    }

    final class ConcreteLeftProjection extends BaseProjection implements LeftProjection {
        private ConcreteLeftProjection(Either either) {
            super(either);
        }
    }

    final class ConcreteRightProjection extends BaseProjection implements RightProjection {
        private ConcreteRightProjection(Either either) {
            super(either);
        }
    }

    abstract class Base implements Either {
        @Override
        public boolean equals(Object o) {
            return o == this
                    || ((o instanceof Either)
                    && ((Either) o).join(
                    otherL -> join(l -> otherL.equals(l), r -> false),
                    otherR -> join(l -> false, r -> otherR.equals(r))));
        }

        @Override
        public int hashCode() {
            return join(Object::hashCode, r -> -r.hashCode());
        }

        @Override
        public String toString() {
            return join(
                    l -> String.format("left(%s)", l),
                    r -> String.format("right(%s)", r));
        }
    }

    class Left extends Base {
        private final L left;

        private Left(L left) {
            this.left = left;
        }

        @Override
        public  O join(Function lf, Function rf) {
            return lf.apply(left);
        }
    }

    class Right extends Base {
        private final R right;

        private Right(R right) {
            this.right = right;
        }

        @Override
        public  O join(Function lf, Function rf) {
            return rf.apply(right);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy