1 package io.atlassian.fugue.extensions.step;
2
3 import io.atlassian.fugue.Either;
4
5 import java.util.function.Function;
6 import java.util.function.Predicate;
7 import java.util.function.Supplier;
8
9 /**
10 * The first step of the {@link Either} type.
11 * <p>
12 * This class is not intended to be contructed manually, and should only be used
13 * as part of a {@link Steps} chain, started by {@link Steps#begin(Either)}
14 *
15 * @param <A> The right hand side type of the first defined right value
16 * @param <LEFT> The left hand side type of the Either result
17 * @see Steps for usage examples
18 * @see Either
19 * @since 4.7.0
20 */
21 public final class EitherStep1<A, LEFT> {
22
23 private final Either<LEFT, A> either1;
24
25 EitherStep1(Either<LEFT, A> either1) {
26 this.either1 = either1;
27 }
28
29 /**
30 * Apply the provided function with the previous Step results.
31 * <p>
32 * Internally this will perform a {@link Either#flatMap(Function)} and the
33 * result will become the next step value.
34 *
35 * @param functor The functor to be applied as a flatMap with the previous
36 * step
37 * @param <B> The right hand side type of the next step result
38 * @param <LL> The left hand side type of the result that must be related to
39 * {@link LEFT}
40 * @return The next step class
41 */
42 public <B, LL extends LEFT> EitherStep2<A, B, LEFT> then(Function<? super A, Either<LL, B>> functor) {
43 Either<LEFT, B> either2 = either1.flatMap(functor);
44 return new EitherStep2<>(either1, either2);
45 }
46
47 /**
48 * Apply the provided supplier with the previous Step results.
49 * <p>
50 * Internally this will perform a {@link Either#flatMap(Function)} and the
51 * supplier will become the next step value.
52 * <p>
53 * This is different to {@link #then(Function)} in that the previous step
54 * results are not provided for the new step evaluation.
55 *
56 * @param supplier The supplier to provide the result of the flatMap with the
57 * previous step.
58 * @param <B> The right hand side type of the next step result
59 * @param <LL> The left hand side type of the result that must be related to
60 * {@link LEFT}
61 * @return The next step class
62 */
63 public <B, LL extends LEFT> EitherStep2<A, B, LEFT> then(Supplier<Either<LL, B>> supplier) {
64 Either<LEFT, B> either2 = either1.flatMap(value1 -> supplier.get());
65 return new EitherStep2<>(either1, either2);
66 }
67
68 /**
69 * Apply the provided predicate with the previous step results.
70 * <p>
71 * If the predicate is not satisfied then the unsatisfiedSupplier is used to
72 * populate the left value that will prevent any further steps evaluation.
73 *
74 * @param predicate The check that must be satisfied by contained values
75 * @param unsatisfiedSupplier Provide the value to populate the left if not
76 * satisfied
77 * @return This step class with either the same last step value, or changed to
78 * a left
79 */
80 public EitherStep1<A, LEFT> filter(Predicate<? super A> predicate, Supplier<? extends LEFT> unsatisfiedSupplier) {
81 Either<LEFT, A> filterEither1 = either1.filterOrElse(predicate, unsatisfiedSupplier);
82 return new EitherStep1<>(filterEither1);
83 }
84
85 /**
86 * Terminating step expression, that will provide the previous steps to this
87 * function and return the result as a <code>Right</code>
88 *
89 * @param functor The yield function to map on previous values
90 * @param <Z> The right hand side type for the returned result
91 * @return An Either with the result of this function on right, or the
92 * existing left
93 */
94 public <Z> Either<LEFT, Z> yield(Function<? super A, Z> functor) {
95 return either1.map(functor);
96 }
97
98 }