refactor!(core): Simplify ConfigEntryValueVisitor by introducing SubEntryKey instead of passing values separately
This commit is contained in:
@@ -9,5 +9,5 @@ public interface AddressableStructuredConfigEntry<T> extends StructuredConfigEnt
|
||||
return this;
|
||||
}
|
||||
|
||||
Object get(T value, String key);
|
||||
Object get(T value, String dataKey);
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ public interface CollectionConfigEntry<E, T extends Collection<E>> extends Struc
|
||||
if (visitor.enterStructuredEntry(this, value)) {
|
||||
int index = 0;
|
||||
for (E item : value) {
|
||||
String indexString = Integer.toString(index);
|
||||
if (visitor.enterAddressableStructuredSubEntry("element", indexString, null)) {
|
||||
SubEntryKey subEntryKey = SubEntryKey.structured("element", Integer.toString(index));
|
||||
if (visitor.enterSubEntry(subEntryKey)) {
|
||||
elementEntry().visitInOrder(visitor, item);
|
||||
visitor.leaveAddressableStructuredSubEntry("element", indexString, null);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
@@ -8,18 +8,11 @@ public interface ConfigEntryValueVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean enterAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
||||
default boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void leaveAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
||||
}
|
||||
|
||||
default void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
||||
default void leaveSubEntry(SubEntryKey subEntryKey) {
|
||||
}
|
||||
|
||||
default <T> void leaveStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||
|
||||
@@ -12,5 +12,5 @@ public interface MutableStructuredConfigEntry<T> extends AddressableStructuredCo
|
||||
}
|
||||
|
||||
@NonNull T instantiateValue();
|
||||
void set(T value, String key, Object subValue);
|
||||
void set(T value, String dataKey, Object subValue);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package de.siphalor.tweed5.core.api.entry;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@Value
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SubEntryKey {
|
||||
String entry;
|
||||
@Nullable String value;
|
||||
@Nullable String data;
|
||||
|
||||
/**
|
||||
* Models the key of a transparent entry. Transparent entries are sub entries that only exist in the entry tree
|
||||
* but are not actually present in the data.
|
||||
* @param entryKey the key of the entry in the entry tree
|
||||
* @apiNote The resulting key is not addressable.
|
||||
*/
|
||||
public static SubEntryKey transparent(String entryKey) {
|
||||
return new SubEntryKey(entryKey, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Models the key of a transparent entry with a data key for use with {@link AddressableStructuredConfigEntry}s.
|
||||
* @param entryKey the key of the entry in the entry tree
|
||||
* @param dataKey the "address" of the data in the {@link AddressableStructuredConfigEntry}
|
||||
*/
|
||||
public static SubEntryKey transparentAddressable(String entryKey, String dataKey) {
|
||||
return new SubEntryKey(entryKey, null, dataKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* A "normal" sub entry key.
|
||||
* @param entryKey the key of the entry in the entry tree
|
||||
* @param valueKey a potentially differing key for the user-facing data tree
|
||||
*/
|
||||
public static SubEntryKey structured(String entryKey, String valueKey) {
|
||||
return new SubEntryKey(entryKey, valueKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sub entry key for {@link AddressableStructuredConfigEntry}s.
|
||||
* @param entryKey the key of the entry in the entry tree
|
||||
* @param valueKey a potentially differing key for the user-facing data tree
|
||||
* @param dataKey the "address" of the data in the {@link AddressableStructuredConfigEntry}
|
||||
* @apiNote {@code valueKey} and {@code dataKey} are usually a 1:1 mapping.
|
||||
*/
|
||||
public static SubEntryKey addressable(String entryKey, String valueKey, String dataKey) {
|
||||
return new SubEntryKey(entryKey, valueKey, dataKey);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||
import de.siphalor.tweed5.core.api.entry.NullableConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -25,7 +26,7 @@ public class NullableConfigEntryImpl<T extends @Nullable Object> extends BaseCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(T value, String key) {
|
||||
public T get(T value, String dataKey) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -38,9 +39,10 @@ public class NullableConfigEntryImpl<T extends @Nullable Object> extends BaseCon
|
||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||
if (value != null) {
|
||||
if (visitor.enterStructuredEntry(this, value)) {
|
||||
if (visitor.enterAddressableStructuredSubEntry(NON_NULL_KEY, NON_NULL_KEY, NON_NULL_KEY)) {
|
||||
SubEntryKey subEntryKey = SubEntryKey.transparentAddressable(NON_NULL_KEY, NON_NULL_KEY);
|
||||
if (visitor.enterSubEntry(subEntryKey)) {
|
||||
nonNullEntry.visitInOrder(visitor, value);
|
||||
visitor.leaveAddressableStructuredSubEntry(NON_NULL_KEY, NON_NULL_KEY, NON_NULL_KEY);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
}
|
||||
visitor.leaveStructuredEntry(this, value);
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ public class StaticMapCompoundConfigEntryImpl<T extends @NonNull Map<String, Obj
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T compoundValue, String key, Object value) {
|
||||
requireKey(key);
|
||||
compoundValue.put(key, value);
|
||||
public void set(T compoundValue, String dataKey, Object value) {
|
||||
requireKey(dataKey);
|
||||
compoundValue.put(dataKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(T compoundValue, String key) {
|
||||
requireKey(key);
|
||||
return compoundValue.get(key);
|
||||
public Object get(T compoundValue, String dataKey) {
|
||||
requireKey(dataKey);
|
||||
return compoundValue.get(dataKey);
|
||||
}
|
||||
|
||||
private void requireKey(String key) {
|
||||
@@ -55,10 +55,11 @@ public class StaticMapCompoundConfigEntryImpl<T extends @NonNull Map<String, Obj
|
||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||
if (visitor.enterStructuredEntry(this, value)) {
|
||||
compoundEntries.forEach((key, entry) -> {
|
||||
if (visitor.enterAddressableStructuredSubEntry(key, key, key)) {
|
||||
SubEntryKey subEntryKey = SubEntryKey.addressable(key, key, key);
|
||||
if (visitor.enterSubEntry(subEntryKey)) {
|
||||
//noinspection unchecked
|
||||
((ConfigEntry<Object>) entry).visitInOrder(visitor, value.get(key));
|
||||
visitor.leaveAddressableStructuredSubEntry(key, key, key);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
}
|
||||
});
|
||||
visitor.leaveStructuredEntry(this, value);
|
||||
|
||||
@@ -9,7 +9,11 @@ public interface PathTracking {
|
||||
|
||||
void pushPathPart(String pathPart);
|
||||
|
||||
void pushEmptyPathPart();
|
||||
|
||||
void popPathPart();
|
||||
|
||||
String currentPath();
|
||||
|
||||
String[] currentPathParts();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||
import de.siphalor.tweed5.core.api.entry.StructuredConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -22,32 +23,21 @@ public class PathTrackingConfigEntryValueVisitor implements ConfigEntryValueVisi
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
||||
boolean enter = delegate.enterAddressableStructuredSubEntry(entryKey, valueKey, dataKey);
|
||||
public boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||
boolean enter = delegate.enterSubEntry(subEntryKey);
|
||||
if (enter) {
|
||||
pathTracking.pushPathPart(entryKey, valueKey);
|
||||
if (subEntryKey.value() != null) {
|
||||
pathTracking.pushPathPart(subEntryKey.entry(), subEntryKey.value());
|
||||
} else {
|
||||
pathTracking.pushEmptyValuePathPart(subEntryKey.entry());
|
||||
}
|
||||
}
|
||||
return enter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
||||
boolean enter = delegate.enterStructuredSubEntry(entryKey, valueKey);
|
||||
if (enter) {
|
||||
pathTracking.pushPathPart(entryKey, valueKey);
|
||||
}
|
||||
return enter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
||||
delegate.leaveAddressableStructuredSubEntry(entryKey, valueKey, dataKey);
|
||||
pathTracking.popPathPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
||||
delegate.leaveStructuredSubEntry(entryKey, valueKey);
|
||||
public void leaveSubEntry(SubEntryKey subEntryKey) {
|
||||
delegate.leaveSubEntry(subEntryKey);
|
||||
pathTracking.popPathPart();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,17 @@ public final class ValuePathTracking implements PathTracking {
|
||||
valuePathTracking.pushPathPart(valuePathPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushEmptyPathPart() {
|
||||
entryPathTracking.pushEmptyPathPart();
|
||||
valuePathTracking.pushEmptyPathPart();
|
||||
}
|
||||
|
||||
public void pushEmptyValuePathPart(String entryPathPart) {
|
||||
entryPathTracking.pushPathPart(entryPathPart);
|
||||
valuePathTracking.pushEmptyPathPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popPathPart() {
|
||||
valuePathTracking.popPathPart();
|
||||
@@ -31,4 +42,13 @@ public final class ValuePathTracking implements PathTracking {
|
||||
public String currentEntryPath() {
|
||||
return entryPathTracking.currentPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] currentPathParts() {
|
||||
return valuePathTracking.currentPathParts();
|
||||
}
|
||||
|
||||
public String[] currentEntryPathParts() {
|
||||
return entryPathTracking.currentPathParts();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.impl;
|
||||
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class PathTrackingImpl implements PathTracking {
|
||||
private final StringBuilder pathBuilder = new StringBuilder(256);
|
||||
private final Deque<String> pathParts = new ArrayDeque<>(50);
|
||||
private final Deque<@Nullable String> pathParts = new ArrayDeque<>(50);
|
||||
|
||||
@Override
|
||||
public void pushPathPart(String entryPathPart) {
|
||||
@@ -15,16 +16,28 @@ public class PathTrackingImpl implements PathTracking {
|
||||
pathBuilder.append(".").append(entryPathPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushEmptyPathPart() {
|
||||
pathParts.push(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popPathPart() {
|
||||
if (!pathParts.isEmpty()) {
|
||||
String poppedPart = pathParts.pop();
|
||||
if (poppedPart != null) {
|
||||
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentPath() {
|
||||
return pathBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] currentPathParts() {
|
||||
return pathParts.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -40,30 +41,30 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T compoundValue, String key, Object value) {
|
||||
SubEntry subEntry = subEntries.get(key);
|
||||
public void set(T compoundValue, String dataKey, Object value) {
|
||||
SubEntry subEntry = subEntries.get(dataKey);
|
||||
if (subEntry == null) {
|
||||
throw new IllegalArgumentException("Unknown config entry: " + key);
|
||||
throw new IllegalArgumentException("Unknown config entry: " + dataKey);
|
||||
}
|
||||
|
||||
try {
|
||||
subEntry.setter().invoke(compoundValue, value);
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalStateException("Failed to set value for config entry \"" + key + "\"", e);
|
||||
throw new IllegalStateException("Failed to set value for config entry \"" + dataKey + "\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(T compoundValue, String key) {
|
||||
SubEntry subEntry = subEntries.get(key);
|
||||
public Object get(T compoundValue, String dataKey) {
|
||||
SubEntry subEntry = subEntries.get(dataKey);
|
||||
if (subEntry == null) {
|
||||
throw new IllegalArgumentException("Unknown config entry: " + key);
|
||||
throw new IllegalArgumentException("Unknown config entry: " + dataKey);
|
||||
}
|
||||
|
||||
try {
|
||||
return subEntry.getter().invoke(compoundValue);
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalStateException("Failed to get value for config entry \"" + key + "\"", e);
|
||||
throw new IllegalStateException("Failed to get value for config entry \"" + dataKey + "\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,12 +81,13 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
|
||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||
if (visitor.enterStructuredEntry(this, value)) {
|
||||
subEntries.forEach((key, entry) -> {
|
||||
if (visitor.enterAddressableStructuredSubEntry(key, key, key)) {
|
||||
SubEntryKey subEntryKey = SubEntryKey.addressable(key, key, key);
|
||||
if (visitor.enterSubEntry(subEntryKey)) {
|
||||
try {
|
||||
Object subValue = entry.getter().invoke(value);
|
||||
//noinspection unchecked
|
||||
((ConfigEntry<Object>) entry.configEntry()).visitInOrder(visitor, subValue);
|
||||
visitor.leaveAddressableStructuredSubEntry(key, key, key);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to get compound sub entry value \"" + key + "\"");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user