package com.codepoetics.octarine.functional.lenses;
import com.codepoetics.octarine.functional.extractors.Extractor;
import com.codepoetics.octarine.functional.functions.Partial;
import org.pcollections.PMap;
import org.pcollections.PVector;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
public interface OptionalLens<T, V> extends Lens<T, Optional<V>>, Extractor.FromPartial<T, V> {
static <T, V> OptionalLens<T, V> of(Function<T, Optional<V>> getter, BiFunction<T, Optional<V>, T> setter) {
return new OptionalLens<T, V>() {
@Override
public Optional<V> get(T instance) {
return getter.apply(instance);
}
@Override
public T set(T instance, Optional<V> newValue) {
return setter.apply(instance, newValue);
}
};
}
static <T, V> OptionalLens<T, V> wrap(Lens<T, Optional<V>> lens) {
return new OptionalLens<T, V>() {
@Override
public Optional<V> get(T instance) {
return lens.get(instance);
}
@Override
public T set(T instance, Optional<V> newValue) {
return lens.set(instance, newValue);
}
};
}
static <T> OptionalLens<T[], T> intoArray(int index) {
return of(
(T[] ts) -> Optional.ofNullable(ts[index]),
(T[] ts, Optional<T> t) -> {
T[] copy = Arrays.copyOf(ts, ts.length);
copy[index] = t.orElse(null);
return copy;
}
);
}
static <K, V> OptionalLens<PMap<K, V>, V> intoPMap(K key) {
return of(
(PMap<K, V> m) -> Optional.ofNullable(m.get(key)),
(PMap<K, V> m, Optional<V> v) -> v.isPresent() ? m.plus(key, v.get()) : m.minus(key)
);
}
static <T> OptionalLens<PVector<T>, T> intoPVector(int index) {
return of(
ts -> index < ts.size() ? Optional.ofNullable(ts.get(index)) : Optional.empty(),
(PVector<T> ts, Optional<T> t) -> t.isPresent() ? ts.with(index, t.get()) : ts.with(index, null)
);
}
default Optional<V> apply(T target) {
return get(target);
}
default T updateIfPresent(T target, UnaryOperator<V> updater) {
return set(target, get(target).map(updater));
}
default T updateIfPresent(T target, Partial<V, V> partialUpdater) {
return set(target, get(target).flatMap(partialUpdater));
}
default V orElse(T target, V defaultValue) {
return get(target).orElse(defaultValue);
}
default T setNullable(T target, V newValue) {
return set(target, Optional.ofNullable(newValue));
}
default <V2> OptionalLens<T, V2> join(OptionalLens<V, V2> next, Supplier<V> missingValueSupplier) {
return of(
(T t) -> get(t).flatMap(next::get),
(T t, Optional<V2> v2) -> set(t, Optional.of(next.set(get(t).orElseGet(missingValueSupplier), v2))));
}
default Lens<T, V> assertPresent() {
return Lens.of(t -> get(t).get(), (t, v) -> set(t, Optional.ofNullable(v)));
}
default Lens<T, V> withDefault(V defaultValue) {
return Lens.of(
t -> get(t).orElse(defaultValue),
(t, v) -> set(t, Optional.ofNullable(v)));
}
default Lens<T, V> withDefault(Supplier<V> defaultValue) {
return Lens.of(t -> get(t).orElseGet(defaultValue), (t, v) -> set(t, Optional.ofNullable(v)));
}
}