PrintableFunction.java
package com.github.dakusui.pcond.core.printable;
import com.github.dakusui.pcond.core.Evaluable;
import com.github.dakusui.pcond.core.Evaluator;
import com.github.dakusui.pcond.experimentals.currying.CurriedFunction;
import com.github.dakusui.pcond.core.identifieable.Identifiable;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
public class PrintableFunction<T, R> extends
Identifiable.Base implements
Evaluable.Func<T>,
CurriedFunction<T, R>,
Evaluator.Explainable,
Cloneable {
final Function<? super T, ? extends R> function;
private final Function<? super T, Object> head;
private final Evaluable<Object> tail;
private final Supplier<String> formatter;
private final Function<?, R> tailAsFunction;
boolean trivial = false;
@SuppressWarnings("unchecked")
protected PrintableFunction(Object creator, List<Object> args, Supplier<String> s, Function<? super T, ? extends R> function, Function<? super T, ?> head, Evaluable<?> tail) {
super(creator, args);
this.formatter = Objects.requireNonNull(s);
this.function = requireNonPrintableFunction(unwrap(Objects.requireNonNull(function)));
this.head = head != null ? (Function<? super T, Object>) head : (Function<? super T, Object>) this;
this.tail = (Evaluable<Object>) tail;
this.tailAsFunction = (Function<?, R>) tail;
}
protected PrintableFunction(Object creator, List<Object> args, Supplier<String> s, Function<? super T, ? extends R> function) {
this(creator, args, s, function, null, null);
}
@Override
public String toString() {
return this.formatter.get();
}
@Override
public <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return PrintableFunctionFactory.<V, T, R>compose(before, this);
}
@SuppressWarnings("unchecked")
@Override
public <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
@SuppressWarnings("rawtypes") Function f = this.tailAsFunction == null ? after : PrintableFunctionFactory.compose((Function) this.tailAsFunction, after);
return PrintableFunctionFactory.compose(this.head, f);
}
@Override
public Function<? super T, Object> head() {
return this.head;
}
@Override
public Optional<Evaluable<Object>> tail() {
return Optional.ofNullable(this.tail);
}
@Override
public R applyFunction(T value) {
return this.function.apply(value);
}
@SuppressWarnings("unchecked")
@Override
public Class<?> parameterType() {
return function instanceof CurriedFunction ?
((CurriedFunction<? super T, ? extends R>) function).parameterType() :
Object.class;
}
@SuppressWarnings("unchecked")
@Override
public Class<? extends R> returnType() {
return function instanceof CurriedFunction ?
(Class<? extends R>) ((CurriedFunction<? super T, ? extends R>) function).returnType() :
(Class<? extends R>) Object.class;
}
@Override
public Object explainOutputExpectation() {
return this.head();
}
@Override
public Object explainActual(Object actualValue) {
return actualValue;
}
@SuppressWarnings("unchecked")
public static <T, R> Function<T, R> unwrap(Function<T, R> function) {
Function<T, R> ret = function;
if (function instanceof PrintableFunction) {
ret = (Function<T, R>) ((PrintableFunction<T, R>) function).function;
assert !(ret instanceof PrintableFunction);
}
return ret;
}
@SuppressWarnings({ "CloneDoesntDeclareCloneNotSupportedException", "unchecked" })
@Override
protected PrintableFunction<T, R> clone() {
try {
return (PrintableFunction<T, R>) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
public boolean isSquashable() {
return this.trivial;
}
@Override
public PrintableFunction<T, R> makeTrivial() {
PrintableFunction<T, R> ret = this.clone();
ret.trivial = true;
return ret;
}
private static <T, R> Function<T, R> requireNonPrintableFunction(Function<T, R> function) {
assert !(function instanceof PrintableFunction);
return function;
}
}