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 super L, ? extends O> left, Function super R, ? extends O> right);
default Either map(Function super L, ? extends L2> left, Function super R, ? extends R2> right) {
return join(left.andThen(Either::ofLeft), right.andThen(Either::ofRight));
}
default void forEither(Consumer super L> left, Consumer super R> right) {
join(
l -> { left.accept(l); return null; },
r -> { right.accept(r); return null; });
}
interface LeftProjection extends Either {
default LeftProjection map(Function super L, ? extends L2> f) {
return join(
f.andThen(Either::ofLeft),
Either::ofRight).left();
}
default LeftProjection flatMap(Function super L, ? extends Either> 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 super L> consumer) {
forEither(consumer, r -> {});
}
}
interface RightProjection extends Either {
default RightProjection map(Function super R, ? extends R2> f) {
return join(
Either::ofLeft,
f.andThen(Either::ofRight)).right();
}
default RightProjection flatMap(Function super R, ? extends Either> 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 super R> 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 super L, ? extends O> left, Function super R, ? extends O> 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 super L, ? extends O> lf, Function super R, ? extends O> 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 super L, ? extends O> lf, Function super R, ? extends O> rf) {
return rf.apply(right);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy