Skip to content

Commit

Permalink
rename toValidList to firstFailure, toValidListAll to allFailures
Browse files Browse the repository at this point in the history
  • Loading branch information
h908714124 committed Feb 22, 2022
1 parent 822f009 commit b631b72
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 108 deletions.
216 changes: 112 additions & 104 deletions src/main/java/io/jbock/util/Eithers.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,103 @@
*/
public final class Eithers {

static final Set<Collector.Characteristics> CH_NOID = Set.of();
private static final Set<Collector.Characteristics> CH_NOID = Set.of();

private Eithers() {
/**
* Returns a {@code Collector} that accumulates the input elements into
* a Right containing all values in the original order,
* but only if there are no Left instances in the stream.
* If the stream does contain a Left instance, it discards the Right instances and
* accumulates a Left instance, which contains the first LHS value in the stream,
* in encounter order.
*
* @param <L> the type of the LHS values in the stream
* @param <R> the type of the RHS values in the stream
* @return a {@code Collector} which collects all the input elements into
* a Right containing all RHS values in the stream, or,
* if an LHS value exists, a Left containing the first LHS value
*/
public static <L, R>
Collector<Either<? extends L, ? extends R>, ?, Either<L, List<R>>>
firstFailure() {

BiConsumer<FirstFailureAcc<L, R>, Either<? extends L, ? extends R>> accumulator = (acc, either) ->
either.ifLeftOrElse(acc::addLeft, acc::addRight);

BinaryOperator<FirstFailureAcc<L, R>> combiner = (acc, other) ->
(FirstFailureAcc<L, R>) acc.combine(other);

return new CollectorImpl<>(FirstFailureAcc::new, accumulator, combiner, FirstFailureAcc::finish);
}

/**
* Returns a {@code Collector} that accumulates the input elements into
* a Right containing all values in the original order,
* but only if there are no Left instances in the stream.
* If the stream does contain a Left instance, it discards the Right instances and
* accumulates a Left containing only the LHS values,
* in encounter order.
*
* @param <L> the type of the LHS values in the stream
* @param <R> the type of the RHS values in the stream
* @return a {@code Collector} which collects all the input elements into
* a Right containing all RHS values in the stream,
* or, if an LHS value exists, a Left containing a nonempty list
* of all LHS values in the stream
*/
public static <L, R>
Collector<Either<? extends L, ? extends R>, ?, Either<List<L>, List<R>>>
allFailures() {

BiConsumer<AllFailuresAcc<L, R>, Either<? extends L, ? extends R>> accumulator = (acc, either) ->
either.ifLeftOrElse(acc::addLeft, acc::addRight);

BinaryOperator<AllFailuresAcc<L, R>> combiner = (acc, other) ->
(AllFailuresAcc<L, R>) acc.combine(other);

return new CollectorImpl<>(AllFailuresAcc::new, accumulator, combiner, AllFailuresAcc::finish);
}

/**
* Returns a {@code Collector} that accumulates the input elements into
* a new {@code List}. There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {@code List} returned.
* The final list is wrapped in an {@code Optional},
* which is empty if and only if the list is empty.
*
* @see #optionalList(List)
* @param <T> the type of the input elements
* @return a list of the RHS values in the stream,
* or, if an LHS value exists, a nonempty list of all LHS values
*/
public static <T> Collector<T, ?, Optional<List<T>>> toOptionalList() {
return Collectors.collectingAndThen(
Collectors.toList(),
Eithers::optionalList);
}

/**
* If the provided list is empty, returns an empty {@link Optional}.
* Otherwise, returns an {@code Optional} containing the nonempty
* input list.
*
* <p>Note: The resulting {@code Optional} might be used in a
* {@link Either#filter(Function) filter} or
* {@link Either#filterLeft(Function) filterLeft} operation.
*
* @see #toOptionalList()
* @param values a list of objects
* @param <T> the type of the members of {@code values}
* @return an {@code Optional} which is either empty, or
* contains a nonempty list
*/
public static <T> Optional<List<T>> optionalList(List<? extends T> values) {
if (values.isEmpty()) {
return Optional.empty();
}
@SuppressWarnings("unchecked")
List<T> result = (List<T>) values;
return Optional.of(result);
}

/**
Expand All @@ -28,7 +122,7 @@ private Eithers() {
* @param <T> the type of elements to be collected
* @param <R> the type of the result
*/
private static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
private static final class CollectorImpl<T, A, R> implements Collector<T, A, R> {
final Supplier<A> supplier;
final BiConsumer<A, T> accumulator;
final BinaryOperator<A> combiner;
Expand Down Expand Up @@ -82,10 +176,12 @@ static abstract class Acc<L, C, R> {
abstract void combineLeft(C otherLeft);

// nullable
abstract C left();
abstract C leftColl();

abstract void addLeft(L left);

final void addRight(R value) {
if (left() != null) {
if (leftColl() != null) {
return;
}
if (right == null) {
Expand All @@ -95,11 +191,11 @@ final void addRight(R value) {
}

final Acc<L, C, R> combine(Acc<L, C, R> other) {
if (left() != null) {
combineLeft(other.left());
if (leftColl() != null) {
combineLeft(other.leftColl());
return this;
}
if (other.left() != null) {
if (other.leftColl() != null) {
return other;
}
if (other.right == null) {
Expand All @@ -114,33 +210,34 @@ final Acc<L, C, R> combine(Acc<L, C, R> other) {
}

final Either<C, List<R>> finish() {
C left = left();
C left = leftColl();
return left != null
? Either.left(left)
: Either.right(right == null ? List.of() : right);
}
}

private static class ShortcuttingAcc<L, R> extends Acc<L, L, R> {
private static final class FirstFailureAcc<L, R> extends Acc<L, L, R> {
L left;

@Override
void combineLeft(L otherLeft) {
addLeft(otherLeft);
}

@Override
void addLeft(L value) {
if (left == null) {
left = value;
}
}

L left() {
L leftColl() {
return left;
}
}

private static class FullAcc<L, R> extends Acc<L, List<L>, R> {
private static final class AllFailuresAcc<L, R> extends Acc<L, List<L>, R> {
List<L> left;

@Override
Expand All @@ -152,6 +249,7 @@ void combineLeft(List<L> otherLeft) {
}
}

@Override
void addLeft(L value) {
if (left == null) {
left = new ArrayList<>();
Expand All @@ -160,101 +258,11 @@ void addLeft(L value) {
}

@Override
List<L> left() {
List<L> leftColl() {
return left;
}
}

/**
* Returns a {@code Collector} that accumulates the input elements into
* a Right containing all values in the original order,
* but only if there are no Left instances in the stream.
* If the stream does contain a Left instance, it discards the Right instances and
* accumulates a Left instance, which contains the first LHS value in the stream,
* in encounter order.
*
* @param <L> the type of the LHS values in the stream
* @param <R> the type of the RHS values in the stream
* @return a {@code Collector} which collects all the input elements into
* a Right containing all RHS values in the stream, or,
* if an LHS value exists, a Left containing the first LHS value
*/
public static <L, R> Collector<Either<? extends L, ? extends R>, ?, Either<L, List<R>>> toValidList() {

BiConsumer<ShortcuttingAcc<L, R>, Either<? extends L, ? extends R>> accumulate = (acc, either) ->
either.ifLeftOrElse(acc::addLeft, acc::addRight);

BinaryOperator<ShortcuttingAcc<L, R>> combine = (acc, other) ->
(ShortcuttingAcc<L, R>) acc.combine(other);

return new CollectorImpl<>(ShortcuttingAcc::new, accumulate, combine, ShortcuttingAcc::finish);
}

/**
* Returns a {@code Collector} that accumulates the input elements into
* a Right containing all values in the original order,
* but only if there are no Left instances in the stream.
* If the stream does contain a Left instance, it discards the Right instances and
* accumulates a Left containing only the LHS values,
* in encounter order.
*
* @param <L> the type of the LHS values in the stream
* @param <R> the type of the RHS values in the stream
* @return a {@code Collector} which collects all the input elements into
* a Right containing all RHS values in the stream,
* or, if an LHS value exists, a Left containing a nonempty list
* of all LHS values in the stream
*/
public static <L, R> Collector<Either<? extends L, ? extends R>, ?, Either<List<L>, List<R>>> toValidListAll() {

BiConsumer<FullAcc<L, R>, Either<? extends L, ? extends R>> accumulate = (acc, either) ->
either.ifLeftOrElse(acc::addLeft, acc::addRight);

BinaryOperator<FullAcc<L, R>> combine = (acc, other) ->
(FullAcc<L, R>) acc.combine(other);

return new CollectorImpl<>(FullAcc::new, accumulate, combine, FullAcc::finish);
}

/**
* Returns a {@code Collector} that accumulates the input elements into
* a new {@code List}. There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {@code List} returned.
* The resulting list is wrapped in an {@code Optional},
* which is empty if and only if the list is empty.
*
* @see #optionalList(List)
* @param <T> the type of the input elements
* @return a list of the RHS values in the stream,
* or, if an LHS value exists, a nonempty list of all LHS values
*/
public static <T> Collector<T, ?, Optional<List<T>>> toOptionalList() {
return Collectors.collectingAndThen(
Collectors.toList(),
Eithers::optionalList);
}

/**
* If the provided list is empty, returns an empty {@link Optional}.
* Otherwise, returns an {@code Optional} containing the nonempty
* input list.
*
* <p>Note: The resulting {@code Optional} might be used in a
* {@link Either#filter(Function) filter} or
* {@link Either#filterLeft(Function) filterLeft} operation.
*
* @see #toOptionalList()
* @param values a list of objects
* @param <T> the type of the members of {@code values}
* @return an {@code Optional} which is either empty, or
* contains a nonempty list
*/
public static <T> Optional<List<T>> optionalList(List<? extends T> values) {
if (values.isEmpty()) {
return Optional.empty();
}
@SuppressWarnings("unchecked")
List<T> result = (List<T>) values;
return Optional.of(result);
private Eithers() {
}
}
4 changes: 2 additions & 2 deletions src/test/java/io/jbock/util/ToValidListAllTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ void testRight() {
}

private Either<List<String>, List<Integer>> apply(List<Either<String, Integer>> data) {
return data.stream().collect(Eithers.toValidListAll());
return data.stream().collect(Eithers.allFailures());
}

private void checkAssociativity(Either<String, Integer> t1, Either<String, Integer> t2) {
@SuppressWarnings("unchecked")
Collector<Either<? extends String, ? extends Integer>, Eithers.Acc<String, ?, Integer>, Either<List<String>, List<Integer>>> coll =
(Collector<Either<? extends String, ? extends Integer>, Eithers.Acc<String, ?, Integer>, Either<List<String>, List<Integer>>>) Eithers.<String, Integer>toValidListAll();
(Collector<Either<? extends String, ? extends Integer>, Eithers.Acc<String, ?, Integer>, Either<List<String>, List<Integer>>>) Eithers.<String, Integer>allFailures();

Eithers.Acc<String, ?, Integer> a1 = coll.supplier().get();
coll.accumulator().accept(a1, t1);
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/io/jbock/util/ToValidListTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ void testRight() {
}

private Either<String, List<Integer>> apply(List<Either<String, Integer>> data) {
return data.stream().collect(Eithers.toValidList());
return data.stream().collect(Eithers.firstFailure());
}

private void checkAssociativity(Either<String, Integer> t1, Either<String, Integer> t2) {
@SuppressWarnings("unchecked")
Collector<Either<? extends String, ? extends Integer>, Eithers.Acc<String, ?, Integer>, Either<String, List<Integer>>> coll =
(Collector<Either<? extends String, ? extends Integer>, Eithers.Acc<String, ?, Integer>, Either<String, List<Integer>>>) Eithers.<String, Integer>toValidList();
(Collector<Either<? extends String, ? extends Integer>, Eithers.Acc<String, ?, Integer>, Either<String, List<Integer>>>) Eithers.<String, Integer>firstFailure();

Eithers.Acc<String, ?, Integer> a1 = coll.supplier().get();
coll.accumulator().accept(a1, t1);
Expand Down

0 comments on commit b631b72

Please sign in to comment.