|
@@ -1,35 +1,88 @@
|
|
|
package org.leumasjaffe.container;
|
|
package org.leumasjaffe.container;
|
|
|
|
|
|
|
|
|
|
+import java.util.function.Consumer;
|
|
|
|
|
+import java.util.function.Function;
|
|
|
|
|
+
|
|
|
import lombok.AccessLevel;
|
|
import lombok.AccessLevel;
|
|
|
import lombok.AllArgsConstructor;
|
|
import lombok.AllArgsConstructor;
|
|
|
import lombok.Getter;
|
|
import lombok.Getter;
|
|
|
|
|
+import lombok.NonNull;
|
|
|
|
|
|
|
|
@AllArgsConstructor(access=AccessLevel.PRIVATE)
|
|
@AllArgsConstructor(access=AccessLevel.PRIVATE)
|
|
|
-@Getter
|
|
|
|
|
|
|
+@Getter(AccessLevel.PACKAGE) // For JUnit tests only
|
|
|
public class Either<T1, T2> {
|
|
public class Either<T1, T2> {
|
|
|
public enum State { LEFT, RIGHT }
|
|
public enum State { LEFT, RIGHT }
|
|
|
T1 left;
|
|
T1 left;
|
|
|
T2 right;
|
|
T2 right;
|
|
|
|
|
|
|
|
- public static <T1, T2> Either<T1, T2> ofLeft(T1 left) {
|
|
|
|
|
|
|
+ public static <T1, T2> Either<T1, T2> ofLeft(@NonNull T1 left) {
|
|
|
return new Either<>(left, null);
|
|
return new Either<>(left, null);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static <T1, T2> Either<T1, T2> ofRight(T2 right) {
|
|
|
|
|
|
|
+ public static <T1, T2> Either<T1, T2> ofRight(@NonNull T2 right) {
|
|
|
return new Either<>(null, right);
|
|
return new Either<>(null, right);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public State getState() {
|
|
|
|
|
|
|
+ State getState() {
|
|
|
return left == null ? State.RIGHT : State.LEFT;
|
|
return left == null ? State.RIGHT : State.LEFT;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public void setLeft(T1 left) {
|
|
|
|
|
|
|
+ public void setLeft(@NonNull T1 left) {
|
|
|
this.right = null;
|
|
this.right = null;
|
|
|
this.left = left;
|
|
this.left = left;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public void setRight(T2 right) {
|
|
|
|
|
|
|
+ public void setRight(@NonNull T2 right) {
|
|
|
this.right = right;
|
|
this.right = right;
|
|
|
this.left = null;
|
|
this.left = null;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ public void consume(@NonNull Consumer<T1> fLeft, @NonNull Consumer<T2> fRight) {
|
|
|
|
|
+ switch (getState()) {
|
|
|
|
|
+ case LEFT: fLeft.accept(left); return;
|
|
|
|
|
+ case RIGHT: fRight.accept(right); return;
|
|
|
|
|
+ default: throw new IllegalStateException();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public <R1, R2> Either<R1, R2> map(@NonNull Function<T1, R1> fLeft,
|
|
|
|
|
+ @NonNull Function<T2, R2> fRight) {
|
|
|
|
|
+ switch (getState()) {
|
|
|
|
|
+ case LEFT: return Either.ofLeft(fLeft.apply(left));
|
|
|
|
|
+ case RIGHT: return Either.ofRight(fRight.apply(right));
|
|
|
|
|
+ default: throw new IllegalStateException();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public <R> Either<R, T2> mapLeft(@NonNull Function<T1, R> fLeft) {
|
|
|
|
|
+ switch (getState()) {
|
|
|
|
|
+ case LEFT: return Either.ofLeft(fLeft.apply(left));
|
|
|
|
|
+ case RIGHT: return Either.ofRight(right);
|
|
|
|
|
+ default: throw new IllegalStateException();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public <R> Either<T1, R> mapRight(@NonNull Function<T2, R> fRight) {
|
|
|
|
|
+ switch (getState()) {
|
|
|
|
|
+ case LEFT: return Either.ofLeft(left);
|
|
|
|
|
+ case RIGHT: return Either.ofRight(fRight.apply(right));
|
|
|
|
|
+ default: throw new IllegalStateException();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> Function<T, T> identity() {
|
|
|
|
|
+ return (x) -> x;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T, R> Function<T, R> discard() {
|
|
|
|
|
+ return (x) -> null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public <R> R unify(@NonNull Function<T1, R> fLeft, @NonNull Function<T2, R> fRight) {
|
|
|
|
|
+ switch (getState()) {
|
|
|
|
|
+ case LEFT: return fLeft.apply(left);
|
|
|
|
|
+ case RIGHT: return fRight.apply(right);
|
|
|
|
|
+ default: throw new IllegalStateException();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|