/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.api.functional;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* This class allow to represent a type that holds two different values.
*
* Only one value can be present at any given type.
*
* This class can be used as a monad to interact and chain functions to be executed over the possible return values.
*
* Most likely the left type represent an error or failure result and the right value represent a successful result.
*
* @param <L> the type of the left value
* @param <R> the type of the right value
*/
final public class Either<L, R> {
/**
* Creates an {@code Either} with a left value.
*
* @param value the left value
* @param <L> the left value type
* @param <R> the right value type
* @return the created {@code Either instance}
*/
public static <L, R> Either<L, R> left(L value) {
return new Either<>(ofNullable(value), empty());
}
/**
* Creates an {@code Either} with a right value.
*
* @param value the right value
* @param <L> the left value type
* @param <R> the right value type
* @return the created {@code Either instance}
*/
public static <L, R> Either<L, R> right(R value) {
return new Either<>(empty(), ofNullable(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left = l;
right = r;
}
/**
* Allows to execute a function over the left value if it is present
*
* @param func the function to apply to the left value
* @param <T> the return type of the function.
* @return a new {@code Either} created from the result of applying the function.
*/
public <T> Either<T, R> mapLeft(Function<? super L, ? extends T> func) {
return new Either<>(left.map(func), right);
}
public void applyLeft(Consumer<? super L> consumer) {
left.ifPresent(consumer::accept);
}
public void applyRight(Consumer<? super R> consumer) {
right.ifPresent(consumer::accept);
}
/**
* Allows to execute a function over the right value if it is present
*
* @param func the function to apply to the right value
* @param <T> the return type of the function.
* @return a new {@code Either} created from the result of applying the function.
*/
public <T> Either<L, T> mapRight(Function<? super R, ? extends T> func) {
return new Either<>(left, right.map(func));
}
/**
* Receives a {@link Consumer} functions for both, the left and right value and applies the one over the value that is present.
*
* @param leftFunc the function to apply to the left value
* @param rightFunc the function to apply to the right value
*/
public void apply(Consumer<? super L> leftFunc, Consumer<? super R> rightFunc) {
applyLeft(leftFunc);
applyRight(rightFunc);
}
/**
* @return true if it holds a value for the left type, false otherwise
*/
public boolean isLeft() {
return left.isPresent();
}
/**
* @return true if it holds a value for the right type, false otherwise
*/
public boolean isRight() {
return right.isPresent();
}
/**
* @return the left value
*/
public L getLeft() {
return left.orElse(null);
}
/**
* @return the right value
*/
public R getRight() {
return right.orElse(null);
}
public Optional<Object> getValue() {
if (left.isPresent()) {
return (Optional<Object>) left;
} else if (right.isPresent()) {
return (Optional<Object>) right;
} else {
return empty();
}
}
}