001package org.clafer.collection;
002
003import java.lang.reflect.Array;
004import java.util.ArrayList;
005import java.util.List;
006import org.clafer.common.Check;
007
008/**
009 * A sum type. Does not allow nulls.
010 *
011 * @param <A> the type of left
012 * @param <B> the type of right
013 * @author jimmy
014 */
015public abstract class Either<A, B> {
016
017    public abstract boolean isLeft();
018
019    public abstract A getLeft();
020
021    public abstract boolean isRight();
022
023    public abstract B getRight();
024
025    public static <A, B> Either<A, B> left(A left) {
026        return new Left<>(Check.notNull(left));
027    }
028
029    public static <A, B> Either<A, B> right(B right) {
030        return new Right<>(Check.notNull(right));
031    }
032
033    public static <A, B> List<A> filterLeft(List<Either<A, B>> eithers) {
034        List<A> lefts = new ArrayList<>();
035        for (Either<A, B> either : eithers) {
036            if (either.isLeft()) {
037                lefts.add(either.getLeft());
038            }
039        }
040        return lefts;
041    }
042
043    @SafeVarargs
044    public static <A, B> A[] filterLeft(Either<A, B>[] eithers, A... array) {
045        List<A> lefts = new ArrayList<>();
046        for (Either<A, B> either : eithers) {
047            if (either.isLeft()) {
048                lefts.add(either.getLeft());
049            }
050        }
051        @SuppressWarnings("unchecked")
052        A[] to = array.length == lefts.size()
053                ? array
054                : (A[]) Array.newInstance(array.getClass().getComponentType(), lefts.size());
055        return lefts.toArray(to);
056    }
057
058    public static <A, B> List<B> filterRight(List<Either<A, B>> eithers) {
059        List<B> rights = new ArrayList<>();
060        for (Either<A, B> either : eithers) {
061            if (either.isRight()) {
062                rights.add(either.getRight());
063            }
064        }
065        return rights;
066    }
067
068    @SafeVarargs
069    public static <A, B> B[] filterRight(Either<A, B>[] eithers, B... array) {
070        List<B> rights = new ArrayList<>();
071        for (Either<A, B> either : eithers) {
072            if (either.isRight()) {
073                rights.add(either.getRight());
074            }
075        }
076        @SuppressWarnings("unchecked")
077        B[] to = array.length == rights.size()
078                ? array
079                : (B[]) Array.newInstance(array.getClass().getComponentType(), rights.size());
080        return rights.toArray(to);
081    }
082}