feat(default-exts): Implement read fallback extension

This commit is contained in:
2025-11-09 21:47:45 +01:00
parent 1f155df646
commit efc9d8647b
3 changed files with 161 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
package de.siphalor.tweed5.defaultextensions.readfallback.api;
import de.siphalor.tweed5.core.api.extension.TweedExtension;
import de.siphalor.tweed5.defaultextensions.readfallback.impl.ReadFallbackExtensionImpl;
public interface ReadFallbackExtension extends TweedExtension {
Class<? extends ReadFallbackExtension> DEFAULT = ReadFallbackExtensionImpl.class;
String EXTENSION_ID = "read-fallback";
@Override
default String getId() {
return EXTENSION_ID;
}
}

View File

@@ -0,0 +1,71 @@
package de.siphalor.tweed5.defaultextensions.readfallback.impl;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.middleware.Middleware;
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
import lombok.extern.apachecommons.CommonsLog;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.Collections;
import java.util.Set;
@CommonsLog
public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWriteRelatedExtension {
private final ConfigContainer<?> configContainer;
private @Nullable PresetsExtension presetsExtension;
public ReadFallbackExtensionImpl(ConfigContainer<?> configContainer) {
this.configContainer = configContainer;
}
@Override
public void extensionsFinalized() {
presetsExtension = configContainer.extension(PresetsExtension.class)
.orElseThrow(() -> new IllegalStateException(getClass().getSimpleName()
+ " requires " + ReadFallbackExtension.class.getSimpleName()));
}
@Override
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
assert presetsExtension != null;
context.registerReaderMiddleware(new Middleware<TweedEntryReader<?, ?>>() {
@Override
public String id() {
return EXTENSION_ID;
}
@Override
public Set<String> mustComeBefore() {
return Collections.singleton(DEFAULT_START);
}
@Override
public Set<String> mustComeAfter() {
return Collections.emptySet();
}
@Override
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
//noinspection unchecked
TweedEntryReader<Object, ConfigEntry<Object>> castedInner =
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) (reader, entry, context1) -> {
try {
return castedInner.read(reader, entry, context1);
} catch (TweedEntryReadException e) {
log.error("Failed to read entry: " + e.getMessage(), e);
return presetsExtension.presetValue(entry, PresetsExtension.DEFAULT_PRESET_NAME);
}
};
}
});
}
}

View File

@@ -0,0 +1,76 @@
package de.siphalor.tweed5.defaultextensions.readfallback.impl;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
import de.siphalor.tweed5.data.extension.api.TweedWriteContext;
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriter;
import de.siphalor.tweed5.data.hjson.HjsonLexer;
import de.siphalor.tweed5.data.hjson.HjsonReader;
import de.siphalor.tweed5.dataapi.api.*;
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import java.io.StringReader;
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.entryReaderWriter;
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.read;
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
import static org.assertj.core.api.Assertions.assertThat;
@NullMarked
class ReadFallbackExtensionImplTest {
@Test
void test() {
DefaultConfigContainer<Integer> configContainer = new DefaultConfigContainer<>();
configContainer.registerExtension(ReadWriteExtension.class);
configContainer.registerExtension(PresetsExtension.class);
configContainer.registerExtension(ReadFallbackExtension.DEFAULT);
configContainer.finishExtensionSetup();
ConfigEntry<Integer> entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
.apply(presetValue(PresetsExtension.DEFAULT_PRESET_NAME, -1))
.apply(entryReaderWriter(new TweedEntryReaderWriter<>() {
@Override
public Integer read(
TweedDataReader reader,
ConfigEntry<Integer> entry,
TweedReadContext context
) throws TweedEntryReadException {
int value;
try {
value = reader.readToken().readAsInt();
} catch (TweedDataReadException e) {
throw new IllegalStateException("Should not be called", e);
}
if (value % 2 == 0) {
return value;
} else {
throw new TweedEntryReadException("Value is not even", context);
}
}
@Override
public void write(
TweedDataVisitor writer,
@Nullable Integer value,
ConfigEntry<Integer> entry,
TweedWriteContext context
) throws TweedDataWriteException {
throw new IllegalStateException("Should not be called");
}
}));
configContainer.attachTree(entry);
configContainer.initialize();
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("12")))))).isEqualTo(12);
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("13")))))).isEqualTo(-1);
}
}