View Javadoc
1   package io.atlassian.fugue.optic;
2   
3   import io.atlassian.fugue.Either;
4   import io.atlassian.fugue.Eithers;
5   import io.atlassian.fugue.Iterables;
6   import io.atlassian.fugue.Option;
7   import io.atlassian.fugue.Pair;
8   import io.atlassian.fugue.Suppliers;
9   
10  import java.util.Collections;
11  import java.util.function.Function;
12  import java.util.function.Supplier;
13  
14  /**
15   * {@link POptional} restricted to monomorphic update
16   */
17  public final class Optional<S, A> extends POptional<S, S, A, A> {
18  
19    final POptional<S, S, A, A> pOptional;
20  
21    public Optional(final POptional<S, S, A, A> pOptional) {
22      this.pOptional = pOptional;
23    }
24  
25    @Override public Function<S, S> set(final A a) {
26      return pOptional.set(a);
27    }
28  
29    @Override public Function<S, Supplier<S>> modifySupplierF(final Function<A, Supplier<A>> f) {
30      return pOptional.modifySupplierF(f);
31    }
32  
33    @Override public Function<S, Option<S>> modifyOptionF(final Function<A, Option<A>> f) {
34      return pOptional.modifyOptionF(f);
35    }
36  
37    @Override public <C> Function<S, Function<C, S>> modifyFunctionF(final Function<A, Function<C, A>> f) {
38      return pOptional.modifyFunctionF(f);
39    }
40  
41    @Override public <L> Function<S, Either<L, S>> modifyEitherF(final Function<A, Either<L, A>> f) {
42      return pOptional.modifyEitherF(f);
43    }
44  
45    @Override public Function<S, Iterable<S>> modifyIterableF(final Function<A, Iterable<A>> f) {
46      return pOptional.modifyIterableF(f);
47    }
48  
49    @Override public Function<S, Pair<S, S>> modifyPairF(final Function<A, Pair<A, A>> f) {
50      return pOptional.modifyPairF(f);
51    }
52  
53    @Override public Function<S, S> modify(final Function<A, A> f) {
54      return pOptional.modify(f);
55    }
56  
57    @Override public Either<S, A> getOrModify(final S s) {
58      return pOptional.getOrModify(s);
59    }
60  
61    @Override public Option<A> getOption(final S s) {
62      return pOptional.getOption(s);
63    }
64  
65    /**
66     * join two {@link Optional} with the same target
67     */
68    public final <S1> Optional<Either<S, S1>, A> sum(final Optional<S1, A> other) {
69      return new Optional<>(pOptional.sum(other.pOptional));
70    }
71  
72    @Override public final <C> Optional<Pair<S, C>, Pair<A, C>> first() {
73      return new Optional<>(pOptional.first());
74    }
75  
76    @Override public final <C> Optional<Pair<C, S>, Pair<C, A>> second() {
77      return new Optional<>(pOptional.second());
78    }
79  
80    /**************************************************************/
81    /** Compose methods between a {@link Optional} and another Optics */
82    /**************************************************************/
83  
84    /**
85     * compose a {@link Optional} with a {@link Setter}
86     */
87    public final <C> Setter<S, C> composeSetter(final Setter<A, C> other) {
88      return new Setter<>(pOptional.composeSetter(other.pSetter));
89    }
90  
91    /**
92     * compose a {@link Optional} with a {@link Traversal}
93     */
94    public final <C> Traversal<S, C> composeTraversal(final Traversal<A, C> other) {
95      return new Traversal<>(pOptional.composeTraversal(other.pTraversal));
96    }
97  
98    /**
99     * compose a {@link Optional} with a {@link Optional}
100    */
101   public final <C> Optional<S, C> composeOptional(final Optional<A, C> other) {
102     return new Optional<>(pOptional.composeOptional(other.pOptional));
103   }
104 
105   /**
106    * compose a {@link Optional} with a {@link Prism}
107    */
108   public final <C> Optional<S, C> composePrism(final Prism<A, C> other) {
109     return new Optional<>(pOptional.composePrism(other.pPrism));
110   }
111 
112   /**
113    * compose a {@link Optional} with a {@link Lens}
114    */
115   public final <C> Optional<S, C> composeLens(final Lens<A, C> other) {
116     return new Optional<>(pOptional.composeLens(other.pLens));
117   }
118 
119   /**
120    * compose a {@link Optional} with an {@link Iso}
121    */
122   public final <C> Optional<S, C> composeIso(final Iso<A, C> other) {
123     return new Optional<>(pOptional.composeIso(other.pIso));
124   }
125 
126   /********************************************************************/
127   /** Transformation methods to view a {@link Optional} as another Optics */
128   /********************************************************************/
129 
130   /**
131    * view a {@link Optional} as a {@link Setter}
132    */
133   @Override public final Setter<S, A> asSetter() {
134     return new Setter<>(pOptional.asSetter());
135   }
136 
137   /**
138    * view a {@link Optional} as a {@link Traversal}
139    */
140   @Override public final Traversal<S, A> asTraversal() {
141     return new Traversal<>(pOptional.asTraversal());
142   }
143 
144   public static <S> Optional<S, S> id() {
145     return new Optional<>(POptional.pId());
146   }
147 
148   public static <S, A> Optional<S, A> optional(final Function<S, Option<A>> getOption, final Function<A, Function<S, S>> set) {
149     return new Optional<>(new POptional<S, S, A, A>() {
150 
151       @Override public Either<S, A> getOrModify(final S s) {
152         return getOption.apply(s).fold(() -> Either.<S, A> left(s), Eithers.<S, A> toRight());
153       }
154 
155       @Override public Function<S, S> set(final A a) {
156         return set.apply(a);
157       }
158 
159       @Override public Option<A> getOption(final S s) {
160         return getOption.apply(s);
161       }
162 
163       @Override public <C> Function<S, Function<C, S>> modifyFunctionF(final Function<A, Function<C, A>> f) {
164         return s -> getOption.apply(s).<Function<C, S>> fold(() -> __ -> s, a -> f.apply(a).andThen(b -> set.apply(b).apply(s)));
165       }
166 
167       @Override public <L> Function<S, Either<L, S>> modifyEitherF(final Function<A, Either<L, A>> f) {
168         return s -> getOption.apply(s).<Either<L, S>> fold(() -> Either.right(s), t -> f.apply(t).right().map(b -> set.apply(b).apply(s)));
169       }
170 
171       @Override public Function<S, Option<S>> modifyOptionF(final Function<A, Option<A>> f) {
172         return s -> getOption.apply(s).fold(() -> Option.some(s), t -> f.apply(t).map(b -> set.apply(b).apply(s)));
173       }
174 
175       @Override public Function<S, Iterable<S>> modifyIterableF(final Function<A, Iterable<A>> f) {
176         return s -> getOption.apply(s).<Iterable<S>> fold(() -> Collections.singleton(s), t -> Iterables.map(f.apply(t), b -> set.apply(b).apply(s)));
177       }
178 
179       @Override public Function<S, Supplier<S>> modifySupplierF(final Function<A, Supplier<A>> f) {
180         return s -> getOption.apply(s).<Supplier<S>> fold(() -> Suppliers.ofInstance(s),
181           t -> Suppliers.compose(b -> set.apply(b).apply(s), f.apply(t)));
182       }
183 
184       @Override public Function<S, Pair<S, S>> modifyPairF(final Function<A, Pair<A, A>> f) {
185         return s -> getOption.apply(s).<Pair<S, S>> fold(() -> Pair.pair(s, s), t -> Pair.map(f.apply(t), b -> set.apply(b).apply(s)));
186       }
187 
188       @Override public Function<S, S> modify(final Function<A, A> f) {
189         return s -> getOption.apply(s).fold(() -> s, a -> set.apply(f.apply(a)).apply(s));
190       }
191 
192     });
193   }
194 
195 }