All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dakusui.valid8j_pcond.experimentals.currying.CurryingUtils Maven / Gradle / Ivy

The newest version!
package com.github.dakusui.valid8j_pcond.experimentals.currying;

import com.github.dakusui.valid8j_pcond.experimentals.currying.context.CurriedContext;
import com.github.dakusui.valid8j_pcond.experimentals.currying.multi.MultiFunction;
import com.github.dakusui.valid8j_pcond.core.printable.PrintableFunctionFactory;

import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static com.github.dakusui.valid8j_pcond.internals.InternalUtils.formatObject;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;

/**
 * Intended for internal use only.
 */
public enum CurryingUtils {
  ;
  private static final ThreadLocal, CurriedFunction>> CURRIED_FUNCTION_FACTORY_POOL = new ThreadLocal<>();

  public static CurriedFunction curry(MultiFunction function) {
    return curry(function, emptyList());
  }

  public static Function, CurriedFunction> currier() {
    if (CURRIED_FUNCTION_FACTORY_POOL.get() == null)
      CURRIED_FUNCTION_FACTORY_POOL.set((List args) ->
          PrintableFunctionFactory.create(
              (args_) -> () -> functionNameFormatter(functionName(args_), ongoingContext(args_)).apply(function(args_)), (args_) -> new CurriedFunction.Impl(function(args_), ongoingContext(args_)), args, CurryingUtils.class
          ));
    return CURRIED_FUNCTION_FACTORY_POOL.get();
  }

  public static  Function applyCurriedFunction(CurriedFunction curriedFunction, int... orderArgs) {
    return context -> {
      CurriedFunction cur = curriedFunction;
      int[] normalizedOrderArgs = normalizeOrderArgs(context, orderArgs);
      for (int i = 0; i < normalizedOrderArgs.length - 1; i++)
        cur = cur.applyNext(context.valueAt(normalizedOrderArgs[i]));
      return cur.applyLast(context.valueAt(normalizedOrderArgs[context.size() - 1]));
    };
  }

  public static int[] normalizeOrderArgs(CurriedContext curriedContext, int[] orderArgs) {
    int[] order;
    if (orderArgs.length == 0)
      order = IntStream.range(0, curriedContext.size()).toArray();
    else
      order = orderArgs;
    return order;
  }

  static CurriedFunction curry(MultiFunction function, List ongoingContext) {
    return currier().apply(asList(function.name(), function, ongoingContext));
  }

  private static String functionName(List args) {
    return (String) args.get(0);
  }

  @SuppressWarnings("unchecked")
  private static MultiFunction function(List args) {
    return (MultiFunction) args.get(1);
  }

  @SuppressWarnings("unchecked")
  private static List ongoingContext(List args) {
    return (List) args.get((2));
  }

  private static Function, String> functionNameFormatter(String functionName, List ongoingContext) {
    return (MultiFunction function) -> functionName +
        (!ongoingContext.isEmpty() ? IntStream.range(0, ongoingContext.size())
            .mapToObj(i -> function.parameterType(i).getSimpleName() + ":" + ongoingContext.get(i))
            .collect(joining(",", "(", ")")) : "") +
        IntStream.range(ongoingContext.size(), function.arity())
            .mapToObj(i -> "(" + function.parameterType(i).getSimpleName() + ")")
            .collect(joining());
  }

  public static String formatParameterOrder(List paramOrder) {
    String formatted = formatParamOrder(paramOrder.stream());
    String uncustomized = formatParamOrder(IntStream.range(0, paramOrder.size()).boxed());
    return formatted.equals(uncustomized) ?
        "" :
        formatted;
  }

  private static String formatParamOrder(Stream paramOrderStream) {
    return paramOrderStream.map(Object::toString).collect(joining(",", "(", ")"));
  }

  static Supplier messageInvalidTypeArgument(Object value, Class aClass) {
    return () -> "Given argument:" + formatObject(value) +
        (value == null ?
            "" :
            "(" + value.getClass() + ")") +
        " cannot be assigned to parameter:" + aClass.getCanonicalName();
  }
}