EnumInitUtil.java

/*
 * Copyright © 2015 The Authors
 *
 * https://www.gnu.org/licenses/lgpl-3.0-standalone.html
 */
package org.interstellarocean.terraforming.util;

import java.util.Collection;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * {@link Enum}s safe transforming utility.
 *
 * <p><b>NOTE</b> All methods throws {@link AssertionError} when unsafe operation is detected.
 *
 * @see <a href="https://github.com/InterstellarOcean/terraforming/wiki/Safe-enum-transforming">Documentation Wiki</a>
 *
 * @author Dariusz Wakuliński
 */
public class EnumInitUtil {

	private static final EnumInitHelper IMPLEMENTATION = new EnumInitHelper();

	// static utility pattern - instantiation and extension is forbidden
	private EnumInitUtil() {
	}

	/**
	 * {@link AssertionError} supplier supporting mapping null attempts.
	 *
	 * @param element The enum instance that is attempted to map with null
	 * @return {@link Supplier} of {@link AssertionError} that throws when called
	 */
	public static Supplier<AssertionError> nullMappingError(Enum<?> element) {
		return IMPLEMENTATION.nullMappingError(element);
	}

	/**
	 * Asserts that all enum instances has been mapped, and none has been missed.
	 * Verifies provided {@link EnumMap} and throws {@link AssertionError}s when failed.
	 * <p>
	 * <b>NOTE</b> Argument is of an {@link EnumMap} type. That way it makes you use that very implementation,
	 * which you should prefer for enum mapping anyway.
	 * </p>
	 *
	 * @param mappings {@link EnumMap} to verify
	 * @param <E> Enum type
	 * @param <M> Mappings type
	 * @return Passed argument, unmodified
	 */
	public static <E extends Enum<E>, M> EnumMap<E, M> assertAllMapped(EnumMap<E, M> mappings) {
		return IMPLEMENTATION.assertAllMapped(mappings);
	}

	/**
	 * Allows defining mapping for an enum instance in a safe way.
	 *
	 * @param element Enum instance to map
	 * @param <E> Enum type
	 * @return Interface {@link SafeMapFrom} with mapping operations
	 */
	public static <E extends Enum<E>> SafeMapFrom<E> safeMap(E element) {
		return IMPLEMENTATION.safeMap(element);
	}

	/**
	 * Enum mapping operations.
	 *
	 * @param <E> Enum type to map
	 */
	public interface SafeMapFrom<E extends Enum<E>> {

		/**
		 * Maps all provided elements to the enum under mapping.
		 *
		 * @param mappings Elements to be mapped to the enum
		 * @param <M> Mapping elements type
		 * @return Interface {@link SafeMapStore} with mappings storing operations
		 */
		<M> SafeMapStore<E, M> from(Collection<M> mappings);

		/**
		 * Maps all provided elements to the enum under mapping.
		 *
		 * @param mappings Elements to be mapped to the enum.
		 * @param <M> Mapping elements type
		 * @return Interface {@link SafeMapStore} with mappings storing operations
		 */
		@SuppressWarnings("unchecked") // @SafeVarargs can be declared on implementation only
		<M> SafeMapStore<E, M> from(M... mappings);

	}

	/**
	 * Mappings storing operations.
	 *
	 * @param <E> Enum type mapped
	 * @param <M> Mapping elements type
	 */
	public interface SafeMapStore<E extends Enum<E>, M> {

		/**
		 * Stores enum instance mappings to provided map.
		 *
		 * @param map Map to store mapping to
		 * @return Enum instance that has been mapped
		 */
		E withStore(Map<M, E> map);

		/**
		 * Allows to include mapped enum's self in the mappings.
		 * Provided enum transformation will be used to produce enum instance's form that will be added to the mappings.
		 *
		 * @param transformation Enum transformation to mappings type
		 * @return Interface {@link SafeMapStore} with mappings storing operations
		 */
		SafeMapStore<E, M> includeSelf(Function<E, M> transformation);

	}

}