ValueHolder.java

package com.github.dakusui.pcond.core;

import static com.github.dakusui.pcond.core.Evaluator.Impl.EVALUATION_SKIPPED;
import static java.util.Objects.requireNonNull;

public class ValueHolder<V> implements Cloneable {

  private final State state;
  private final CreatorFormType creatorFormType;
  V         value;
  Throwable exception;

  private ValueHolder(State state, V value, Throwable exception, CreatorFormType creatorFormType) {
    this.state = state;
    this.value = value;
    this.exception = exception;
    this.creatorFormType = creatorFormType;
  }

  @SuppressWarnings("unchecked")
  public ValueHolder<V> clone() {
    try {
      return (ValueHolder<V>) super.clone();
    } catch (CloneNotSupportedException e) {
      throw new RuntimeException(e);
    }
  }

  public State state() {
    return this.state;
  }

  public V returnedValue() {
    return this.state.value(this);
  }

  public Throwable thrownException() {
    return this.state.exception(this);
  }

  public Object value() {
    if (isValueReturned())
      return this.returnedValue();
    if (isEvaluationSkipped())
      return EVALUATION_SKIPPED;
    if (isExceptionThrown())
      return this.thrownException();
    throw new IllegalStateException();
  }

  public static <V> ValueHolder<V> forValue(V value) {
    return new ValueHolder<>(State.VALUE_RETURNED, value, null, CreatorFormType.UNKNOWN);
  }

  @Override
  public String toString() {
    if (isValueReturned())
      return String.format("state:%s, value:%s, creator:%s", state, value, creatorFormType);
    if (isEvaluationSkipped())
      return String.format("state:%s, exception:%s, creator:%s", state, exception, creatorFormType);
    return String.format("state:%s, creator:%s", state, creatorFormType);
  }

  public boolean isValueReturned() {
    return this.state() == State.VALUE_RETURNED;
  }

  public boolean isExceptionThrown() {
    return this.state() == State.EXCEPTION_THROWN;
  }

  public boolean isEvaluationSkipped() {
    return this.state() == State.EVALUATION_SKIPPED;
  }

  public CreatorFormType creatorFormType() {
    return this.creatorFormType;
  }

  public ValueHolder<V> valueReturned(V value) {
    //    requireState(this.state, v -> v.equals(State.NOT_YET_EVALUATED), v -> messageNotYetEvaluatedStateIsRequired(v, this));
    return new ValueHolder<>(State.VALUE_RETURNED, value, null, this.creatorFormType);
  }

  public ValueHolder<V> exceptionThrown(Throwable throwable) {
    //    requireState(this.state, v -> v.equals(State.NOT_YET_EVALUATED), v -> messageNotYetEvaluatedStateIsRequired(v, this));
    return new ValueHolder<>(State.EXCEPTION_THROWN, null, requireNonNull(throwable), this.creatorFormType);
  }

  public ValueHolder<V> evaluationSkipped() {
    //    requireState(this.state, v -> v.equals(State.NOT_YET_EVALUATED), v -> messageNotYetEvaluatedStateIsRequired(v, this));
    return new ValueHolder<>(State.EVALUATION_SKIPPED, null, null, this.creatorFormType);
  }

  public ValueHolder<V> creatorFormType(CreatorFormType creatorFormType) {
    return new ValueHolder<>(this.state, this.value, this.exception, creatorFormType);
  }

  static <E> ValueHolder<E> create() {
    return create(CreatorFormType.UNKNOWN);
  }

  public static <E> ValueHolder<E> create(CreatorFormType creatorFormType) {
    return new ValueHolder<>(State.NOT_YET_EVALUATED, null, null, creatorFormType);
  }

  public enum State {
    NOT_YET_EVALUATED {
    },
    VALUE_RETURNED {
      <V> V value(ValueHolder<V> valueHolder) {
        return valueHolder.value;
      }
    },
    EXCEPTION_THROWN {
      <V> Throwable exception(ValueHolder<V> vContextVariable) {
        return vContextVariable.exception;
      }
    },
    EVALUATION_SKIPPED {
    };

    <V> V value(ValueHolder<V> valueHolder) {
      throw new IllegalStateException("current state=" + valueHolder.state);
    }

    <V> Throwable exception(ValueHolder<V> vContextVariable) {
      throw new IllegalStateException();
    }
  }

  enum CreatorFormType {
    FUNC_HEAD,
    FUNC_TAIL,
    TRANSFORM,
    UNKNOWN
  }
}