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

io.rouz.flo.BuilderCurried Maven / Gradle / Ivy

package io.rouz.flo;

import java.io.Serializable;
import java.util.List;

import static io.rouz.flo.TaskContextWithId.withId;

/**
 * Implementation of the curried {@link TaskBuilder} api
 */
class BuilderCurried {

  private BuilderCurried() {
  }

  private static  RecursiveEval leafEval(
      TaskId taskId,
      EvalClosure aClosure) {
    return new RecursiveEval<>(true, taskId, aClosure, taskContext -> taskContext::immediateValue);
  }

  private static  RecursiveEval, B> leafValEval(
      TaskId taskId,
      EvalClosure aClosure) {
    return new RecursiveEval<>(true, taskId, aClosure, taskContext -> val -> val);
  }

  static class BuilderC0 extends BaseRefs implements CurriedTaskBuilder.TaskBuilderC0 {

    BuilderC0(TaskId taskId, Class type) {
      super(taskId, type);
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderC in(Fn> aTask) {
      Fn> aTaskSingleton = Singleton.create(aTask);
      return new BuilderC<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyList(aTaskSingleton)),
          taskId, type,
          leafEval(
              taskId,
              tc -> tc.evaluate(aTaskSingleton.get())));
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderC, Z, Z> ins(Fn>> aTasks) {
      Fn>> aTasksSingleton = Singleton.create(aTasks);
      return new BuilderC<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyFlatten(aTasksSingleton)),
          taskId, type,
          leafEval(
              taskId,
              tc -> aTasksSingleton.get()
                  .stream().map(tc::evaluate).collect(Values.toValueList(tc))));
    }
  }

  static class BuilderCV0 extends BaseRefs implements CurriedTaskBuilder.TaskBuilderCV0 {

    BuilderCV0(TaskId taskId, Class type) {
      super(taskId, type);
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderCV, Z> in(Fn> aTask) {
      Fn> aTaskSingleton = Singleton.create(aTask);
      return new BuilderCV<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyList(aTaskSingleton)),
          taskId, type,
          leafValEval(
              taskId,
              tc -> tc.evaluate(aTaskSingleton.get())));
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderCV, TaskContext.Value, Z> ins(Fn>> aTasks) {
      Fn>> aTasksSingleton = Singleton.create(aTasks);
      return new BuilderCV<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyFlatten(aTasksSingleton)),
          taskId, type,
          leafValEval(
              taskId,
              tc -> aTasksSingleton.get()
                  .stream().map(tc::evaluate).collect(Values.toValueList(tc))));
    }
  }

  private static class BuilderC extends BaseRefs implements CurriedTaskBuilder.TaskBuilderC {

    private final RecursiveEval evaluator;

    private BuilderC(Fn>> inputs, TaskId taskId, Class type, RecursiveEval evaluator) {
      super(inputs, taskId, type);
      this.evaluator = evaluator;
    }

    @Override
    public Task process(Fn1 fn) {
      return Task.create(inputs, type, evaluator.enclose(fn), taskId);
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderC, Z> in(Fn> bTask) {
      Fn> bTaskSingleton = Singleton.create(bTask);
      return new BuilderC<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyList(bTaskSingleton)),
          taskId, type,
          evaluator.curry(
              tc -> tc.evaluate(bTaskSingleton.get())));
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderC, Fn1, Z> ins(Fn>> bTasks) {
      Fn>> bTasksSingleton = Singleton.create(bTasks);
      return new BuilderC<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyFlatten(bTasksSingleton)),
          taskId, type,
          evaluator.curry(
              tc -> bTasksSingleton.get()
                  .stream().map(tc::evaluate).collect(Values.toValueList(tc))));
    }
  }

  private static class BuilderCV extends BaseRefs implements CurriedTaskBuilder.TaskBuilderCV {

    private final RecursiveEval evaluator;

    private BuilderCV(Fn>> inputs, TaskId taskId, Class type, RecursiveEval evaluator) {
      super(inputs, taskId, type);
      this.evaluator = evaluator;
    }

    @Override
    public Task process(Fn1> code) {
      EvalClosure closure =
          tc -> evaluator.enclose((a) -> code.apply(withId(tc, taskId)).apply(a)).eval(tc);
      return Task.create(inputs, type, closure, taskId);
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderCV, Z> in(Fn> bTask) {
      Fn> bTaskSingleton = Singleton.create(bTask);
      return new BuilderCV<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyList(bTaskSingleton)),
          taskId, type,
          evaluator.curry(
              tc -> tc.evaluate(bTaskSingleton.get())));
    }

    @Override
    public  CurriedTaskBuilder.TaskBuilderCV, Fn1, Z> ins(Fn>> bTasks) {
      Fn>> bTasksSingleton = Singleton.create(bTasks);
      return new BuilderCV<>(
          BuilderUtils.lazyFlatten(inputs, BuilderUtils.lazyFlatten(bTasksSingleton)),
          taskId, type,
          evaluator.curry(
              tc -> bTasksSingleton.get()
                  .stream().map(tc::evaluate).collect(Values.toValueList(tc))));
    }
  }

  private static final class RecursiveEval implements Serializable {

    private final boolean leaf;
    private final TaskId taskId;
    private final EvalClosure aClosure;
    private final Fn1>> contClosure;

    RecursiveEval(
        boolean leaf,
        TaskId taskId,
        EvalClosure aClosure,
        Fn1>> contClosure) {
      this.leaf = leaf;
      this.taskId = taskId;
      this.aClosure = aClosure;
      this.contClosure = contClosure;
    }

    EvalClosure enclose(Fn1 fn) {
      return taskContext -> continuation(taskContext).apply(fn);
    }

     RecursiveEval, Z> curry(EvalClosure tClosure) {
      return new RecursiveEval<>(false, taskId, tClosure, this::continuation);
    }

    private Fn1, TaskContext.Value> continuation(TaskContext taskContext) {
      Fn1> cont = contClosure.apply(taskContext);
      TaskContext.Value aVal = aClosure.eval(taskContext);

      return fn -> aVal.flatMap((a) -> (leaf)
          ? taskContext.invokeProcessFn(taskId, () -> cont.apply(fn.apply(a)))
          : cont.apply(fn.apply(a)));
    }
  }
}