io.codemodder.Either Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of codemodder-base Show documentation
Show all versions of codemodder-base Show documentation
Base framework for writing codemods in Java
package io.codemodder;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/** An implementation of the Either monad. It holds a single value of two possible types. */
public class Either {
private final L leftValue;
private final R rightValue;
private Either(L left, R right) {
this.leftValue = left;
this.rightValue = right;
}
/** Returns {@code true} if the left value is present. */
public boolean isLeft() {
return leftValue != null;
}
/** Returns {@code true} if the right value is present. */
public boolean isRight() {
return leftValue == null;
}
/** Returns the left value, may be {@code null} */
public L getLeft() {
return leftValue;
}
/** Returns the right value, may be {@code null} */
public R getRight() {
return rightValue;
}
/** Returns an {@link Either} containing {@code value} as a left value. */
public static Either left(A value) {
return new Either<>(value, null);
}
/** Returns an {@link Either} containing {@code value} as a right value. */
public static Either right(B value) {
return new Either<>(null, value);
}
/** Applies {@code func} to the left value if present. */
public Either map(Function func) {
if (this.isLeft()) return new Either<>(func.apply(this.leftValue), null);
else return new Either<>(null, this.rightValue);
}
/**
* Applies {@code func} to the right value if present and returns an {@code Either} containing the
* result. Otherwise returns an {@code Either} containing the left value.
*/
public Either flatMap(Function> func) {
if (this.isLeft()) {
var other = func.apply(this.leftValue);
if (other.isLeft()) return new Either<>(other.leftValue, null);
else return new Either<>(null, other.rightValue);
} else return new Either<>(null, this.rightValue);
}
/** Applies {@code func} to the left value if present. */
public Either mapRight(Function func) {
if (this.isRight()) return new Either<>(null, func.apply(this.rightValue));
else return new Either<>(this.leftValue, null);
}
/**
* Applies {@code func} to the right value if present and returns an {@code Either} containing the
* result. Otherwise returns an {@code Either} containing the left value.
*/
public Either flatMapRight(Function> func) {
if (this.isRight()) {
var other = func.apply(this.rightValue);
if (other.isRight()) return new Either<>(null, other.rightValue);
else return new Either<>(other.leftValue, null);
} else return new Either<>(this.leftValue, null);
}
/**
* Builds {@code Either} from an {@link Optional} where either it contains the value of
* the {@link Optional} or the {@code orElse} object.
*/
public static Either fromOptional(Optional maybe, R orElse) {
return maybe.>map(Either::left).orElseGet(() -> Either.right(orElse));
}
/**
* If it contains the left value, applies the {@link Predicate} {@code pred} and return an {@code
* Either} containing {@code orElse} if it fails. Otherwise do nothing
*/
public Either filter(Predicate pred, R orElse) {
if (this.isLeft()) {
if (pred.test(this.leftValue)) return this;
else return Either.right(orElse);
} else return this;
}
/**
* Applies the {@link Consumer} {@code leftAction} if it contains the left value, or the {@code
* rightAction} otherwise.
*/
public void ifLeftOrElse(Consumer super L> leftAction, Consumer super R> rightAction) {
if (isLeft()) {
leftAction.accept(getLeft());
} else {
rightAction.accept(getRight());
}
}
/** Returns the result of the {@link Function}s {@code leftFunction} or {@code rightFunction}. */
public A ifLeftOrElseGet(
Function super L, A> leftFunction, Function super R, A> rightFunction) {
if (isLeft()) {
return leftFunction.apply(getLeft());
} else {
return rightFunction.apply(getRight());
}
}
@Override
public String toString() {
return "Either[" + (this.isLeft() ? this.leftValue : this.rightValue) + "]";
}
}