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