MessageFieldGenerator.java

package net.morimekta.providence.testing.generator;

import net.morimekta.providence.PMessage;
import net.morimekta.providence.PMessageOrBuilder;

import javax.annotation.Nonnull;
import java.util.function.Predicate;

/**
 * Basic generator interface.
 *
 * @param <M> The message type.
 * @param <MB> The message or builder interface.
 * @param <C> The context implementation type.
 * @param <T> The value type.
 */
@FunctionalInterface
public interface MessageFieldGenerator<
        M extends PMessage<M>,
        MB extends PMessageOrBuilder<M>,
        C extends GeneratorContext<C>,
        T> {
    /**
     * @param message The message (intermediate) this field is built for.
     * @param generator The generator to use for internal values.
     * @return The generated value.
     */
    T generate(MB message, C generator);

    /**
     * Simple class that wraps a standard value generator.
     *
     * @param <M> The message type.
     * @param <MB> The message or builder interface.
     * @param <C> The context implementation type.
     * @param <T> The value type.
     */
    class Wrapper<
            M extends PMessage<M>,
            MB extends PMessageOrBuilder<M>,
            C extends GeneratorContext<C>,
            T> implements MessageFieldGenerator<M, MB, C, T> {
        private final Generator<C, T> generator;

        public Wrapper(Generator<C, T> generator) {
            this.generator = generator;
        }

        @Override
        public T generate(MB message, C generator) {
            return this.generator.generate(generator);
        }
    }

    /**
     * Conditional field value generator.
     *
     * @param <M> The message type.
     * @param <MB> The message or builder interface.
     * @param <C> The context implementation type.
     * @param <T> The value type.
     */
    class Conditional<
            M extends PMessage<M>,
            MB extends PMessageOrBuilder<M>,
            C extends GeneratorContext<C>,
            T>
            implements MessageFieldGenerator<M, MB, C, T> {
        private final Predicate<MB>                      predicate;
        private final MessageFieldGenerator<M, MB, C, T> generator;

        public Conditional(@Nonnull Predicate<MB> predicate,
                           @Nonnull MessageFieldGenerator<M, MB, C, T> generator) {
            this.predicate = predicate;
            this.generator = generator;
        }

        @Override
        public T generate(MB message, C context) {
            if (predicate.test(message)) {
                return generator.generate(message, context);
            }
            return null;
        }
    }
}