View Javadoc
1   package io.atlassian.fugue.optic.law;
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.Options;
8   import io.atlassian.fugue.Pair;
9   import io.atlassian.fugue.Suppliers;
10  import io.atlassian.fugue.law.IsEq;
11  import io.atlassian.fugue.optic.PTraversal;
12  
13  import java.util.Collections;
14  import java.util.List;
15  import java.util.function.Function;
16  import java.util.stream.Collectors;
17  
18  import static io.atlassian.fugue.law.IsEq.isEq;
19  import static java.util.Spliterator.ORDERED;
20  import static java.util.Spliterators.spliteratorUnknownSize;
21  import static java.util.stream.Collectors.toList;
22  import static java.util.stream.StreamSupport.stream;
23  
24  public final class TraversalLaws<S, A> {
25  
26    private final PTraversal<S, S, A, A> traversal;
27  
28    public TraversalLaws(PTraversal<S, S, A, A> traversal) {
29      this.traversal = traversal;
30    }
31  
32    /**
33     * get what you set.
34     */
35    public IsEq<List<A>> setGetAll(S s, A a) {
36      return isEq(stream(traversal.getAll(traversal.set(a).apply(s)).spliterator(), false).collect(Collectors.toList()),
37        stream(Iterables.map(traversal.getAll(s), __ -> a).spliterator(), false).collect(Collectors.toList()));
38    }
39  
40    /**
41     * set idempotent
42     */
43    public IsEq<S> setIdempotent(S s, A a) {
44      return isEq(traversal.set(a).apply(traversal.set(a).apply(s)), traversal.set(a).apply(s));
45    }
46  
47    /**
48     * modify id = id
49     */
50    public IsEq<S> modifyIdentity(S s) {
51      return isEq(traversal.modify(Function.<A> identity()).apply(s), s);
52    }
53  
54    /**
55     * modifyF Applicative.point(_) = Applicative.point(_)
56     */
57    public IsEq<S> modifySupplierFPoint(S s) {
58      return isEq(traversal.modifySupplierF(Suppliers::ofInstance).apply(s).get(), s);
59    }
60  
61    /**
62     * modifyF Applicative.point(_) = Applicative.point(_)
63     */
64    public IsEq<Either<String, S>> modifyEitherFPoint(S s) {
65      return isEq(traversal.<String> modifyEitherF(Eithers.toRight()).apply(s), Either.right(s));
66    }
67  
68    /**
69     * modifyF Applicative.point(_) = Applicative.point(_)
70     */
71    public IsEq<Option<S>> modifyOptionFPoint(S s) {
72      return isEq(traversal.modifyOptionF(Options.toOption()).apply(s), Option.some(s));
73    }
74  
75    /**
76     * modifyF Applicative.point(_) = Applicative.point(_)
77     */
78    public IsEq<Pair<S, S>> modifyPairFPoint(S s) {
79      return isEq(traversal.modifyPairF(a -> Pair.pair(a, a)).apply(s), Pair.pair(s, s));
80    }
81  
82    /**
83     * modifyF Applicative.point(_) = Applicative.point(_)
84     */
85    public IsEq<S> modifyFunctionFPoint(S s) {
86      return isEq(traversal.<String> modifyFunctionF(a -> __ -> a).apply(s).apply(""), s);
87    }
88  
89    /**
90     * modifyF Applicative.point(_) = Applicative.point(_)
91     */
92    public IsEq<List<S>> modifyIterableFPoint(S s) {
93      return isEq(
94        stream(spliteratorUnknownSize(traversal.modifyIterableF(Collections::singleton).apply(s).iterator(), ORDERED), false).collect(toList()),
95        Collections.singletonList(s));
96    }
97  
98    /**
99     * headOption returns the first element of getAll
100    */
101   public IsEq<Option<A>> headOption(S s) {
102     return isEq(traversal.headOption(s), Iterables.first(traversal.getAll(s)));
103   }
104 
105 }