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