content: package org.allaymc.api.registry;
  
  import java.util.Map;
  import java.util.function.Supplier;
  
  /**
   * A public registry holding a map of various registrations as defined by {@code MAPPING}.
   * The M represents the map class, which can be anything that extends {@link Map}. The
   * {@code KEY} and {@code VALUE} generics are the key and value respectively.
   *
   * @param <KEY>     the key
   * @param <VALUE>   the value
   * @param <MAPPING> the map
   *
   * @author GeyserMC | daoge_cmd
   */
  public class MappedRegistry<KEY, VALUE, MAPPING extends Map<KEY, VALUE>> extends AbstractMappedRegistry<KEY, VALUE, MAPPING> {
      protected <INPUT> MappedRegistry(INPUT input, RegistryLoader<INPUT, MAPPING> registryLoader) {
          super(input, registryLoader);
      }
  
      /**
       * Creates a new mapped registry with the given {@link RegistryLoader}. The
       * input type is not specified here, meaning the loader return type is either
       * predefined, or the registry is populated at a later point.
       *
       * @param registryLoader the registry loader
       * @param <INPUT>        the input
       * @param <KEY>          the map key
       * @param <VALUE>        the map value
       * @param <MAPPING>      the returned mappings type, a map in this case
       *
       * @return a new registry with the given RegistryLoader
       */
      public static <INPUT, KEY, VALUE, MAPPING extends Map<KEY, VALUE>> AbstractMappedRegistry<KEY, VALUE, MAPPING> of(RegistryLoader<INPUT, MAPPING> registryLoader) {
          return new MappedRegistry<>(null, registryLoader);
      }
  
      /**
       * Creates a new mapped registry with the given {@link RegistryLoader} and input.
       *
       * @param input          the input
       * @param registryLoader the registry loader
       * @param <INPUT>        the input
       * @param <KEY>          the map key
       * @param <VALUE>        the map value
       * @param <MAPPING>      the returned mappings type, a map in this case
       *
       * @return a new registry with the given RegistryLoader
       */
      public static <INPUT, KEY, VALUE, MAPPING extends Map<KEY, VALUE>> AbstractMappedRegistry<KEY, VALUE, MAPPING> of(INPUT input, RegistryLoader<INPUT, MAPPING> registryLoader) {
          return new MappedRegistry<>(input, registryLoader);
      }
  
      /**
       * Creates a new mapped registry with the given {@link RegistryLoader} supplier.
       * The input type is not specified here, meaning the loader return type is either
       * predefined, or the registry is populated at a later point.
       *
       * @param registryLoader the registry loader supplier
       * @param <INPUT>        the input
       * @param <KEY>          the map key
       * @param <VALUE>        the map value
       * @param <MAPPING>      the returned mappings type, a map in this case
       *
       * @return a new registry with the given RegistryLoader supplier
       */
      public static <INPUT, KEY, VALUE, MAPPING extends Map<KEY, VALUE>> AbstractMappedRegistry<KEY, VALUE, MAPPING> of(Supplier<RegistryLoader<INPUT, MAPPING>> registryLoader) {
          return new MappedRegistry<>(null, registryLoader.get());
      }
  
      /**
       * Creates a new mapped registry with the given {@link RegistryLoader} and input.
       *
       * @param registryLoader the registry loader
       * @param <INPUT>        the input
       * @param <KEY>          the map key
       * @param <VALUE>        the map value
       * @param <MAPPING>      the returned mappings type, a map in this case
       *
       * @return a new registry with the given RegistryLoader supplier
       */
      public static <INPUT, KEY, VALUE, MAPPING extends Map<KEY, VALUE>> AbstractMappedRegistry<KEY, VALUE, MAPPING> of(INPUT input, Supplier<RegistryLoader<INPUT, MAPPING>> registryLoader) {
          return new MappedRegistry<>(input, registryLoader.get());
      }
  }
  