blob: 2bc0d74669c666655f22d770763e3f70a31df6d3 [file] [log] [blame]
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.util;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* A container wrapping a value of one of two types. An {@code Either<A, B>} instance either wraps
* an instance of {@code A} or a instance of {@code B}.
*
* <p>Just as with {@link Pair}, this class is immutable, supports nullable values, and is
* completely devoid of Bazel-business-logic-specific semantics. Avoid using it in public APIs.
*
* <p>This class is a simple implementation of a general purpose "sum" type. In type theory, sum
* types are the duals of product types -- the corresponding observation here is that {@link Either}
* is the dual of {@link Pair}.
*/
public abstract class Either<A, B> {
// Disallow subclasses outside of this file.
private Either() {
}
/** Constructs a {@link Either} representing the left injection of {@code a}. */
public static <A, B> Either<A, B> ofLeft(A a) {
return new LeftEither<>(a);
}
/** Constructs a {@link Either} representing the right injection of {@code b}. */
public static <A, B> Either<A, B> ofRight(B b) {
return new RightEither<>(b);
}
/**
* Consumes the value injected into this {@link Either}. A left injection is consumed using
* {@code leftConsumer} and a right injection is consumed using {@code rightConsumer}.
*/
public abstract void consume(Consumer<A> leftConsumer, Consumer<B> rightConsumer);
/**
* Maps the value injected into this {@link Either}. A left injection is mapped using
* {@code leftFunction} and a right injection is mapped using {@code rightFunction}.
*/
public abstract <C> C map(Function<A, C> leftFunction, Function<B, C> rightFunction);
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object other);
@Override
public abstract String toString();
private static class LeftEither<A, B> extends Either<A, B> {
private final A a;
private LeftEither(A a) {
this.a = a;
}
@Override
public void consume(Consumer<A> leftConsumer, Consumer<B> rightConsumer) {
leftConsumer.accept(a);
}
@Override
public <C> C map(Function<A, C> leftFunction, Function<B, C> rightFunction) {
return leftFunction.apply(a);
}
@Override
public int hashCode() {
return Objects.hashCode(a);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof LeftEither)) {
return false;
}
return Objects.equals(this.a, ((LeftEither) other).a);
}
@Override
public String toString() {
return "left injection of " + a;
}
}
private static class RightEither<A, B> extends Either<A, B> {
private final B b;
private RightEither(B b) {
this.b = b;
}
@Override
public void consume(Consumer<A> leftConsumer, Consumer<B> rightConsumer) {
rightConsumer.accept(b);
}
@Override
public <C> C map(Function<A, C> leftFunction, Function<B, C> rightFunction) {
return rightFunction.apply(b);
}
@Override
public int hashCode() {
return Objects.hashCode(b);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof RightEither)) {
return false;
}
return Objects.equals(this.b, ((RightEither) other).b);
}
@Override
public String toString() {
return "right injection of " + b;
}
}
}