1 package io.atlassian.fugue.optic;
2
3 import io.atlassian.fugue.*;
4
5 import java.util.Collections;
6 import java.util.function.BinaryOperator;
7 import java.util.function.Function;
8 import java.util.function.Supplier;
9 import java.util.stream.Stream;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 public abstract class POptional<S, T, A, B> {
29
30 POptional() {
31 super();
32 }
33
34
35
36
37
38 public abstract Either<T, A> getOrModify(S s);
39
40
41
42
43 public abstract Function<S, T> set(final B b);
44
45
46
47
48 public abstract Option<A> getOption(final S s);
49
50
51
52
53
54 public abstract <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f);
55
56
57
58
59
60 public abstract <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f);
61
62
63
64
65
66 public abstract Function<S, Option<T>> modifyOptionF(Function<A, Option<B>> f);
67
68
69
70
71
72 public abstract Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f);
73
74
75
76
77
78 public abstract Function<S, Supplier<T>> modifySupplierF(Function<A, Supplier<B>> f);
79
80
81
82
83
84 public abstract Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f);
85
86
87
88
89 public abstract Function<S, T> modify(final Function<A, B> f);
90
91
92
93
94
95 public final Function<S, Option<T>> modifyOption(final Function<A, B> f) {
96 return s -> getOption(s).map(__ -> modify(f).apply(s));
97 }
98
99
100
101
102
103 public final Function<S, Option<T>> setOption(final B b) {
104 return modifyOption(__ -> (b));
105 }
106
107
108
109
110 public final boolean isMatching(final S s) {
111 return getOption(s).isDefined();
112
113 }
114
115
116
117
118 public final <S1, T1> POptional<Either<S, S1>, Either<T, T1>, A, B> sum(final POptional<S1, T1, A, B> other) {
119 return pOptional(e -> e.fold(s -> getOrModify(s).left().map(Eithers.toLeft()), s1 -> other.getOrModify(s1).left().map(Eithers.toRight())),
120 b -> e -> e.bimap(set(b), other.set(b)));
121 }
122
123 public <C> POptional<Pair<S, C>, Pair<T, C>, Pair<A, C>, Pair<B, C>> first() {
124 return pOptional(sc -> getOrModify(sc.left()).bimap(t -> Pair.pair(t, sc.right()), a -> Pair.pair(a, sc.right())),
125 bc -> s_ -> Pair.pair(set(bc.left()).apply(s_.left()), bc.right()));
126 }
127
128 public <C> POptional<Pair<C, S>, Pair<C, T>, Pair<C, A>, Pair<C, B>> second() {
129 return pOptional(cs -> getOrModify(cs.right()).bimap(t -> Pair.pair(cs.left(), t), a -> Pair.pair(cs.left(), a)),
130 cb -> _s -> Pair.pair(cb.left(), set(cb.right()).apply(_s.right())));
131 }
132
133
134
135
136
137
138
139
140 public final <C> Fold<S, C> composeFold(final Fold<A, C> other) {
141 return asFold().composeFold(other);
142 }
143
144
145
146
147 public final <C> Fold<S, C> composeGetter(final Getter<A, C> other) {
148 return asFold().composeGetter(other);
149 }
150
151
152
153
154 public final <C, D> PSetter<S, T, C, D> composeSetter(final PSetter<A, B, C, D> other) {
155 return asSetter().composeSetter(other);
156 }
157
158
159
160
161 public final <C, D> PTraversal<S, T, C, D> composeTraversal(final PTraversal<A, B, C, D> other) {
162 return asTraversal().composeTraversal(other);
163 }
164
165
166
167
168 public final <C, D> POptional<S, T, C, D> composeOptional(final POptional<A, B, C, D> other) {
169 final POptional<S, T, A, B> self = this;
170 return new POptional<S, T, C, D>() {
171
172 @Override public Either<T, C> getOrModify(final S s) {
173 return self.getOrModify(s).right().flatMap(a -> other.getOrModify(a).bimap(b -> POptional.this.set(b).apply(s), Function.identity()));
174 }
175
176 @Override public Function<S, T> set(final D d) {
177 return self.modify(other.set(d));
178 }
179
180 @Override public Option<C> getOption(final S s) {
181 return self.getOption(s).flatMap(other::getOption);
182 }
183
184 @Override public <G> Function<S, Function<G, T>> modifyFunctionF(final Function<C, Function<G, D>> f) {
185 return self.modifyFunctionF(other.modifyFunctionF(f));
186 }
187
188 @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<C, Either<L, D>> f) {
189 return self.modifyEitherF(other.modifyEitherF(f));
190 }
191
192 @Override public Function<S, Option<T>> modifyOptionF(final Function<C, Option<D>> f) {
193 return self.modifyOptionF(other.modifyOptionF(f));
194 }
195
196 @Override public Function<S, Iterable<T>> modifyIterableF(final Function<C, Iterable<D>> f) {
197 return self.modifyIterableF(other.modifyIterableF(f));
198 }
199
200 @Override public Function<S, Supplier<T>> modifySupplierF(final Function<C, Supplier<D>> f) {
201 return self.modifySupplierF(other.modifySupplierF(f));
202 }
203
204 @Override public Function<S, Pair<T, T>> modifyPairF(final Function<C, Pair<D, D>> f) {
205 return self.modifyPairF(other.modifyPairF(f));
206 }
207
208 @Override public Function<S, T> modify(final Function<C, D> f) {
209 return self.modify(other.modify(f));
210 }
211 };
212 }
213
214
215
216
217 public final <C, D> POptional<S, T, C, D> composePrism(final PPrism<A, B, C, D> other) {
218 return composeOptional(other.asOptional());
219 }
220
221
222
223
224 public final <C, D> POptional<S, T, C, D> composeLens(final PLens<A, B, C, D> other) {
225 return composeOptional(other.asOptional());
226 }
227
228
229
230
231 public final <C, D> POptional<S, T, C, D> composeIso(final PIso<A, B, C, D> other) {
232 return composeOptional(other.asOptional());
233 }
234
235
236
237
238
239
240
241
242 public final Fold<S, A> asFold() {
243 return new Fold<S, A>() {
244 @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
245 return s -> POptional.this.getOption(s).map(f).getOrElse(monoid.zero());
246 }
247 };
248 }
249
250
251
252
253 public PSetter<S, T, A, B> asSetter() {
254 return new PSetter<S, T, A, B>() {
255 @Override public Function<S, T> modify(final Function<A, B> f) {
256 return POptional.this.modify(f);
257 }
258
259 @Override public Function<S, T> set(final B b) {
260 return POptional.this.set(b);
261 }
262 };
263 }
264
265
266
267
268 public PTraversal<S, T, A, B> asTraversal() {
269 final POptional<S, T, A, B> self = this;
270 return new PTraversal<S, T, A, B>() {
271
272 @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
273 return self.modifyFunctionF(f);
274 }
275
276 @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
277 return self.modifyEitherF(f);
278 }
279
280 @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
281 return self.modifyOptionF(f);
282 }
283
284 @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
285 return self.modifyIterableF(f);
286 }
287
288 @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
289 return self.modifySupplierF(f);
290 }
291
292 @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
293 return self.modifyPairF(f);
294 }
295
296 @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
297 return s -> self.getOption(s).map(f).getOrElse(monoid.zero());
298 }
299 };
300 }
301
302 public static <S, T> POptional<S, T, S, T> pId() {
303 return PIso.<S, T> pId().asOptional();
304 }
305
306
307
308
309
310 public static <S, T, A, B> POptional<S, T, A, B> pOptional(final Function<S, Either<T, A>> getOrModify, final Function<B, Function<S, T>> set) {
311 return new POptional<S, T, A, B>() {
312 @Override public Either<T, A> getOrModify(final S s) {
313 return getOrModify.apply(s);
314 }
315
316 @Override public Function<S, T> set(final B b) {
317 return set.apply(b);
318 }
319
320 @Override public Option<A> getOption(final S s) {
321 return getOrModify.apply(s).right().toOption();
322 }
323
324 @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
325 return s -> getOrModify.apply(s).fold(t -> __ -> t, a -> f.apply(a).andThen(b -> set.apply(b).apply(s)));
326 }
327
328 @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
329 return s -> getOrModify.apply(s).fold(Eithers.toRight(), t -> f.apply(t).right().map(b -> set.apply(b).apply(s)));
330 }
331
332 @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
333 return s -> getOrModify.apply(s).fold(Option::some, t -> f.apply(t).map(b -> set.apply(b).apply(s)));
334 }
335
336 @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
337 return s -> getOrModify.apply(s).fold(Collections::singleton, t -> Iterables.<B, T> map(f.apply(t), b -> set.apply(b).apply(s)));
338 }
339
340 @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
341 return s -> getOrModify.apply(s).fold(Suppliers::ofInstance, t -> Suppliers.<B, T> compose(b -> set.apply(b).apply(s), f.apply(t)));
342 }
343
344 @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
345 return s -> getOrModify.apply(s).fold(t -> Pair.pair(t, t), t -> Pair.<B, T> map(f.apply(t), b -> set.apply(b).apply(s)));
346 }
347
348 @Override public Function<S, T> modify(final Function<A, B> f) {
349 return s -> getOrModify.apply(s).fold(Function.identity(), a -> set.apply(f.apply(a)).apply(s));
350 }
351 };
352 }
353 }