package fj.data.optic;
import fj.F;
import fj.P2;
/** {@link PIso} when S = T and A = B */
public final class Iso<S, A> extends PIso<S, S, A, A> {
final PIso<S, S, A, A> pIso;
public Iso(final PIso<S, S, A, A> pIso) {
this.pIso = pIso;
}
@Override
public A get(final S s) {
return pIso.get(s);
}
@Override
public S reverseGet(final A a) {
return pIso.reverseGet(a);
}
@Override
public Iso<A, S> reverse() {
return new Iso<>(pIso.reverse());
}
/** pair two disjoint {@link Iso} */
public <S1, A1> Iso<P2<S, S1>, P2<A, A1>> product(final Iso<S1, A1> other) {
return new Iso<>(pIso.product(other.pIso));
}
@Override
public <C> Iso<P2<S, C>, P2<A, C>> first() {
return new Iso<>(pIso.first());
}
@Override
public <C> Iso<P2<C, S>, P2<C, A>> second() {
return new Iso<>(pIso.second());
}
/**********************************************************/
/** Compose methods between an {@link Iso} and another Optics */
/**********************************************************/
/** compose an {@link Iso} with a {@link Setter} */
public <C> Setter<S, C> composeSetter(final Setter<A, C> other) {
return new Setter<>(pIso.composeSetter(other.pSetter));
}
/** compose an {@link Iso} with a {@link Traversal} */
public <C> Traversal<S, C> composeTraversal(final Traversal<A, C> other) {
return new Traversal<>(pIso.composeTraversal(other.pTraversal));
}
/** compose an {@link Iso} with a {@link Optional} */
public <C> Optional<S, C> composeOptional(final Optional<A, C> other) {
return new Optional<>(pIso.composeOptional(other.pOptional));
}
/** compose an {@link Iso} with a {@link Prism} */
public <C> Prism<S, C> composePrism(final Prism<A, C> other) {
return new Prism<>(pIso.composePrism(other.pPrism));
}
/** compose an {@link Iso} with a {@link Lens} */
public <C> Lens<S, C> composeLens(final Lens<A, C> other) {
return asLens().composeLens(other);
}
/** compose an {@link Iso} with an {@link Iso} */
public <C> Iso<S, C> composeIso(final Iso<A, C> other) {
return new Iso<>(pIso.composeIso(other.pIso));
}
/****************************************************************/
/** Transformation methods to view an {@link Iso} as another Optics */
/****************************************************************/
/** view an {@link Iso} as a {@link Setter} */
@Override
public Setter<S, A> asSetter() {
return new Setter<>(pIso.asSetter());
}
/** view an {@link Iso} as a {@link Traversal} */
@Override
public Traversal<S, A> asTraversal() {
return new Traversal<>(pIso.asTraversal());
}
/** view an {@link Iso} as a {@link Optional} */
@Override
public Optional<S, A> asOptional() {
return new Optional<>(pIso.asOptional());
}
/** view an {@link Iso} as a {@link Prism} */
@Override
public Prism<S, A> asPrism() {
return new Prism<>(pIso.asPrism());
}
/** view an {@link Iso} as a {@link Lens} */
@Override
public Lens<S, A> asLens() {
return new Lens<>(pIso.asLens());
}
/** create an {@link Iso} using a pair of functions: one to get the target and one to get the source. */
public static <S, A> Iso<S, A> iso(final F<S, A> get, final F<A, S> reverseGet) {
return new Iso<>(PIso.pIso(get, reverseGet));
}
/**
* create an {@link Iso} between any type and itself. id is the zero element of optics composition, for all optics o of type O
* (e.g. Lens, Iso, Prism, ...):
*
* <pre>
* o composeIso Iso.id == o
* Iso.id composeO o == o
* </pre>
*
* (replace composeO by composeLens, composeIso, composePrism, ...)
*/
public static <S> Iso<S, S> id() {
return new Iso<>(PIso.pId());
}
}