make Registry immutable, remove other registry implementations

This commit is contained in:
dfsek
2022-08-21 00:51:26 -07:00
parent b04a4850da
commit 620ae7d1ff
39 changed files with 275 additions and 819 deletions

View File

@@ -58,19 +58,15 @@ import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.Injector;
import com.dfsek.terra.api.inject.impl.InjectorImpl;
import com.dfsek.terra.api.profiler.Profiler;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.mutable.MutableBoolean;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.GenericLoaders;
import com.dfsek.terra.config.PluginConfigImpl;
import com.dfsek.terra.event.EventManagerImpl;
import com.dfsek.terra.profiler.ProfilerImpl;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.LockedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.RegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry;
@@ -84,9 +80,7 @@ public abstract class AbstractPlatform implements Platform {
private static final MutableBoolean LOADED = new MutableBoolean(false);
private final EventManager eventManager = new EventManagerImpl();
private final ConfigRegistry configRegistry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry);
private final Registry<ConfigPack> configRegistry = new ConfigRegistry();
private final Profiler profiler = new ProfilerImpl();
@@ -94,9 +88,7 @@ public abstract class AbstractPlatform implements Platform {
private final PluginConfigImpl config = new PluginConfigImpl();
private final CheckedRegistry<BaseAddon> addonRegistry = new CheckedRegistryImpl<>(new OpenRegistryImpl<>(TypeKey.of(BaseAddon.class)));
private final Registry<BaseAddon> lockedAddonRegistry = new LockedRegistryImpl<>(addonRegistry);
private final Registry<BaseAddon> addonRegistry = ;
public ConfigRegistry getRawConfigRegistry() {
return configRegistry;
@@ -321,13 +313,13 @@ public abstract class AbstractPlatform implements Platform {
}
@Override
public @NotNull CheckedRegistry<ConfigPack> getConfigRegistry() {
return checkedConfigRegistry;
public @NotNull Registry<ConfigPack> getConfigRegistry() {
return configRegistry;
}
@Override
public @NotNull Registry<BaseAddon> getAddons() {
return lockedAddonRegistry;
public @NotNull Registry<BaseAddon> addons() {
return addonRegistry;
}
@Override

View File

@@ -56,7 +56,7 @@ public class GenericLoaders implements LoaderRegistrar {
.registerLoader(LinkedHashMap.class, new LinkedHashMapLoader());
if(platform != null) {
registry.registerLoader(BaseAddon.class, platform.getAddons())
registry.registerLoader(BaseAddon.class, platform.addons())
.registerLoader(BlockType.class, (type, object, configLoader, depthTracker) -> platform
.getWorldHandle().createBlockState((String) object).getBlockType())
.registerLoader(BlockState.class, (type, object, configLoader, depthTracker) -> platform

View File

@@ -67,8 +67,6 @@ import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.events.config.type.ConfigTypePostLoadEvent;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.tectonic.ShortcutLoader;
@@ -89,8 +87,7 @@ import com.dfsek.terra.config.preprocessor.MetaNumberPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaStringPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaValuePreprocessor;
import com.dfsek.terra.config.prototype.ProtoConfig;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.RegistryImpl;
import com.dfsek.terra.registry.ShortcutHolder;
@@ -113,10 +110,10 @@ public class ConfigPackImpl implements ConfigPack {
private final BiomeProvider seededBiomeProvider;
private final Map<Type, CheckedRegistryImpl<?>> registryMap = new HashMap<>();
private final Map<Type, RegistryImpl<?>> registryMap = new HashMap<>();
private final Map<Type, ShortcutHolder<?>> shortcuts = new HashMap<>();
private final OpenRegistry<ConfigType<?, ?>> configTypeRegistry;
private final Registry<ConfigType<?, ?>> configTypeRegistry;
private final TreeMap<Integer, List<Pair<RegistryKey, ConfigType<?, ?>>>> configTypes = new TreeMap<>();
private final RegistryKey key;
@@ -202,7 +199,7 @@ public class ConfigPackImpl implements ConfigPack {
}, ListMultimap::putAll);
configTypeRegistry.forEach(configType -> {
CheckedRegistry registry = getCheckedRegistry(configType.getTypeKey());
Registry registry = getRegistry(configType.getTypeKey());
abstractConfigLoader
.loadConfigs(multimap.get(configType))
.stream()
@@ -311,35 +308,33 @@ public class ConfigPackImpl implements ConfigPack {
@SuppressWarnings("unchecked")
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
OpenRegistry<T> registry = new OpenRegistryImpl<>(typeKey);
selfLoader.registerLoader(c, registry);
abstractConfigLoader.registerLoader(c, registry);
logger.debug("Registered loader for registry of class {}", ReflectionUtil.typeToString(c));
if(typeKey.getType() instanceof ParameterizedType param) {
Type base = param.getRawType();
if(base instanceof Class // should always be true but we'll check anyways
&& Supplier.class.isAssignableFrom((Class<?>) base)) { // If it's a supplier
Type supplied = param.getActualTypeArguments()[0]; // Grab the supplied type
if(supplied instanceof ParameterizedType suppliedParam) {
Type suppliedBase = suppliedParam.getRawType();
if(suppliedBase instanceof Class // should always be true but we'll check anyways
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
Type templateType = suppliedParam.getActualTypeArguments()[0];
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
selfLoader.registerLoader(templateType, loader);
abstractConfigLoader.registerLoader(templateType, loader);
logger.debug("Registered template loader for registry of class {}", ReflectionUtil.typeToString(templateType));
}
public <T> Registry<T> createRegistry(TypeKey<T> typeKey) {
Registry<T> registry = RegistryImpl.empty(typeKey);
selfLoader.registerLoader(c, registry);
abstractConfigLoader.registerLoader(c, registry);
logger.debug("Registered loader for registry of class {}", ReflectionUtil.typeToString(c));
if(typeKey.getType() instanceof ParameterizedType param) {
Type base = param.getRawType();
if(base instanceof Class // should always be true but we'll check anyway
&& Supplier.class.isAssignableFrom((Class<?>) base)) { // If it's a supplier
Type supplied = param.getActualTypeArguments()[0]; // Grab the supplied type
if(supplied instanceof ParameterizedType suppliedParam) {
Type suppliedBase = suppliedParam.getRawType();
if(suppliedBase instanceof Class // should always be true but we'll check anyway
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
Type templateType = suppliedParam.getActualTypeArguments()[0];
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
selfLoader.registerLoader(templateType, loader);
abstractConfigLoader.registerLoader(templateType, loader);
logger.debug("Registered template loader for registry of class {}", ReflectionUtil.typeToString(templateType));
}
}
}
return new CheckedRegistryImpl<>(registry);
});
}
return registry;
}
@Override
@@ -366,7 +361,7 @@ public class ConfigPackImpl implements ConfigPack {
@Override
public <T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader) {
ShortcutHolder<?> holder = shortcuts
.computeIfAbsent(clazz.getType(), c -> new ShortcutHolder<>(getOrCreateRegistry(clazz)))
.computeIfAbsent(clazz.getType(), c -> new ShortcutHolder<>(createRegistry(clazz)))
.register(shortcut, (ShortcutLoader) loader);
selfLoader.registerLoader(clazz.getType(), holder);
abstractConfigLoader.registerLoader(clazz.getType(), holder);
@@ -378,17 +373,17 @@ public class ConfigPackImpl implements ConfigPack {
return template.getGeneratorProvider();
}
private OpenRegistry<ConfigType<?, ?>> createConfigRegistry() {
return new OpenRegistryImpl<>(new LinkedHashMap<>(), CONFIG_TYPE_TYPE_KEY) {
private Registry<ConfigType<?, ?>> createConfigRegistry() {
return new RegistryImpl<>(new LinkedHashMap<>(), CONFIG_TYPE_TYPE_KEY) {
@Override
public boolean register(@NotNull RegistryKey key, @NotNull ConfigType<?, ?> value) {
if(!registryMap
.containsKey(value.getTypeKey()
.getType())) {
OpenRegistry<?> openRegistry = new OpenRegistryImpl<>(value.getTypeKey());
selfLoader.registerLoader(value.getTypeKey().getType(), openRegistry);
abstractConfigLoader.registerLoader(value.getTypeKey().getType(), openRegistry);
registryMap.put(value.getTypeKey().getType(), new CheckedRegistryImpl<>(openRegistry));
Registry<?> Registry = new RegistryImpl<>(value.getTypeKey());
selfLoader.registerLoader(value.getTypeKey().getType(), Registry);
abstractConfigLoader.registerLoader(value.getTypeKey().getType(), Registry);
registryMap.put(value.getTypeKey().getType(), new RegistryImpl<>(Registry));
}
return super.register(key, value);
}
@@ -396,9 +391,10 @@ public class ConfigPackImpl implements ConfigPack {
}
private void checkDeadEntries() {
registryMap.forEach((clazz, pair) -> ((OpenRegistryImpl<?>) pair.getRegistry())
.getDeadEntries()
.forEach((id, value) -> logger.debug("Dead entry in '{}' registry: '{}'", ReflectionUtil.typeToString(clazz), id)));
logger.warn("TODO: Dead Entries");
//registryMap.forEach((clazz, pair) -> ((RegistryImpl<?>) pair.getRegistry())
// .getDeadEntries()
// .forEach((id, value) -> logger.debug("Dead entry in '{}' registry: '{}'", ReflectionUtil.typeToString(clazz), id)));
}
public ConfigPackTemplate getTemplate() {
@@ -407,14 +403,14 @@ public class ConfigPackImpl implements ConfigPack {
@Override
@SuppressWarnings("unchecked")
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
public <T> Registry<T> getRegistry(Type type) {
return (Registry<T>) registryMap.get(type);
}
@SuppressWarnings("unchecked")
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);
public <T> Registry<T> getRegistry(Type type) throws IllegalStateException {
return (Registry<T>) registryMap.get(type);
}
@Override

View File

@@ -1,108 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.registry;
import com.dfsek.tectonic.api.depth.DepthTracker;
import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.TypeKey;
/**
* Wrapper for a registry that ensures checked additions.
*
* @param <T> Type in registry
*/
public class CheckedRegistryImpl<T> implements CheckedRegistry<T> {
private final OpenRegistry<T> registry;
public CheckedRegistryImpl(OpenRegistry<T> registry) {
this.registry = registry;
}
@Internal
public OpenRegistry<T> getRegistry() {
return registry;
}
@Override
public void register(@NotNull RegistryKey identifier, @NotNull T value) throws DuplicateEntryException {
registry.registerChecked(identifier, value);
}
@Override
public Optional<T> get(@NotNull RegistryKey key) {
return registry.get(key);
}
@Override
public boolean contains(@NotNull RegistryKey key) {
return registry.contains(key);
}
@Override
public void forEach(@NotNull Consumer<T> consumer) {
registry.forEach(consumer);
}
@Override
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
registry.forEach(consumer);
}
@Override
public @NotNull Collection<T> entries() {
return registry.entries();
}
@Override
public @NotNull Set<RegistryKey> keys() {
return registry.keys();
}
@Override
public TypeKey<T> getType() {
return registry.getType();
}
@Override
public Map<RegistryKey, T> getMatches(String id) {
return registry.getMatches(id);
}
@Override
public T load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
throws LoadException {
return registry.load(t, c, loader, depthTracker);
}
}

View File

@@ -1,95 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.registry;
import com.dfsek.tectonic.api.depth.DepthTracker;
import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.TypeKey;
/**
* Wrapper for a registry that forbids all write access.
*
* @param <T> Type in registry
*/
public class LockedRegistryImpl<T> implements Registry<T> {
private final Registry<T> registry;
public LockedRegistryImpl(Registry<T> registry) {
this.registry = registry;
}
@Override
public Optional<T> get(@NotNull RegistryKey key) {
return registry.get(key);
}
@Override
public boolean contains(@NotNull RegistryKey key) {
return registry.contains(key);
}
@Override
public void forEach(@NotNull Consumer<T> consumer) {
registry.forEach(consumer);
}
@Override
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
registry.forEach(consumer);
}
@Override
public @NotNull Collection<T> entries() {
return registry.entries();
}
@Override
public @NotNull Set<RegistryKey> keys() {
return registry.keys();
}
@Override
public TypeKey<T> getType() {
return registry.getType();
}
@Override
public Map<RegistryKey, T> getMatches(String id) {
return registry.getMatches(id);
}
@Override
public T load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
throws LoadException {
return registry.load(t, c, loader, depthTracker);
}
}

View File

@@ -1,185 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.registry;
import com.dfsek.tectonic.api.depth.DepthTracker;
import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.reflection.TypeKey;
/**
* Registry implementation with read/write access. For internal use only.
*
* @param <T>
*/
public class OpenRegistryImpl<T> implements OpenRegistry<T> {
private static final Entry<?> NULL = new Entry<>(null);
private final Map<RegistryKey, Entry<T>> objects;
private final ListMultimap<String, Pair<RegistryKey, Entry<T>>> objectIDs = Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
private final TypeKey<T> typeKey;
public OpenRegistryImpl(TypeKey<T> typeKey) {
this(new HashMap<>(), typeKey);
}
protected OpenRegistryImpl(Map<RegistryKey, Entry<T>> init, TypeKey<T> typeKey) {
this.objects = init;
this.typeKey = typeKey;
}
@Override
public T load(@NotNull AnnotatedType type, @NotNull Object o, @NotNull ConfigLoader configLoader, DepthTracker depthTracker)
throws LoadException {
return getByID((String) o).orElseThrow(() -> new LoadException("No such " + type.getType().getTypeName() + " matching \"" + o +
"\" was found in this registry. Registry contains items: " +
getItemsFormatted(), depthTracker));
}
private String getItemsFormatted() {
if(objects.isEmpty()) {
return "[ ]";
}
return objects
.keySet()
.stream()
.map(RegistryKey::toString)
.sorted()
.reduce("", (a, b) -> a + "\n - " + b);
}
@Override
public boolean register(@NotNull RegistryKey identifier, @NotNull T value) {
return register(identifier, new Entry<>(value));
}
@Override
public void registerChecked(@NotNull RegistryKey identifier, @NotNull T value) throws DuplicateEntryException {
if(objects.containsKey(identifier))
throw new DuplicateEntryException("Value with identifier \"" + identifier + "\" is already defined in registry.");
register(identifier, value);
}
@Override
public void clear() {
objects.clear();
objectIDs.clear();
}
private boolean register(RegistryKey identifier, Entry<T> value) {
boolean exists = objects.containsKey(identifier);
objects.put(identifier, value);
objectIDs.put(identifier.getID(), Pair.of(identifier, value));
return exists;
}
@SuppressWarnings("unchecked")
@Override
public Optional<T> get(@NotNull RegistryKey key) {
return Optional.ofNullable(objects.getOrDefault(key, (Entry<T>) NULL).getValue());
}
@Override
public boolean contains(@NotNull RegistryKey key) {
return objects.containsKey(key);
}
@Override
public void forEach(@NotNull Consumer<T> consumer) {
objects.forEach((id, obj) -> consumer.accept(obj.getRaw()));
}
@Override
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw()));
}
@Override
public @NotNull Collection<T> entries() {
return objects.values().stream().map(Entry::getRaw).collect(Collectors.toList());
}
@Override
public @NotNull Set<RegistryKey> keys() {
return objects.keySet();
}
@Override
public TypeKey<T> getType() {
return typeKey;
}
@Override
public Map<RegistryKey, T> getMatches(String id) {
return objectIDs
.get(id)
.stream()
.collect(HashMap::new, (map, pair) -> map.put(pair.getLeft(), pair.getRight().getValue()), Map::putAll);
}
public Map<RegistryKey, T> getDeadEntries() {
Map<RegistryKey, T> dead = new HashMap<>();
objects.forEach((id, entry) -> {
if(entry.dead()) dead.put(id, entry.value); // dont increment value here.
});
return dead;
}
private static final class Entry<T> {
private final T value;
private final AtomicInteger access = new AtomicInteger(0);
public Entry(T value) {
this.value = value;
}
public boolean dead() {
return access.get() == 0;
}
public T getValue() {
access.incrementAndGet();
return value;
}
private T getRaw() {
return value;
}
}
}

View File

@@ -0,0 +1,103 @@
package com.dfsek.terra.registry;
import com.dfsek.tectonic.api.depth.DepthTracker;
import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.TypeKey;
public class RegistryImpl<T> implements Registry<T> {
private final io.vavr.collection.Map<RegistryKey, T> contents;
private final TypeKey<T> type;
private RegistryImpl(io.vavr.collection.Map<RegistryKey, T> contents, TypeKey<T> type) {
this.contents = contents;
this.type = type;
}
public static <T> RegistryImpl<T> empty(TypeKey<T> key) {
return new RegistryImpl<>(io.vavr.collection.HashMap.empty(), key);
}
@Override
public Optional<T> get(@NotNull RegistryKey key) {
return contents.get(key).toJavaOptional();
}
@Override
public boolean contains(@NotNull RegistryKey key) {
return contents.containsKey(key);
}
@Override
public void forEach(@NotNull Consumer<T> consumer) {
contents.values().forEach(consumer);
}
@Override
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
contents.forEach(consumer);
}
@Override
public @NotNull Set<T> entries() {
return contents.values().toJavaSet();
}
@Override
public Registry<T> register(@NotNull RegistryKey identifier, @NotNull T value) {
return new RegistryImpl<>(contents.put(identifier, value), type);
}
@Override
public @NotNull Set<RegistryKey> keys() {
return contents.keySet().toJavaSet();
}
@Override
public TypeKey<T> getType() {
return type;
}
@Override
public Map<RegistryKey, T> getID(String id) {
return contents.filterKeys(key -> key.getID().equals(id)).toJavaMap();
}
@Override
public Map<RegistryKey, T> getNamespace(String namespace) {
return contents.filterKeys(key -> key.getNamespace().equals(namespace)).toJavaMap();
}
@Override
public T load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader, DepthTracker depthTracker)
throws LoadException {
return get(RegistryKey.parse((String) o)).orElseThrow(() -> new LoadException("No such " + type.getType().getTypeName() + " matching \"" + o +
"\" was found in this registry. Registry contains items: " +
getItemsFormatted(), depthTracker));
}
private String getItemsFormatted() {
if(contents.isEmpty()) {
return "[ ]";
}
return contents
.keySet()
.map(RegistryKey::toString)
.toSortedSet()
.reduce((a, b) -> a + "\n - " + b);
}
}

View File

@@ -18,6 +18,9 @@
package com.dfsek.terra.registry.master;
import com.dfsek.tectonic.api.exception.ConfigException;
import com.dfsek.terra.registry.RegistryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,13 +33,12 @@ import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.pack.ConfigPackImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
/**
* Class to hold config packs
*/
public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
public class ConfigRegistry extends RegistryImpl<ConfigPack> {
private static final Logger logger = LoggerFactory.getLogger(ConfigRegistry.class);
public ConfigRegistry() {

View File

@@ -1,96 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package registry;
import org.junit.jupiter.api.Test;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import static org.junit.jupiter.api.Assertions.*;
public class RegistryTest {
@Test
public void openRegistry() {
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
test.register(RegistryKey.parse("test:test"), "bazinga");
assertEquals(test.get(RegistryKey.parse("test:test")).orElseThrow(), "bazinga");
}
@Test
public void openRegistryChecked() {
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
test.registerChecked(RegistryKey.parse("test:test"), "bazinga");
try {
test.registerChecked(RegistryKey.parse("test:test"), "bazinga2");
fail("Shouldn't be able to re-register with #registerChecked!");
} catch(DuplicateEntryException ignore) {
}
}
@Test
public void checkedRegistry() {
CheckedRegistry<String> test = new CheckedRegistryImpl<>(new OpenRegistryImpl<>(TypeKey.of(String.class)));
test.register(RegistryKey.parse("test:test"), "bazinga");
assertEquals(test.get(RegistryKey.parse("test:test")).orElseThrow(), "bazinga");
try {
test.register(RegistryKey.parse("test:test"), "bazinga2");
fail("Shouldn't be able to re-register in CheckedRegistry!");
} catch(DuplicateEntryException ignore) {
}
}
@Test
public void getID() {
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
test.register(RegistryKey.parse("test:test"), "bazinga");
assertEquals(test.getByID("test").orElseThrow(), "bazinga");
}
@Test
public void getIDAmbiguous() {
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
test.registerChecked(RegistryKey.parse("test:test"), "bazinga");
test.registerChecked(RegistryKey.parse("test2:test"), "bazinga");
try {
test.getByID("test");
fail("Shouldn't be able to get with ambiguous ID!");
} catch(IllegalArgumentException ignore) {
}
}
}