1 /*
2 Copyright 2011 Atlassian
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 package io.atlassian.fugue;
17
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.function.Function;
21 import java.util.function.Predicate;
22 import java.util.function.Supplier;
23
24 import static io.atlassian.fugue.Iterables.collect;
25 import static io.atlassian.fugue.Iterables.map;
26 import static io.atlassian.fugue.Suppliers.compose;
27 import static io.atlassian.fugue.Suppliers.ofInstance;
28
29 /**
30 * Utility functions for Eithers.
31 *
32 * @since 1.2
33 */
34 public class Eithers {
35
36 // /CLOVER:OFF
37
38 private Eithers() {}
39
40 // /CLOVER:ON
41
42 /**
43 * Extracts an object from an Either, regardless of the side in which it is
44 * stored, provided both sides contain the same type. This method will never
45 * return null.
46 *
47 * @param <T> the type for both the LHS and the RHS
48 * @param either use whichever side holds the value to return
49 * @return the value from whichever side holds it
50 */
51 public static <T> T merge(final Either<T, T> either) {
52 if (either.isLeft()) {
53 return either.left().get();
54 }
55 return either.right().get();
56 }
57
58 /**
59 * Creates an Either based on a boolean expression. If predicate is true, a
60 * Right will be returned containing the supplied right value; if it is false,
61 * a Left will be returned containing the supplied left value.
62 *
63 * @param <L> the LHS type
64 * @param <R> the RHS type
65 * @param predicate if predicate is true, a Right will be returned if it is
66 * false, a Left will be returned containing the supplied left value.
67 * @param left the LHS value
68 * @param right the RHS value
69 * @return an either with the appropriately selected value
70 */
71 public static <L, R> Either<L, R> cond(final boolean predicate, final L left, final R right) {
72 return predicate ? Either.<L, R> right(right) : Either.<L, R> left(left);
73 }
74
75 /**
76 * Simplifies extracting a value or throwing a checked exception from an
77 * Either.
78 *
79 * @param <A> the value type
80 * @param <X> the exception type
81 * @param either to extract from
82 * @return the value from the RHS
83 * @throws X the exception on the LHS
84 */
85 public static <X extends Exception, A> A getOrThrow(final Either<X, A> either) throws X {
86 if (either.isLeft()) {
87 throw either.left().get();
88 }
89 return either.right().get();
90 }
91
92 /**
93 * A predicate that tests if the supplied either is a left.
94 *
95 * @param <L> the LHS type
96 * @param <R> the RHS type
97 * @return the predicate testing left-hand-sidedness
98 */
99 public static <L, R> Predicate<Either<L, R>> isLeft() {
100 return Either::isLeft;
101 }
102
103 /**
104 * A predicate that tests if the supplied either is a right.
105 *
106 * @param <L> the LHS type
107 * @param <R> the RHS type
108 * @return the predicate testing right-hand-sidedness
109 */
110 public static <L, R> Predicate<Either<L, R>> isRight() {
111 return Either::isRight;
112 }
113
114 /**
115 * A function that maps an either to an option of its left type. The Function
116 * will return a defined {@link io.atlassian.fugue.Option} containing the
117 * either's left value if {Either#isLeft()} is true, an undefined
118 * {@link io.atlassian.fugue.Option} otherwise.
119 *
120 * @param <L> the LHS type
121 * @param <R> the RHS type
122 * @return the function returning a defined option for left-hand-sided eithers
123 */
124 public static <L, R> Function<Either<L, R>, Option<L>> leftMapper() {
125 return either -> either.left().toOption();
126 }
127
128 /**
129 * A function that maps an either to an option of its right type. The Function
130 * will return a defined {@link io.atlassian.fugue.Option} containing the
131 * either's right value if {Either#isRight()} is true, an undefined
132 * {@link io.atlassian.fugue.Option} otherwise.
133 *
134 * @param <L> the LHS type
135 * @param <R> the RHS type
136 * @return the function returning a defined option for right-hand-sided
137 * eithers
138 */
139 public static <L, R> Function<Either<L, R>, Option<R>> rightMapper() {
140 return either -> either.right().toOption();
141 }
142
143 /**
144 * Function to convert from an value to a
145 * {@link io.atlassian.fugue.Either.Left} containing that value.
146 *
147 * @param <L> left type.
148 * @param <R> right type.
149 * @return a {@link java.util.function.Function} returning a
150 * {@link io.atlassian.fugue.Either.Left}.
151 */
152 public static <L, R> Function<L, Either<L, R>> toLeft() {
153 return Either::left;
154 }
155
156 /**
157 * Function to convert from a value to a
158 * {@link io.atlassian.fugue.Either.Left} containing that value. Allows
159 * hinting the correct types.
160 *
161 * @param leftType expected left type.
162 * @param rightType expected right type.
163 * @param <L> left type.
164 * @param <R> right type.
165 * @return a {@link java.util.function.Function} returning a
166 * {@link io.atlassian.fugue.Either.Left}.
167 */
168 public static <L, R> Function<L, Either<L, R>> toLeft(final Class<L> leftType, final Class<R> rightType) {
169 return Eithers.toLeft();
170 }
171
172 /**
173 * Supplier returning a {@link io.atlassian.fugue.Either.Left}.
174 *
175 * @param l value to return inside the left.
176 * @param <L> left type.
177 * @param <R> right type.
178 * @return a {@link java.util.function.Supplier} returning a
179 * {@link io.atlassian.fugue.Either.Left}..
180 */
181 public static <L, R> Supplier<Either<L, R>> toLeft(final L l) {
182 return compose(Eithers.<L, R> toLeft(), ofInstance(l));
183 }
184
185 /**
186 * Supplier returning a {@link io.atlassian.fugue.Either.Left}. Allows hinting
187 * the correct right type.
188 *
189 * @param l value to return inside the left.
190 * @param rightType type hint for the right type of the either.
191 * @param <L> left type.
192 * @param <R> right type.
193 * @return a {@link java.util.function.Supplier} returning a
194 * {@link io.atlassian.fugue.Either.Left}.
195 */
196 public static <L, R> Supplier<Either<L, R>> toLeft(final L l, final Class<R> rightType) {
197 return Eithers.toLeft(l);
198 }
199
200 /**
201 * Function to convert from an value to a
202 * {@link io.atlassian.fugue.Either.Right}. Allows hinting the correct types.
203 *
204 * @param <L> left type.
205 * @param <R> right type.
206 * @return a {@link java.util.function.Function} returning a
207 * {@link io.atlassian.fugue.Either.Right}.
208 */
209 public static <L, R> Function<R, Either<L, R>> toRight() {
210 return Either::right;
211 }
212
213 /**
214 * Function to convert from a value to a
215 * {@link io.atlassian.fugue.Either.Right} containing that value. Allows
216 * hinting the correct types.
217 *
218 * @param leftType expected left type.
219 * @param rightType expected right type.
220 * @param <L> left type.
221 * @param <R> right type.
222 * @return a {@link java.util.function.Function} returning a
223 * {@link io.atlassian.fugue.Either.Right}.
224 */
225 public static <L, R> Function<R, Either<L, R>> toRight(final Class<L> leftType, final Class<R> rightType) {
226 return Eithers.toRight();
227 }
228
229 /**
230 * Supplier returning a {@link io.atlassian.fugue.Either.Right}.
231 *
232 * @param r value to return inside the right.
233 * @param <L> left type.
234 * @param <R> right type.
235 * @return a {@link java.util.function.Supplier} returning a
236 * {@link io.atlassian.fugue.Either.Right}..
237 */
238 public static <L, R> Supplier<Either<L, R>> toRight(final R r) {
239 return compose(Eithers.<L, R> toRight(), ofInstance(r));
240 }
241
242 /**
243 * Supplier returning a {@link io.atlassian.fugue.Either.Right}. Allows
244 * hinting the correct right type.
245 *
246 * @param r value to return inside the right.
247 * @param leftType type hint for the left type of the either.
248 * @param <L> left type.
249 * @param <R> right type.
250 * @return a {@link java.util.function.Supplier} returning a
251 * {@link io.atlassian.fugue.Either.Right}.
252 */
253 public static <L, R> Supplier<Either<L, R>> toRight(final Class<L> leftType, final R r) {
254 return Eithers.toRight(r);
255 }
256
257 /**
258 * Upcasts an {@link Either either} of left type L to an either of left type
259 * LL, which is a super type of L, keeping the right type unchanged.
260 *
261 * @param e the source either
262 * @param <L> the base type to upcast
263 * @param <LL> the super type of the contained left type
264 * @param <R> the contained right type
265 * @return an either of left type LL and right type R
266 * @since 2.0
267 */
268 public static <LL, L extends LL, R> Either<LL, R> upcastLeft(final Either<L, R> e) {
269 return e.left().map(Functions.<LL> identity());
270 }
271
272 /**
273 * Upcasts an {@link Either either} of right type R to an either of right type
274 * RR, which is a super type of R, keeping the left type unchanged.
275 *
276 * @param e the source either
277 * @param <L> the contained left type
278 * @param <R> the base type to upcast
279 * @param <RR> the super type of the contained right type
280 * @return an either of left type L and right type RR
281 * @since 2.0
282 */
283 public static <L, RR, R extends RR> Either<L, RR> upcastRight(final Either<L, R> e) {
284 return e.right().map(Functions.<RR> identity());
285 }
286
287 /**
288 * Takes an {@link java.lang.Iterable} of {@link Either eithers}, and collects
289 * the left values of every either which has a left value
290 *
291 * @param <L> the LHS type
292 * @param <R> the RHS type
293 * @param it iterable of eithers to filter and transform from
294 * @return the left values contained in the contents of it
295 */
296 public static <L, R> Iterable<L> filterLeft(final Iterable<Either<L, R>> it) {
297 return collect(it, Eithers.<L, R> leftMapper());
298 }
299
300 /**
301 * Takes an {@link java.lang.Iterable} of {@link Either eithers}, and collects
302 * the right values of every either which has a left value
303 *
304 * @param <L> the LHS type
305 * @param <R> the RHS type
306 * @param it iterable of eithers to filter and transform from
307 * @return the right values contained in the contents of it
308 */
309 public static <L, R> Iterable<R> filterRight(final Iterable<Either<L, R>> it) {
310 return Options.flatten(map(it, Eithers.<L, R> rightMapper()));
311 }
312
313 /**
314 * Collect the right values if there are only rights, otherwise return the
315 * first left encountered.
316 *
317 * @param <L> the LHS type
318 * @param <R> the RHS type
319 * @param eithers an Iterable of either values
320 * @return either the iterable of right values, or the first left encountered.
321 */
322 public static <L, R> Either<L, Iterable<R>> sequenceRight(final Iterable<Either<L, R>> eithers) {
323 final ArrayList<R> rs = new ArrayList<>();
324 for (final Either<L, R> e : eithers) {
325 if (e.isLeft()) {
326 return e.left().<Iterable<R>> as();
327 }
328 rs.add(e.right().get());
329 }
330 return Either.right(Collections.unmodifiableList(rs));
331 }
332
333 /**
334 * Collect the left values if there are only lefts, otherwise return the first
335 * right encountered.
336 *
337 * @param <L> the LHS type
338 * @param <R> the RHS type
339 * @param eithers an Iterable of either values
340 * @return either the iterable of left values, or the first right encountered.
341 */
342 public static <L, R> Either<Iterable<L>, R> sequenceLeft(final Iterable<Either<L, R>> eithers) {
343 final ArrayList<L> ls = new ArrayList<>();
344 for (final Either<L, R> e : eithers) {
345 if (e.isRight()) {
346 return e.right().<Iterable<L>> as();
347 }
348 ls.add(e.left().get());
349 }
350 return Either.left(Collections.unmodifiableList(ls));
351 }
352 }