Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
52e2a52468
|
|||
|
2f4011c144
|
|||
|
a413fab8d5
|
|||
|
615d3810a0
|
|||
|
e6ef13ff7f
|
|||
|
784309b426
|
|||
|
affc1de0f5
|
|||
|
d69eb85d81
|
|||
|
1b9958f980
|
|||
|
e879050a33
|
|||
|
7673399f3e
|
|||
|
ad9c22243a
|
|||
|
56ed60e532
|
|||
|
0e5a907446
|
|||
|
2e9f4c1689
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
|||||||
.gitattributes text eol=lf
|
.gitattributes text eol=lf
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
gradlew text eol=lf
|
gradlew text eol=lf
|
||||||
|
gradlew.bat text eol=crlf
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,6 +5,11 @@ build/
|
|||||||
!**/src/test/**/build/
|
!**/src/test/**/build/
|
||||||
.kotlin/
|
.kotlin/
|
||||||
|
|
||||||
|
### Gradle in Subprojects ###
|
||||||
|
*/gradlew
|
||||||
|
*/gradlew.bat
|
||||||
|
*/gradle/wrapper
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea/
|
.idea/
|
||||||
*.iws
|
*.iws
|
||||||
|
|||||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -5,15 +5,20 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [0.7.2] - 2026-03-29
|
## [Unreleased]
|
||||||
### Changed
|
|
||||||
- `minecraft`: Added support for Minecraft 26.1.
|
|
||||||
This includes some required changes in the build process. So this release is published for all versions of Minecraft.
|
|
||||||
|
|
||||||
## [0.7.1] - 2026-02-08
|
### Added
|
||||||
|
- `networking`: Added module for Minecraft networking.
|
||||||
|
- `coat-bridge`: Added experimental text mapper based on Tweed Serde.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Relicensed to MPL-2.0.
|
- **Breaking**@`core`: Refactored type hierarchy and methods of `StructuredConfigEntry`.
|
||||||
|
- **Breaking**@`serde-*`: Repackaged all classes to bear `tweed5.serde` instead of `tweed5.data` in their packages.
|
||||||
|
- `weaver-pojo-serde-extension`: Slightly changed the `SerdePojoReaderWriterSpec`
|
||||||
|
to be more closely aligned with Java's identifier rules.
|
||||||
|
- `attributes-extension`: The `AttributesReadWriteFilterExtension` now correctly skips non-matching compound entries
|
||||||
|
instead of returning `null` for them.
|
||||||
|
- `serde-hjson`: `inlineCommentType` on `HjsonWriter.Options` now correctly works builder-style.
|
||||||
|
|
||||||
## [0.7.0] - 2025-12-19
|
## [0.7.0] - 2025-12-19
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ abstract class MinecraftModComponentPlugin : Plugin<Project> {
|
|||||||
attribute(Category.CATEGORY_ATTRIBUTE, objectFactory.named(Category.LIBRARY))
|
attribute(Category.CATEGORY_ATTRIBUTE, objectFactory.named(Category.LIBRARY))
|
||||||
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objectFactory.named(LibraryElements.JAR))
|
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objectFactory.named(LibraryElements.JAR))
|
||||||
attribute(Bundling.BUNDLING_ATTRIBUTE, objectFactory.named(Bundling.EXTERNAL))
|
attribute(Bundling.BUNDLING_ATTRIBUTE, objectFactory.named(Bundling.EXTERNAL))
|
||||||
attribute(Usage.USAGE_ATTRIBUTE, objectFactory.named(Usage.JAVA_API))
|
attribute(Usage.USAGE_ATTRIBUTE, objectFactory.named(Usage.JAVA_RUNTIME))
|
||||||
|
|
||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, targetJvmVersion.get().toInt())
|
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, targetJvmVersion.get().toInt())
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
`java-library`
|
`java-library`
|
||||||
jacoco
|
|
||||||
id("io.freefair.lombok")
|
id("io.freefair.lombok")
|
||||||
|
id("de.siphalor.tweed5.unit-tests")
|
||||||
id("de.siphalor.tweed5.publishing")
|
id("de.siphalor.tweed5.publishing")
|
||||||
id("de.siphalor.tweed5.local-runtime-only")
|
id("de.siphalor.tweed5.local-runtime-only")
|
||||||
id("de.siphalor.tweed5.expanded-sources-jar")
|
id("de.siphalor.tweed5.expanded-sources-jar")
|
||||||
@@ -13,12 +13,6 @@ java {
|
|||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
val testAgent = configurations.dependencyScope("mockitoAgent")
|
|
||||||
val testAgentClasspath = configurations.resolvable("testAgentClasspath") {
|
|
||||||
isTransitive = false
|
|
||||||
extendsFrom(testAgent.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
lombok {
|
lombok {
|
||||||
version = libs.versions.lombok.get()
|
version = libs.versions.lombok.get()
|
||||||
}
|
}
|
||||||
@@ -39,40 +33,9 @@ dependencies {
|
|||||||
testImplementation(libs.acl)
|
testImplementation(libs.acl)
|
||||||
testImplementation(libs.slf4j.rt)
|
testImplementation(libs.slf4j.rt)
|
||||||
|
|
||||||
testImplementation(platform(libs.junit.platform))
|
|
||||||
testImplementation(libs.junit.core)
|
|
||||||
testRuntimeOnly(libs.junit.launcher)
|
|
||||||
testImplementation(libs.mockito)
|
|
||||||
testAgent(libs.mockito)
|
|
||||||
testImplementation(libs.assertj)
|
|
||||||
testImplementation(project(":generic-test-utils"))
|
testImplementation(project(":generic-test-utils"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileTestJava {
|
|
||||||
sourceCompatibility = libs.versions.java.test.get()
|
|
||||||
targetCompatibility = libs.versions.java.test.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
|
||||||
val testAgentFiles = testAgentClasspath.map { it.files }
|
|
||||||
doFirst {
|
|
||||||
jvmArgs(testAgentFiles.get().map { file -> "-javaagent:${file.absolutePath}" })
|
|
||||||
}
|
|
||||||
dependsOn(testAgentClasspath)
|
|
||||||
finalizedBy(tasks.jacocoTestReport)
|
|
||||||
|
|
||||||
useJUnitPlatform()
|
|
||||||
systemProperties(
|
|
||||||
"junit.jupiter.execution.timeout.mode" to "disabled_on_debug",
|
|
||||||
"junit.jupiter.execution.timeout.testable.method.default" to "10s",
|
|
||||||
"junit.jupiter.execution.timeout.thread.mode.default" to "SEPARATE_THREAD",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.jacocoTestReport {
|
|
||||||
dependsOn(tasks.test)
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("lib") {
|
create<MavenPublication>("lib") {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
|
||||||
val rootProperties = Properties()
|
val rootPropertiesFile = project.layout.settingsDirectory.file("../gradle.properties").asFile
|
||||||
project.layout.settingsDirectory.file("../gradle.properties").asFile.inputStream().use { rootProperties.load(it) }
|
if (rootPropertiesFile.exists()) {
|
||||||
rootProperties.forEach { (key, value) -> project.ext.set(key.toString(), value.toString()) }
|
Properties()
|
||||||
|
.apply { rootPropertiesFile.inputStream().use { load(it) } }
|
||||||
|
.forEach { (key, value) -> project.ext.set(key.toString(), value.toString()) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
plugins {
|
||||||
|
java
|
||||||
|
jacoco
|
||||||
|
}
|
||||||
|
|
||||||
|
val testAgent = configurations.dependencyScope("mockitoAgent")
|
||||||
|
val testAgentClasspath = configurations.resolvable("testAgentClasspath") {
|
||||||
|
isTransitive = false
|
||||||
|
extendsFrom(testAgent.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
versionCatalogs.find("libs").ifPresent { libs ->
|
||||||
|
testImplementation(platform(libs.findLibrary("junit.platform").get()))
|
||||||
|
testImplementation(libs.findLibrary("junit.core").get())
|
||||||
|
testRuntimeOnly(libs.findLibrary("junit.launcher").get())
|
||||||
|
testImplementation(libs.findLibrary("mockito").get())
|
||||||
|
testAgent(libs.findLibrary("mockito").get())
|
||||||
|
testImplementation(libs.findLibrary("assertj").get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.compileTestJava {
|
||||||
|
versionCatalogs.find("libs").ifPresent { libs ->
|
||||||
|
sourceCompatibility = libs.findVersion("java.test").get().requiredVersion
|
||||||
|
targetCompatibility = libs.findVersion("java.test").get().requiredVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
val testAgentFiles = testAgentClasspath.map { it.files }
|
||||||
|
doFirst {
|
||||||
|
jvmArgs(testAgentFiles.get().map { file -> "-javaagent:${file.absolutePath}" })
|
||||||
|
}
|
||||||
|
dependsOn(testAgentClasspath)
|
||||||
|
finalizedBy(tasks.jacocoTestReport)
|
||||||
|
|
||||||
|
useJUnitPlatform()
|
||||||
|
systemProperties(
|
||||||
|
"junit.jupiter.execution.timeout.mode" to "disabled_on_debug",
|
||||||
|
"junit.jupiter.execution.timeout.testable.method.default" to "10s",
|
||||||
|
"junit.jupiter.execution.timeout.thread.mode.default" to "SEPARATE_THREAD",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.jacocoTestReport {
|
||||||
|
dependsOn(tasks.test)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
org.gradle.jvmargs = -Xmx2G
|
org.gradle.jvmargs = -Xmx2G
|
||||||
org.gradle.configuration-cache = true
|
org.gradle.configuration-cache = true
|
||||||
|
|
||||||
tweed5.version = 0.7.2
|
tweed5.version = 0.7.1
|
||||||
|
|
||||||
git.url = https://gitea.siphalor.de/siphalor/tweed5
|
git.url = https://gitea.siphalor.de/siphalor/tweed5
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
5
gradlew
vendored
5
gradlew
vendored
@@ -57,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -114,6 +114,7 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -171,6 +172,7 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -210,6 +212,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
|
|||||||
3
gradlew.bat
vendored
3
gradlew.bat
vendored
@@ -70,10 +70,11 @@ goto fail
|
|||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("de.siphalor.tweed5:tweed5-conventions")
|
implementation("de.siphalor.tweed5:tweed5-conventions")
|
||||||
implementation("de.siphalor.tweed5:tweed5-conventions-helpers")
|
implementation("de.siphalor.tweed5:tweed5-conventions-helpers")
|
||||||
implementation(pluginMarker(mcCommonLibs.plugins.smcmtk))
|
implementation(pluginMarker(mcCommonLibs.plugins.fabric.loom))
|
||||||
implementation(pluginMarker(mcCommonLibs.plugins.jcyo))
|
implementation(pluginMarker(mcCommonLibs.plugins.jcyo))
|
||||||
implementation(pluginMarker(mcLibs.plugins.fabric.loom))
|
|
||||||
implementation(pluginMarker(libs.plugins.lombok))
|
implementation(pluginMarker(libs.plugins.lombok))
|
||||||
implementation(pluginMarker(libs.plugins.shadow))
|
implementation(pluginMarker(libs.plugins.shadow))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import de.siphalor.jcyo.gradle.JcyoTask
|
import de.siphalor.jcyo.gradle.JcyoTask
|
||||||
import de.siphalor.tweed5.gradle.plugin.minecraft.mod.MinecraftModded
|
import de.siphalor.tweed5.gradle.plugin.minecraft.mod.MinecraftModded
|
||||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI
|
|
||||||
import net.fabricmc.loom.task.RemapJarTask
|
|
||||||
import net.fabricmc.loom.util.Constants
|
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
id("de.siphalor.minecraft-modding-toolkit.project-plugin")
|
id("fabric-loom")
|
||||||
|
id("de.siphalor.tweed5.unit-tests")
|
||||||
id("de.siphalor.tweed5.publishing")
|
id("de.siphalor.tweed5.publishing")
|
||||||
id("de.siphalor.tweed5.expanded-sources-jar")
|
id("de.siphalor.tweed5.expanded-sources-jar")
|
||||||
id("de.siphalor.jcyo")
|
id("de.siphalor.jcyo")
|
||||||
@@ -19,21 +17,14 @@ plugins {
|
|||||||
id("de.siphalor.tweed5.minecraft.mod.base")
|
id("de.siphalor.tweed5.minecraft.mod.base")
|
||||||
}
|
}
|
||||||
|
|
||||||
val mcCatalog = versionCatalogs.named("mcLibs")
|
|
||||||
val loomPluginId = mcCatalog.findPlugin("fabric.loom").get().get().pluginId
|
|
||||||
if (!loomPluginId.endsWith("-remap")) {
|
|
||||||
project.extensions.extraProperties.set(Constants.Properties.DISABLE_OBFUSCATION, "true")
|
|
||||||
project.extensions.extraProperties.set(Constants.Properties.DONT_REMAP, "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(plugin = loomPluginId)
|
|
||||||
|
|
||||||
val minecraftVersionDescriptor = project.property("minecraft.version.descriptor") as String
|
val minecraftVersionDescriptor = project.property("minecraft.version.descriptor") as String
|
||||||
val mcProps = Properties().apply {
|
val mcProps = Properties().apply {
|
||||||
val propFile = project.layout.settingsDirectory.file("gradle/mc-$minecraftVersionDescriptor/gradle.properties").asFile
|
val propFile = project.layout.settingsDirectory.file("gradle/mc-$minecraftVersionDescriptor/gradle.properties").asFile
|
||||||
propFile.inputStream().use { load(it) }
|
propFile.inputStream().use { load(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val mcCatalog = versionCatalogs.named("mcLibs")
|
||||||
|
|
||||||
group = "de.siphalor.tweed5.minecraft"
|
group = "de.siphalor.tweed5.minecraft"
|
||||||
val archivesBaseName = "${project.name}-mc$minecraftVersionDescriptor"
|
val archivesBaseName = "${project.name}-mc$minecraftVersionDescriptor"
|
||||||
base {
|
base {
|
||||||
@@ -48,12 +39,7 @@ val testmod by sourceSets.creating {
|
|||||||
runtimeClasspath += sourceSets.main.get().runtimeClasspath
|
runtimeClasspath += sourceSets.main.get().runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
smcmtk {
|
loom {
|
||||||
useMojangMappings()
|
|
||||||
createModConfigurations(listOf(sourceSets.main.get(), testmod))
|
|
||||||
}
|
|
||||||
|
|
||||||
extensions.configure<LoomGradleExtensionAPI>() {
|
|
||||||
runs {
|
runs {
|
||||||
create("testmodClient") {
|
create("testmodClient") {
|
||||||
client()
|
client()
|
||||||
@@ -61,6 +47,7 @@ extensions.configure<LoomGradleExtensionAPI>() {
|
|||||||
source(testmod)
|
source(testmod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
createRemapConfigurations(testmod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason dependencyResolutionManagement from the settings.gradle doesn't seem to be passed through correctly,
|
// For some reason dependencyResolutionManagement from the settings.gradle doesn't seem to be passed through correctly,
|
||||||
@@ -92,8 +79,12 @@ configurations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
"minecraft"(mcCatalog.findLibrary("minecraft").get())
|
minecraft(mcCatalog.findLibrary("minecraft").get())
|
||||||
"modImplementation"(mcCommonLibs.fabric.loader)
|
mappings(loom.layered {
|
||||||
|
officialMojangMappings()
|
||||||
|
parchment("org.parchmentmc.data:parchment-$minecraftVersion:${getMcCatalogVersion("parchment")}@zip")
|
||||||
|
})
|
||||||
|
modImplementation(mcCommonLibs.fabric.loader)
|
||||||
"modTestmodImplementation"(mcCommonLibs.fabric.loader)
|
"modTestmodImplementation"(mcCommonLibs.fabric.loader)
|
||||||
|
|
||||||
compileOnly(libs.jspecify.annotations)
|
compileOnly(libs.jspecify.annotations)
|
||||||
@@ -101,11 +92,6 @@ dependencies {
|
|||||||
"testmodImplementation"(sourceSets.main.map { it.output })
|
"testmodImplementation"(sourceSets.main.map { it.output })
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.toVersion(mcCatalog.findVersion("java").get())
|
|
||||||
targetCompatibility = JavaVersion.toVersion(mcCatalog.findVersion("java").get())
|
|
||||||
}
|
|
||||||
|
|
||||||
val jcyoVars = mcProps.stringPropertyNames()
|
val jcyoVars = mcProps.stringPropertyNames()
|
||||||
.filter { it.startsWith("preprocessor.") }
|
.filter { it.startsWith("preprocessor.") }
|
||||||
.map { it to mcProps[it] }
|
.map { it to mcProps[it] }
|
||||||
@@ -131,6 +117,31 @@ lombok {
|
|||||||
version = libs.versions.lombok.get()
|
version = libs.versions.lombok.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val testmodLombokConfigSource = project.layout.settingsDirectory.file("lombok.testmod.config").asFile
|
||||||
|
val testmodLombokConfigTarget = file("src/testmod/lombok.config")
|
||||||
|
val copyTestmodLombokConfig by tasks.register("copyTestmodLombokConfig") {
|
||||||
|
val source = testmodLombokConfigSource
|
||||||
|
val target = testmodLombokConfigTarget
|
||||||
|
inputs.file(source)
|
||||||
|
outputs.file(target)
|
||||||
|
|
||||||
|
doFirst {
|
||||||
|
target.parentFile.mkdirs()
|
||||||
|
Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("compileTestmodJava") {
|
||||||
|
inputs.file(testmodLombokConfigSource)
|
||||||
|
dependsOn(copyTestmodLombokConfig)
|
||||||
|
}
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.named("generateTestmodEffectiveLombokConfig") {
|
||||||
|
inputs.file(testmodLombokConfigSource)
|
||||||
|
dependsOn(copyTestmodLombokConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.named<Copy>("processResources") {
|
tasks.named<Copy>("processResources") {
|
||||||
val processMinecraftModResources = tasks.named<Sync>("processMinecraftModResources")
|
val processMinecraftModResources = tasks.named<Sync>("processMinecraftModResources")
|
||||||
dependsOn(processMinecraftModResources)
|
dependsOn(processMinecraftModResources)
|
||||||
@@ -149,8 +160,7 @@ shadow {
|
|||||||
addShadowVariantIntoJavaComponent = false
|
addShadowVariantIntoJavaComponent = false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.findByName("remapJar")?.apply {
|
tasks.remapJar {
|
||||||
this as RemapJarTask
|
|
||||||
dependsOn(tasks.shadowJar)
|
dependsOn(tasks.shadowJar)
|
||||||
inputFile = tasks.shadowJar.get().archiveFile
|
inputFile = tasks.shadowJar.get().archiveFile
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,16 @@ dependencies {
|
|||||||
compileOnly("de.siphalor.tweed5:tweed5-attributes-extension")
|
compileOnly("de.siphalor.tweed5:tweed5-attributes-extension")
|
||||||
compileOnly("de.siphalor.tweed5:tweed5-default-extensions")
|
compileOnly("de.siphalor.tweed5:tweed5-default-extensions")
|
||||||
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo")
|
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo")
|
||||||
compileOnly(project(":tweed5-logging", configuration = "minecraftModApiElements"))
|
|
||||||
modCompileOnly(mcLibs.coat)
|
modCompileOnly(mcLibs.coat)
|
||||||
|
|
||||||
listOf(smcmtk.mcProps.getting("fabric.api.key_mapping").get(), "fabric-resource-loader-v0").forEach {
|
listOf("fabric-key-binding-api-v1", "fabric-resource-loader-v0").forEach {
|
||||||
modTestmodImplementation(fabricApi.module(it, mcLibs.versions.fabric.api.get()))
|
modTestmodImplementation(fabricApi.module(it, mcLibs.versions.fabric.api.get()))
|
||||||
}
|
}
|
||||||
testmodImplementation(project(":tweed5-logging", configuration = "minecraftModElements"))
|
testmodImplementation(project(":tweed5-logging", configuration = "minecraftModApiElements"))
|
||||||
testmodImplementation(project(":tweed5-bundle", configuration = "runtimeElements"))
|
testmodImplementation(project(":tweed5-bundle", configuration = "runtimeElements"))
|
||||||
testmodImplementation(project(":tweed5-bundle-pojo-weaving", configuration = "runtimeElements"))
|
testmodImplementation(project(":tweed5-bundle-pojo-weaving", configuration = "runtimeElements"))
|
||||||
testmodImplementation(project(":tweed5-fabric-helper", configuration = "namedElements"))
|
testmodImplementation(project(":tweed5-fabric-helper", configuration = "namedElements"))
|
||||||
modTestmodImplementation(mcLibs.coat)
|
modTestmodImplementation(mcLibs.coat)
|
||||||
modTestmodImplementation(mcLibs.amecs.priorityKeyMappings)
|
modTestmodImplementation(mcLibs.amecs.api)
|
||||||
testmodImplementation("de.siphalor.tweed5:tweed5-serde-hjson")
|
testmodImplementation("de.siphalor.tweed5:tweed5-serde-hjson")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatMapper;
|
|||||||
import de.siphalor.tweed5.coat.bridge.impl.TweedCoatMappersImpl;
|
import de.siphalor.tweed5.coat.bridge.impl.TweedCoatMappersImpl;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -66,4 +67,10 @@ public class TweedCoatMappers {
|
|||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return TweedCoatMappersImpl.convertingTextMapper(new Class[]{valueClass}, textMapper, textParser);
|
return TweedCoatMappersImpl.convertingTextMapper(new Class[]{valueClass}, textMapper, textParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public static <T> TweedCoatMapper<T> serdeTextMapper(Class<T> valueClass) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return TweedCoatMappersImpl.serdeTextMapper(new Class[]{valueClass});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
|||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||||
import lombok.CustomLog;
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.literalComponent;
|
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.literalComponent;
|
||||||
|
|
||||||
@CustomLog
|
@CommonsLog
|
||||||
public class BasicTweedCoatEntryHandler<T extends @Nullable Object> implements ConfigEntryHandler<T> {
|
public class BasicTweedCoatEntryHandler<T extends @Nullable Object> implements ConfigEntryHandler<T> {
|
||||||
protected final ConfigEntry<T> configEntry;
|
protected final ConfigEntry<T> configEntry;
|
||||||
protected final T defaultValue;
|
protected final T defaultValue;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package de.siphalor.tweed5.coat.bridge.api.mapping.handler;
|
|||||||
|
|
||||||
import de.siphalor.coat.handler.ConfigEntryHandler;
|
import de.siphalor.coat.handler.ConfigEntryHandler;
|
||||||
import de.siphalor.coat.handler.Message;
|
import de.siphalor.coat.handler.Message;
|
||||||
import lombok.CustomLog;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.literalCo
|
|||||||
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.translatableComponent;
|
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.translatableComponent;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@CustomLog
|
@CommonsLog
|
||||||
public class ConvertingTweedCoatEntryHandler<T extends @Nullable Object, C> implements ConfigEntryHandler<C> {
|
public class ConvertingTweedCoatEntryHandler<T extends @Nullable Object, C> implements ConfigEntryHandler<C> {
|
||||||
private static final String CONVERSION_EXCEPTION_TEXT_KEY = "tweed5_coat_bridge.handler.conversion.exception";
|
private static final String CONVERSION_EXCEPTION_TEXT_KEY = "tweed5_coat_bridge.handler.conversion.exception";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.siphalor.tweed5.coat.bridge.impl;
|
package de.siphalor.tweed5.coat.bridge.impl;
|
||||||
|
|
||||||
import de.siphalor.coat.handler.ConfigEntryHandler;
|
import de.siphalor.coat.handler.ConfigEntryHandler;
|
||||||
|
import de.siphalor.coat.handler.Message;
|
||||||
import de.siphalor.coat.input.CheckBoxConfigInput;
|
import de.siphalor.coat.input.CheckBoxConfigInput;
|
||||||
import de.siphalor.coat.input.ConfigInput;
|
import de.siphalor.coat.input.ConfigInput;
|
||||||
import de.siphalor.coat.input.CycleButtonConfigInput;
|
import de.siphalor.coat.input.CycleButtonConfigInput;
|
||||||
@@ -20,14 +21,24 @@ import de.siphalor.tweed5.coat.bridge.api.mapping.handler.BasicTweedCoatEntryHan
|
|||||||
import de.siphalor.tweed5.coat.bridge.api.mapping.handler.ConvertingTweedCoatEntryHandler;
|
import de.siphalor.tweed5.coat.bridge.api.mapping.handler.ConvertingTweedCoatEntryHandler;
|
||||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import lombok.CustomLog;
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedReadContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReadException;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataToken;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataDecoration;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.resources.language.I18n;
|
import net.minecraft.client.resources.language.I18n;
|
||||||
import net.minecraft.resources.Identifier;
|
import net.minecraft.network.chat.Component;
|
||||||
//- import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import org.jspecify.annotations.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@@ -35,10 +46,9 @@ import java.util.*;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.translatableComponent;
|
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.*;
|
||||||
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.translatableComponentWithFallback;
|
|
||||||
|
|
||||||
@CustomLog
|
@CommonsLog
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class TweedCoatMappersImpl {
|
public class TweedCoatMappersImpl {
|
||||||
public static TweedCoatMapper<Byte> BYTE_TEXT_MAPPER = convertingTextMapper(
|
public static TweedCoatMapper<Byte> BYTE_TEXT_MAPPER = convertingTextMapper(
|
||||||
@@ -83,6 +93,10 @@ public class TweedCoatMappersImpl {
|
|||||||
|
|
||||||
public static TweedCoatMapper<Object> COMPOUND_CATEGORY_MAPPER = new CompoundCategoryMapper<>();
|
public static TweedCoatMapper<Object> COMPOUND_CATEGORY_MAPPER = new CompoundCategoryMapper<>();
|
||||||
|
|
||||||
|
public static <T> TweedCoatMapper<T> serdeTextMapper(Class<T>[] valueClasses) {
|
||||||
|
return new SerdeTextMapper<>(valueClasses);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> TweedCoatMapper<T> convertingTextMapper(
|
public static <T> TweedCoatMapper<T> convertingTextMapper(
|
||||||
Class<T>[] valueClasses,
|
Class<T>[] valueClasses,
|
||||||
Function<T, String> textMapper,
|
Function<T, String> textMapper,
|
||||||
@@ -91,6 +105,240 @@ public class TweedCoatMappersImpl {
|
|||||||
return new ConvertingTextMapper<>(valueClasses, textMapper, textParser);
|
return new ConvertingTextMapper<>(valueClasses, textMapper, textParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class SerdeTextMapper<T> implements TweedCoatMapper<T> {
|
||||||
|
private final Class<T>[] valueClasses;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context) {
|
||||||
|
if (!anyClassMatches(entry.valueClass(), valueClasses)) {
|
||||||
|
return TweedCoatEntryMappingResult.notApplicable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadWriteExtension readWriteExtension = entry.container().extension(ReadWriteExtension.class)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("No ReadWriteExtension registered"));
|
||||||
|
|
||||||
|
return new TweedCoatEntryMappingResult<T, String>() {
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigInput<String> createInput(TweedCoatEntryCreationContext<T> context) {
|
||||||
|
return new TextConfigInput(convertToString(context.currentValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigEntryHandler<String> createHandler(TweedCoatEntryCreationContext<T> context) {
|
||||||
|
if (context.parentSaveHandler() == null) {
|
||||||
|
throw new IllegalArgumentException("No parent save handler provided");
|
||||||
|
}
|
||||||
|
return new ConfigEntryHandler<String>() {
|
||||||
|
@Override
|
||||||
|
public String getDefault() {
|
||||||
|
return convertToString(context.defaultValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Message> getMessages(String text) {
|
||||||
|
try {
|
||||||
|
TweedReadResult<T> readResult = convertFromString(text);
|
||||||
|
if (readResult.hasValue() && !readResult.hasIssues()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
} else if (readResult.hasIssues()) {
|
||||||
|
Message.Level messageLevel = readResult.hasValue()
|
||||||
|
? Message.Level.WARNING
|
||||||
|
: Message.Level.ERROR;
|
||||||
|
return Arrays.stream(readResult.issues()).map(issue ->
|
||||||
|
new Message(messageLevel, literalComponent(issue.exception().getMessage()))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Collections.singletonList(
|
||||||
|
new Message(Message.Level.ERROR, literalComponent(e.getMessage()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(String s) {
|
||||||
|
try {
|
||||||
|
TweedReadResult<T> readResult = convertFromString(s);
|
||||||
|
if (readResult.hasValue()) {
|
||||||
|
if (readResult.hasIssues()) {
|
||||||
|
log.warn(
|
||||||
|
"There were issues understanding value \"" + s + "\":\n - "
|
||||||
|
+ Arrays.stream(readResult.issues())
|
||||||
|
.map(issue -> issue.exception().getMessage())
|
||||||
|
.collect(Collectors.joining("\n - "))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
context.parentSaveHandler().accept(readResult.value());
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Failed to understand value \"" + s + "\":\n - "
|
||||||
|
+ Arrays.stream(readResult.issues())
|
||||||
|
.map(issue -> issue.exception().getMessage())
|
||||||
|
.collect(Collectors.joining("\n - "))
|
||||||
|
);
|
||||||
|
context.parentSaveHandler().accept(context.defaultValue());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to save value \"" + s + "\"", e);
|
||||||
|
context.parentSaveHandler().accept(context.defaultValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component asText(String text) {
|
||||||
|
return literalComponent(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<T> context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertToString(T value) {
|
||||||
|
String[] wrapper = new String[]{""};
|
||||||
|
try {
|
||||||
|
readWriteExtension.write(
|
||||||
|
new TweedDataVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visitNull() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBoolean(boolean value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitByte(byte value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitShort(short value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInt(int value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitLong(long value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitFloat(float value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDouble(double value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitString(String value) {
|
||||||
|
wrapper[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListStart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListEnd() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapStart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEntryKey(String key) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEnd() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDecoration(TweedDataDecoration decoration) {
|
||||||
|
}
|
||||||
|
}, value, entry, readWriteExtension.createReadWriteContextExtensionsData()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to serialize value " + value + " to string", e);
|
||||||
|
}
|
||||||
|
return wrapper[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private TweedReadResult<T> convertFromString(String text) {
|
||||||
|
TweedEntryReader<T, ConfigEntry<T>> reader =
|
||||||
|
readWriteExtension.getDefinedEntryReader(entry);
|
||||||
|
Patchwork readExtData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
|
//noinspection DataFlowIssue
|
||||||
|
return reader.read(
|
||||||
|
new TweedDataReader() {
|
||||||
|
private boolean consumed = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TweedDataToken peekToken() throws TweedDataReadException {
|
||||||
|
if (consumed) {
|
||||||
|
throw new IllegalStateException("Already consumed");
|
||||||
|
}
|
||||||
|
return new TweedDataToken() {
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsString() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readAsString() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TweedDataToken readToken() throws TweedDataReadException {
|
||||||
|
TweedDataToken token = peekToken();
|
||||||
|
consumed = true;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
}, entry, new TweedReadContext() {
|
||||||
|
@Override
|
||||||
|
public ReadWriteExtension readWriteExtension() {
|
||||||
|
return readWriteExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Patchwork extensionsData() {
|
||||||
|
return readExtData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry(
|
||||||
|
TweedDataReader reader,
|
||||||
|
C entry
|
||||||
|
) {
|
||||||
|
return TweedReadResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public static class ConvertingTextMapper<T> implements TweedCoatMapper<T> {
|
public static class ConvertingTextMapper<T> implements TweedCoatMapper<T> {
|
||||||
private final Class<T>[] valueClasses;
|
private final Class<T>[] valueClasses;
|
||||||
@@ -256,20 +504,12 @@ public class TweedCoatMappersImpl {
|
|||||||
CompoundConfigEntry<T> compoundEntry = (CompoundConfigEntry<T>) entry;
|
CompoundConfigEntry<T> compoundEntry = (CompoundConfigEntry<T>) entry;
|
||||||
|
|
||||||
Optional<AttributesExtension> attributesExtension = entry.container().extension(AttributesExtension.class);
|
Optional<AttributesExtension> attributesExtension = entry.container().extension(AttributesExtension.class);
|
||||||
//# if MC_VERSION_NUMBER >= 260100
|
ResourceLocation backgroundTexture = attributesExtension
|
||||||
Identifier backgroundTexture = attributesExtension
|
|
||||||
//# else
|
|
||||||
//- ResourceLocation backgroundTexture = attributesExtension
|
|
||||||
//# end
|
|
||||||
.map(extension -> extension.getAttributeValue(
|
.map(extension -> extension.getAttributeValue(
|
||||||
entry,
|
entry,
|
||||||
TweedCoatAttributes.BACKGROUND_TEXTURE
|
TweedCoatAttributes.BACKGROUND_TEXTURE
|
||||||
))
|
))
|
||||||
//# if MC_VERSION_NUMBER >= 260100
|
.map(ResourceLocation::tryParse)
|
||||||
.map(Identifier::tryParse)
|
|
||||||
//# else
|
|
||||||
//- .map(ResourceLocation::tryParse)
|
|
||||||
//# end
|
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
String translationKey = attributesExtension
|
String translationKey = attributesExtension
|
||||||
.map(extension -> extension.getAttributeValue(
|
.map(extension -> extension.getAttributeValue(
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
package de.siphalor.tweed5.coat.bridge.testmod;
|
package de.siphalor.tweed5.coat.bridge.testmod;
|
||||||
|
|
||||||
import de.siphalor.amecs.priority_key_mappings.api.AmecsPriorityKeyMapping;
|
import de.siphalor.amecs.api.PriorityKeyBinding;
|
||||||
import de.siphalor.coat.screen.ConfigScreen;
|
import de.siphalor.coat.screen.ConfigScreen;
|
||||||
import de.siphalor.tweed5.coat.bridge.api.ConfigScreenCreateParams;
|
import de.siphalor.tweed5.coat.bridge.api.ConfigScreenCreateParams;
|
||||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatBridgeExtension;
|
import de.siphalor.tweed5.coat.bridge.api.TweedCoatBridgeExtension;
|
||||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatMappers;
|
import de.siphalor.tweed5.coat.bridge.api.TweedCoatMappers;
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonSerde;
|
import de.siphalor.tweed5.serde.hjson.HjsonSerde;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
import de.siphalor.tweed5.serde.hjson.HjsonWriter;
|
||||||
import de.siphalor.tweed5.fabric.helper.api.FabricConfigContainerHelper;
|
import de.siphalor.tweed5.fabric.helper.api.FabricConfigContainerHelper;
|
||||||
import de.siphalor.tweed5.weaver.pojo.api.TweedPojoWeaver;
|
import de.siphalor.tweed5.weaver.pojo.api.TweedPojoWeaver;
|
||||||
import lombok.CustomLog;
|
import lombok.CustomLog;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
//- import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper;
|
|
||||||
import net.minecraft.client.KeyMapping;
|
import net.minecraft.client.KeyMapping;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
@@ -55,11 +54,7 @@ public class TweedCoatBridgeTestMod implements ClientModInitializer {
|
|||||||
|
|
||||||
config = configContainerHelper.loadAndUpdateInConfigDirectory(() -> DEFAULT_CONFIG_VALUE);
|
config = configContainerHelper.loadAndUpdateInConfigDirectory(() -> DEFAULT_CONFIG_VALUE);
|
||||||
|
|
||||||
//# if MC_VERSION_NUMBER >= 260100
|
KeyBindingHelper.registerKeyBinding(new ScreenKeyBinding(
|
||||||
KeyMappingHelper.registerKeyMapping(new ScreenKeyBinding(
|
|
||||||
//# else
|
|
||||||
//- KeyBindingHelper.registerKeyBinding(new ScreenKeyBinding(
|
|
||||||
//# end
|
|
||||||
MOD_ID + ".config",
|
MOD_ID + ".config",
|
||||||
GLFW.GLFW_KEY_T,
|
GLFW.GLFW_KEY_T,
|
||||||
//# if MC_VERSION_NUMBER >= 12109
|
//# if MC_VERSION_NUMBER >= 12109
|
||||||
@@ -72,7 +67,7 @@ public class TweedCoatBridgeTestMod implements ClientModInitializer {
|
|||||||
log.info("Current config: " + config);
|
log.info("Current config: " + config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScreenKeyBinding extends KeyMapping implements AmecsPriorityKeyMapping {
|
private class ScreenKeyBinding extends KeyMapping implements PriorityKeyBinding {
|
||||||
//# if MC_VERSION_NUMBER >= 12109
|
//# if MC_VERSION_NUMBER >= 12109
|
||||||
public ScreenKeyBinding(String name, int key, Category category) {
|
public ScreenKeyBinding(String name, int key, Category category) {
|
||||||
//# else
|
//# else
|
||||||
|
|||||||
@@ -15,12 +15,11 @@ dependencies {
|
|||||||
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo-serde-extension")
|
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo-serde-extension")
|
||||||
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo-validation-extension")
|
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo-validation-extension")
|
||||||
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo-presets-extension")
|
compileOnly("de.siphalor.tweed5:tweed5-weaver-pojo-presets-extension")
|
||||||
compileOnly(project(":tweed5-logging", configuration = "minecraftModApiElements"))
|
|
||||||
|
|
||||||
listOf("fabric-networking-api-v1", "fabric-lifecycle-events-v1").forEach {
|
listOf("fabric-networking-api-v1", "fabric-lifecycle-events-v1").forEach {
|
||||||
modTestmodImplementation(fabricApi.module(it, mcLibs.versions.fabric.api.get()))
|
modTestmodImplementation(fabricApi.module(it, mcLibs.versions.fabric.api.get()))
|
||||||
}
|
}
|
||||||
testmodImplementation(project(":tweed5-logging", configuration = "minecraftModElements"))
|
testmodImplementation(project(":tweed5-logging", configuration = "minecraftModApiElements"))
|
||||||
testmodImplementation(project(":tweed5-bundle", configuration = "runtimeElements"))
|
testmodImplementation(project(":tweed5-bundle", configuration = "runtimeElements"))
|
||||||
testmodImplementation(project(":tweed5-bundle-pojo-weaving", configuration = "runtimeElements"))
|
testmodImplementation(project(":tweed5-bundle-pojo-weaving", configuration = "runtimeElements"))
|
||||||
testmodImplementation("de.siphalor.tweed5:tweed5-comment-loader-extension")
|
testmodImplementation("de.siphalor.tweed5:tweed5-comment-loader-extension")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package de.siphalor.tweed5.fabric.helper.api;
|
|||||||
import de.siphalor.tweed5.annotationinheritance.api.AnnotationInheritance;
|
import de.siphalor.tweed5.annotationinheritance.api.AnnotationInheritance;
|
||||||
import de.siphalor.tweed5.attributesextension.api.AttributesExtension;
|
import de.siphalor.tweed5.attributesextension.api.AttributesExtension;
|
||||||
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
|
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ import com.google.gson.stream.JsonReader;
|
|||||||
import de.siphalor.tweed5.commentloaderextension.api.CommentLoaderExtension;
|
import de.siphalor.tweed5.commentloaderextension.api.CommentLoaderExtension;
|
||||||
import de.siphalor.tweed5.commentloaderextension.api.CommentPathProcessor;
|
import de.siphalor.tweed5.commentloaderextension.api.CommentPathProcessor;
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
import de.siphalor.tweed5.data.gson.GsonReader;
|
import de.siphalor.tweed5.serde.gson.GsonReader;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.CustomLog;
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
@CustomLog
|
@CommonsLog
|
||||||
@Builder
|
@Builder
|
||||||
public class FabricConfigCommentLoader {
|
public class FabricConfigCommentLoader {
|
||||||
private final ConfigContainer<?> configContainer;
|
private final ConfigContainer<?> configContainer;
|
||||||
|
|||||||
@@ -2,29 +2,29 @@ package de.siphalor.tweed5.fabric.helper.api;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataWriter;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedSerde;
|
|
||||||
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
import lombok.CustomLog;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadIssue;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataWriter;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedSerde;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@CustomLog
|
@CommonsLog
|
||||||
public class FabricConfigContainerHelper<T extends @Nullable Object> {
|
public class FabricConfigContainerHelper<T extends @Nullable Object> {
|
||||||
@Getter
|
@Getter
|
||||||
private final ConfigContainer<T> configContainer;
|
private final ConfigContainer<T> configContainer;
|
||||||
@@ -84,14 +84,24 @@ public class FabricConfigContainerHelper<T extends @Nullable Object> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (TweedDataReader reader = serde.createReader(new FileInputStream(configFile))) {
|
try (TweedDataReader reader = serde.createReader(Files.newInputStream(configFile.toPath()))) {
|
||||||
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
readContextCustomizer.accept(contextExtensionsData);
|
readContextCustomizer.accept(contextExtensionsData);
|
||||||
PatchInfo patchInfo = patchExtension.collectPatchInfo(contextExtensionsData);
|
PatchInfo patchInfo = patchExtension.collectPatchInfo(contextExtensionsData);
|
||||||
|
|
||||||
T readValue = readWriteExtension.read(reader, configContainer().rootEntry(), contextExtensionsData);
|
TweedReadResult<T> readResult = readWriteExtension.read(reader, configContainer().rootEntry(), contextExtensionsData);
|
||||||
|
if (readResult.hasValue()) {
|
||||||
|
patchExtension.patch(configContainer.rootEntry(), value, readResult.value(), patchInfo);
|
||||||
|
|
||||||
|
if (readResult.hasIssues()) {
|
||||||
|
log.warn(formatIssuesLogMessage(configFile, "issues", readResult.issues()));
|
||||||
|
}
|
||||||
|
} else if (readResult.hasIssues()) {
|
||||||
|
log.error(formatIssuesLogMessage(configFile, "errors", readResult.issues()));
|
||||||
|
} else {
|
||||||
|
log.debug("Reading config file " + configFile.getAbsolutePath() + " yielded empty result");
|
||||||
|
}
|
||||||
|
|
||||||
patchExtension.patch(configContainer.rootEntry(), value, readValue, patchInfo);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed loading config file " + configFile.getAbsolutePath(), e);
|
log.error("Failed loading config file " + configFile.getAbsolutePath(), e);
|
||||||
}
|
}
|
||||||
@@ -108,20 +118,54 @@ public class FabricConfigContainerHelper<T extends @Nullable Object> {
|
|||||||
return defaultValueSupplier.get();
|
return defaultValueSupplier.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
try (TweedDataReader reader = serde.createReader(new FileInputStream(configFile))) {
|
try (TweedDataReader reader = serde.createReader(Files.newInputStream(configFile.toPath()))) {
|
||||||
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
return readWriteExtension.read(reader, configContainer.rootEntry(), contextExtensionsData);
|
TweedReadResult<T> readResult = readWriteExtension.read(
|
||||||
|
reader,
|
||||||
|
configContainer.rootEntry(),
|
||||||
|
contextExtensionsData
|
||||||
|
);
|
||||||
|
if (readResult.hasValue()) {
|
||||||
|
if (readResult.hasIssues()) {
|
||||||
|
log.warn(formatIssuesLogMessage(configFile, "issues", readResult.issues()));
|
||||||
|
}
|
||||||
|
return readResult.value();
|
||||||
|
} else if (readResult.hasIssues()) {
|
||||||
|
log.error(formatIssuesLogMessage(configFile, "errors", readResult.issues()));
|
||||||
|
} else {
|
||||||
|
log.info(
|
||||||
|
"Reading config file "
|
||||||
|
+ configFile.getAbsolutePath()
|
||||||
|
+ " yielded empty result, using default value"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return defaultValueSupplier.get();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed loading config file " + configFile.getAbsolutePath(), e);
|
log.error("Failed loading config file " + configFile.getAbsolutePath(), e);
|
||||||
return defaultValueSupplier.get();
|
return defaultValueSupplier.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String formatIssuesLogMessage(File file, String type, TweedReadIssue[] issues) {
|
||||||
|
String filePath = file.getAbsolutePath();
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder(20 + filePath.length() + type.length() + issues.length * 50);
|
||||||
|
stringBuilder.append("Encountered ");
|
||||||
|
stringBuilder.append(type);
|
||||||
|
stringBuilder.append(" while reading ");
|
||||||
|
stringBuilder.append(filePath);
|
||||||
|
stringBuilder.append(": ");
|
||||||
|
for (TweedReadIssue issue : issues) {
|
||||||
|
stringBuilder.append(" - ").append(issue).append("\n");
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public void writeConfigInConfigDirectory(T configValue) {
|
public void writeConfigInConfigDirectory(T configValue) {
|
||||||
File configFile = getConfigFile();
|
File configFile = getConfigFile();
|
||||||
Path tempConfigDirectory = getOrCreateTempConfigDirectory();
|
Path tempConfigDirectory = getOrCreateTempConfigDirectory();
|
||||||
File tempConfigFile = tempConfigDirectory.resolve(getConfigFileName()).toFile();
|
File tempConfigFile = tempConfigDirectory.resolve(getConfigFileName()).toFile();
|
||||||
try (TweedDataWriter writer = serde.createWriter(new FileOutputStream(tempConfigFile))) {
|
try (TweedDataWriter writer = serde.createWriter(Files.newOutputStream(tempConfigFile.toPath()))) {
|
||||||
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
|
|
||||||
readWriteExtension.write(
|
readWriteExtension.write(
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package de.siphalor.tweed5.fabric.helper.testmod;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonSerde;
|
import de.siphalor.tweed5.serde.hjson.HjsonSerde;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
import de.siphalor.tweed5.serde.hjson.HjsonWriter;
|
||||||
import de.siphalor.tweed5.fabric.helper.api.FabricConfigCommentLoader;
|
import de.siphalor.tweed5.fabric.helper.api.FabricConfigCommentLoader;
|
||||||
import de.siphalor.tweed5.fabric.helper.api.FabricConfigContainerHelper;
|
import de.siphalor.tweed5.fabric.helper.api.FabricConfigContainerHelper;
|
||||||
import de.siphalor.tweed5.weaver.pojo.api.TweedPojoWeaver;
|
import de.siphalor.tweed5.weaver.pojo.api.TweedPojoWeaver;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
org.gradle.jvmargs = -Xmx2G
|
org.gradle.jvmargs = -Xmx2G
|
||||||
|
org.gradle.configuration-cache = true
|
||||||
|
|
||||||
minecraft.version.descriptor = 26.1.0
|
minecraft.version.descriptor = 1.21.10
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
fabric.api.key_mapping = fabric-key-binding-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 11605
|
preprocessor.mc_version_number = 11605
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
[versions]
|
[versions]
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
amecs-api = "1.6.2"
|
||||||
coat = "1.0.0-beta.24"
|
coat = "1.0.0-beta.24"
|
||||||
fabric-api = "0.42.0+1.16"
|
fabric-api = "0.42.0+1.16"
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "8"
|
|
||||||
minecraft = "1.16.5"
|
minecraft = "1.16.5"
|
||||||
parchment = "2022.03.06"
|
parchment = "2022.03.06"
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom-remap", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc1.16.5", version.ref = "amecs-priorityKeyMappings" }
|
amecs-api = { group = "de.siphalor.amecs-api", name = "amecs-api-mc1.16.5", version.ref = "amecs-api" }
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.16.5", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.16.5", version.ref = "coat" }
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
@@ -1,3 +1 @@
|
|||||||
fabric.api.key_mapping = fabric-key-binding-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 11701
|
preprocessor.mc_version_number = 11701
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
[versions]
|
[versions]
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
amecs-api = "1.6.2"
|
||||||
coat = "1.0.0-beta.24"
|
coat = "1.0.0-beta.24"
|
||||||
fabric-api = "0.46.1+1.17"
|
fabric-api = "0.46.1+1.17"
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "16"
|
|
||||||
minecraft = "1.17.1"
|
minecraft = "1.17.1"
|
||||||
parchment = "2021.12.12"
|
parchment = "2021.12.12"
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom-remap", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc1.17.1", version.ref = "amecs-priorityKeyMappings" }
|
amecs-api = { group = "de.siphalor.amecs-api", name = "amecs-api-mc1.17.1", version.ref = "amecs-api" }
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.17.1", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.17.1", version.ref = "coat" }
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
@@ -1,3 +1 @@
|
|||||||
fabric.api.key_mapping = fabric-key-binding-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 11802
|
preprocessor.mc_version_number = 11802
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
[versions]
|
[versions]
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
amecs-api = "1.6.2"
|
||||||
coat = "1.0.0-beta.24"
|
coat = "1.0.0-beta.24"
|
||||||
fabric-api = "0.77.0+1.18.2"
|
fabric-api = "0.77.0+1.18.2"
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "17"
|
|
||||||
minecraft = "1.18.2"
|
minecraft = "1.18.2"
|
||||||
parchment = "2022.11.06"
|
parchment = "2022.11.06"
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom-remap", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc1.18.2", version.ref = "amecs-priorityKeyMappings" }
|
amecs-api = { group = "de.siphalor.amecs-api", name = "amecs-api-mc1.18.2", version.ref = "amecs-api" }
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.18.2", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.18.2", version.ref = "coat" }
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
@@ -1,3 +1 @@
|
|||||||
fabric.api.key_mapping = fabric-key-binding-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 11904
|
preprocessor.mc_version_number = 11904
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
[versions]
|
[versions]
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
amecs-api = "1.6.2"
|
||||||
coat = "1.0.0-beta.24"
|
coat = "1.0.0-beta.24"
|
||||||
fabric-api = "0.87.2+1.19.4"
|
fabric-api = "0.87.2+1.19.4"
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "17"
|
|
||||||
minecraft = "1.19.4"
|
minecraft = "1.19.4"
|
||||||
parchment = "2023.06.26"
|
parchment = "2023.06.26"
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom-remap", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc1.19.4", version.ref = "amecs-priorityKeyMappings" }
|
amecs-api = { group = "de.siphalor.amecs-api", name = "amecs-api-mc1.19.4", version.ref = "amecs-api" }
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.19.4", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.19.4", version.ref = "coat" }
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
@@ -1,3 +1 @@
|
|||||||
fabric.api.key_mapping = fabric-key-binding-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 12006
|
preprocessor.mc_version_number = 12006
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
[versions]
|
[versions]
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
amecs-api = "1.6.2"
|
||||||
coat = "1.0.0-beta.24"
|
coat = "1.0.0-beta.24"
|
||||||
fabric-api = "0.100.8+1.20.6"
|
fabric-api = "0.100.8+1.20.6"
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "17"
|
|
||||||
minecraft = "1.20.6"
|
minecraft = "1.20.6"
|
||||||
parchment = "2024.06.16"
|
parchment = "2024.06.16"
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom-remap", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc1.20.2", version.ref = "amecs-priorityKeyMappings" }
|
amecs-api = { group = "de.siphalor.amecs-api", name = "amecs-api-mc1.20.2", version.ref = "amecs-api" }
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.20.5", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.20.5", version.ref = "coat" }
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
@@ -1,3 +1 @@
|
|||||||
fabric.api.key_mapping = fabric-key-binding-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 12110
|
preprocessor.mc_version_number = 12110
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
[versions]
|
[versions]
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
amecs-api = "1.6.2"
|
||||||
coat = "1.0.0-beta.24"
|
coat = "1.0.0-beta.24"
|
||||||
fabric-api = "0.136.0+1.21.10"
|
fabric-api = "0.136.0+1.21.10"
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "21"
|
|
||||||
minecraft = "1.21.10"
|
minecraft = "1.21.10"
|
||||||
parchment = "2025.10.12"
|
parchment = "2025.10.12"
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom-remap", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc1.21.9", version.ref = "amecs-priorityKeyMappings" }
|
amecs-api = { group = "de.siphalor.amecs-api", name = "amecs-api-mc1.21.9", version.ref = "amecs-api" }
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.21.10", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.21.10", version.ref = "coat" }
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fabric.api.key_mapping = fabric-key-mapping-api-v1
|
|
||||||
|
|
||||||
preprocessor.mc_version_number = 260100
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[versions]
|
|
||||||
amecs-priorityKeyMappings = "1.0.1"
|
|
||||||
coat = "1.1.1"
|
|
||||||
fabric-api = "0.144.3+26.1"
|
|
||||||
fabric-loom = "1.15-SNAPSHOT"
|
|
||||||
java = "25"
|
|
||||||
minecraft = "26.1"
|
|
||||||
|
|
||||||
[plugins]
|
|
||||||
fabric-loom = { id = "net.fabricmc.fabric-loom", version.ref = "fabric-loom" }
|
|
||||||
|
|
||||||
[libraries]
|
|
||||||
amecs-priorityKeyMappings = { group = "de.siphalor.amecs.amecs-priority-key-mappings", name = "amecs-priority-key-mappings-mc26.1.0", version.ref = "amecs-priorityKeyMappings" }
|
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc26.1.0", version.ref = "coat" }
|
|
||||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
[versions]
|
[versions]
|
||||||
fabric-loader = "0.18.5"
|
fabric-loader = "0.17.2"
|
||||||
jcyo = "0.5.1"
|
fabric-loom = "1.11-SNAPSHOT"
|
||||||
smcmtk = "0.1.0"
|
jcyo = "0.6.1"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
jcyo = { id = "de.siphalor.jcyo", version.ref = "jcyo" }
|
jcyo = { id = "de.siphalor.jcyo", version.ref = "jcyo" }
|
||||||
smcmtk = { id = "de.siphalor.minecraft-modding-toolkit.project-plugin", version.ref = "smcmtk" }
|
fabric-loom = { id = "fabric-loom", version.ref = "fabric-loom" }
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
|
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
|
||||||
|
|||||||
@@ -1,7 +1,2 @@
|
|||||||
lombok.accessors.fluent = true
|
lombok.accessors.fluent = true
|
||||||
lombok.addLombokGeneratedAnnotation = true
|
lombok.addLombokGeneratedAnnotation = true
|
||||||
|
|
||||||
# Special configuration, so that the testmod can use the correct shadowed logging classes.
|
|
||||||
lombok.log.apacheCommons.flagUsage=WARNING
|
|
||||||
lombok.log.custom.declaration=de.siphalor.tweed5.shadowed.org.apache.commons.logging.Log de.siphalor.tweed5.shadowed.org.apache.commons.logging.LogFactory.getLog(TYPE)
|
|
||||||
lombok.log.custom.flagUsage=ALLOW
|
|
||||||
4
tweed5-minecraft/lombok.testmod.config
Normal file
4
tweed5-minecraft/lombok.testmod.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Special configuration, so that the testmod can use the correct shadowed logging classes.
|
||||||
|
lombok.log.apacheCommons.flagUsage=WARNING
|
||||||
|
lombok.log.custom.declaration=de.siphalor.tweed5.shadowed.org.apache.commons.logging.Log de.siphalor.tweed5.shadowed.org.apache.commons.logging.LogFactory.getLog(TYPE)
|
||||||
|
lombok.log.custom.flagUsage=ALLOW
|
||||||
13
tweed5-minecraft/networking/build.gradle.kts
Normal file
13
tweed5-minecraft/networking/build.gradle.kts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
plugins {
|
||||||
|
id("de.siphalor.tweed5.local-runtime-only")
|
||||||
|
id("de.siphalor.tweed5.minecraft.mod.cross-version")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
modCompileOnly(fabricApi.module("fabric-networking-api-v1", mcLibs.versions.fabric.api.get()))
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-core")
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-serde-extension")
|
||||||
|
|
||||||
|
testImplementation("de.siphalor.tweed5:tweed5-core")
|
||||||
|
testImplementation("de.siphalor.tweed5:tweed5-serde-extension")
|
||||||
|
}
|
||||||
2
tweed5-minecraft/networking/gradle.properties
Normal file
2
tweed5-minecraft/networking/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module.name = Tweed 5 Netwoking
|
||||||
|
module.description = Minecraft networking support for Tweed 5
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
package de.siphalor.tweed5.minecraft.networking.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReadException;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataToken;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataTokens;
|
||||||
|
import de.siphalor.tweed5.minecraft.networking.impl.ByteBufSerdeConstants;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ByteBufReader implements TweedDataReader {
|
||||||
|
private final ByteBuf buf;
|
||||||
|
private final Deque<Context> contextStack = new ArrayDeque<>();
|
||||||
|
private @Nullable TweedDataToken peek;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TweedDataToken peekToken() throws TweedDataReadException {
|
||||||
|
if (peek != null) return peek;
|
||||||
|
ensureReadable();
|
||||||
|
return (peek = nextToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TweedDataToken readToken() throws TweedDataReadException {
|
||||||
|
if (peek != null) {
|
||||||
|
TweedDataToken token = peek;
|
||||||
|
peek = null;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
ensureReadable();
|
||||||
|
return nextToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureReadable() throws TweedDataReadException {
|
||||||
|
if (!buf.isReadable()) {
|
||||||
|
throw TweedDataReadException.builder().message("Reached end of buffer").build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TweedDataToken nextToken() throws TweedDataReadException {
|
||||||
|
int b = Byte.toUnsignedInt(buf.readByte());
|
||||||
|
switch (b) {
|
||||||
|
case ByteBufSerdeConstants.NULL_VALUE:
|
||||||
|
return wrapTokenForContext(TweedDataTokens.getNull());
|
||||||
|
case ByteBufSerdeConstants.FALSE_VALUE:
|
||||||
|
return wrapTokenForContext(BooleanToken.FALSE);
|
||||||
|
case ByteBufSerdeConstants.TRUE_VALUE:
|
||||||
|
return wrapTokenForContext(BooleanToken.TRUE);
|
||||||
|
case ByteBufSerdeConstants.EMPTY_STRING_VALUE:
|
||||||
|
return wrapTokenForContext(new StringToken(""));
|
||||||
|
case ByteBufSerdeConstants.VARNUM_VARIANT_INT8:
|
||||||
|
return wrapTokenForContext(new ByteToken(buf.readByte()));
|
||||||
|
case ByteBufSerdeConstants.VARNUM_VARIANT_INT16:
|
||||||
|
return wrapTokenForContext(new IntToken(buf.readShort()));
|
||||||
|
case ByteBufSerdeConstants.VARNUM_VARIANT_INT32:
|
||||||
|
return wrapTokenForContext(new IntToken(buf.readInt()));
|
||||||
|
case ByteBufSerdeConstants.VARNUM_VARIANT_INT64: {
|
||||||
|
long value = buf.readLong();
|
||||||
|
if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
|
||||||
|
return wrapTokenForContext(new IntToken((int) value));
|
||||||
|
} else {
|
||||||
|
return wrapTokenForContext(new TweedDataToken() {
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsLong() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readAsLong() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ByteBufSerdeConstants.VARNUM_VARIANT_FLOAT:
|
||||||
|
return wrapTokenForContext(new TweedDataToken() {
|
||||||
|
private final float value = buf.readFloat();
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsFloat() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float readAsFloat() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
case ByteBufSerdeConstants.VARNUM_VARIANT_DOUBLE:
|
||||||
|
return wrapTokenForContext(new TweedDataToken() {
|
||||||
|
private final double value = buf.readDouble();
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsDouble() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double readAsDouble() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
case ByteBufSerdeConstants.COMPLEX_VARIANT_STRING: {
|
||||||
|
int length = buf.readInt();
|
||||||
|
ByteBuf byteBuf = buf.readBytes(length);
|
||||||
|
return wrapTokenForContext(new StringToken(byteBuf.toString(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
case ByteBufSerdeConstants.COMPLEX_VARIANT_LIST: {
|
||||||
|
TweedDataToken token = wrapTokenForContext(TweedDataTokens.getListStart(), false);
|
||||||
|
contextStack.push(Context.LIST);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
case ByteBufSerdeConstants.COMPLEX_VARIANT_MAP: {
|
||||||
|
TweedDataToken token = wrapTokenForContext(TweedDataTokens.getMapStart(), false);
|
||||||
|
contextStack.push(Context.MAP);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
case ByteBufSerdeConstants.COMPLEX_VARIANT_END: {
|
||||||
|
Context context = contextStack.pop();
|
||||||
|
return wrapTokenForContext(
|
||||||
|
context == Context.MAP
|
||||||
|
? TweedDataTokens.getMapEnd()
|
||||||
|
: TweedDataTokens.getListEnd()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
int specialEmbedType = b & ByteBufSerdeConstants.SPECIAL_EMBED_TYPE_MASK;
|
||||||
|
if (specialEmbedType == ByteBufSerdeConstants.UINT6_TYPE) {
|
||||||
|
return wrapTokenForContext(new ByteToken((byte) (b & ByteBufSerdeConstants.SPECIAL_EMBED_VALUE_MASK)));
|
||||||
|
} else if (specialEmbedType == ByteBufSerdeConstants.SMALL_STRING_TYPE) {
|
||||||
|
int length = (b & ByteBufSerdeConstants.SPECIAL_EMBED_VALUE_MASK) + 1;
|
||||||
|
ByteBuf byteBuf = buf.readBytes(length);
|
||||||
|
return wrapTokenForContext(new StringToken(byteBuf.toString(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
throw TweedDataReadException.builder()
|
||||||
|
.message("Unknown type byte value " + Integer.toBinaryString(b))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TweedDataToken wrapTokenForContext(TweedDataToken token) {
|
||||||
|
return wrapTokenForContext(token, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TweedDataToken wrapTokenForContext(TweedDataToken token, boolean isValueEnd) {
|
||||||
|
Context context = contextStack.peek();
|
||||||
|
if (context == null) {
|
||||||
|
return token;
|
||||||
|
} else if (context == Context.LIST) {
|
||||||
|
return TweedDataTokens.asListValue(token);
|
||||||
|
} else if (context == Context.MAP) {
|
||||||
|
contextStack.push(Context.MAP_VALUE);
|
||||||
|
return TweedDataTokens.asMapEntryKey(token);
|
||||||
|
} else {
|
||||||
|
if (isValueEnd) {
|
||||||
|
contextStack.pop();
|
||||||
|
}
|
||||||
|
return TweedDataTokens.asMapEntryValue(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Context {
|
||||||
|
LIST, MAP, MAP_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class BooleanToken implements TweedDataToken {
|
||||||
|
public static final BooleanToken FALSE = new BooleanToken(false);
|
||||||
|
public static final BooleanToken TRUE = new BooleanToken(true);
|
||||||
|
|
||||||
|
private final boolean value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsBoolean() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readAsBoolean() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class ByteToken implements TweedDataToken {
|
||||||
|
private final byte value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsByte() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte readAsByte() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsShort() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short readAsShort() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsInt() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readAsInt() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsLong() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readAsLong() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class IntToken implements TweedDataToken {
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsByte() {
|
||||||
|
return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte readAsByte() {
|
||||||
|
return (byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsShort() {
|
||||||
|
return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short readAsShort() {
|
||||||
|
return (short) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsInt() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readAsInt() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsLong() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readAsLong() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class StringToken implements TweedDataToken {
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadAsString() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readAsString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package de.siphalor.tweed5.minecraft.networking.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataWriter;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataDecoration;
|
||||||
|
import de.siphalor.tweed5.minecraft.networking.impl.ByteBufSerdeConstants;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RawByteBufWriter implements TweedDataWriter {
|
||||||
|
protected final ByteBuf buf;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitNull() {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.NULL_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBoolean(boolean value) {
|
||||||
|
if (value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.TRUE_VALUE);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.FALSE_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitByte(byte value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT8);
|
||||||
|
buf.writeByte(Byte.toUnsignedInt(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitShort(short value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT16);
|
||||||
|
buf.writeShort(Short.toUnsignedInt(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInt(int value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT32);
|
||||||
|
buf.writeInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitLong(long value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT64);
|
||||||
|
buf.writeLong(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitFloat(float value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_FLOAT);
|
||||||
|
buf.writeFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDouble(double value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_DOUBLE);
|
||||||
|
buf.writeDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitString(String value) {
|
||||||
|
writeStringBytes(value.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeStringBytes(byte[] bytes) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.COMPLEX_VARIANT_STRING);
|
||||||
|
buf.writeInt(bytes.length);
|
||||||
|
buf.writeBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListStart() {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.COMPLEX_VARIANT_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListEnd() {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.COMPLEX_VARIANT_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapStart() {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.COMPLEX_VARIANT_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEntryKey(String key) {
|
||||||
|
visitString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEnd() {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.COMPLEX_VARIANT_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDecoration(TweedDataDecoration decoration) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package de.siphalor.tweed5.minecraft.networking.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.minecraft.networking.impl.ByteBufSerdeConstants;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class SlightlyCompressedByteBufWriter extends RawByteBufWriter {
|
||||||
|
public SlightlyCompressedByteBufWriter(ByteBuf buf) {
|
||||||
|
super(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitByte(byte value) {
|
||||||
|
int v = Byte.toUnsignedInt(value);
|
||||||
|
if (v <= 0b11_1111) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.UINT6_TYPE + (v & 0b11_1111));
|
||||||
|
} else {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT8);
|
||||||
|
buf.writeByte(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitShort(short value) {
|
||||||
|
int v = Short.toUnsignedInt(value);
|
||||||
|
if (v <= 0b11_1111) {
|
||||||
|
writeUint6(v);
|
||||||
|
} else if (v <= 0b0111_1111) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT8);
|
||||||
|
buf.writeByte(v & 0b0111_1111);
|
||||||
|
} else if (v >= 0b1000_0000_0000_0000 && v <= 0b1000_0000_0111_1111) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT8);
|
||||||
|
buf.writeByte(v & 0b0111_1111 | 0b1000_0000);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT16);
|
||||||
|
buf.writeShort(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInt(int value) {
|
||||||
|
if (value >= 0 && value <= 0b11_1111) {
|
||||||
|
writeUint6(value);
|
||||||
|
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT8);
|
||||||
|
if (value < 0) value |= 0b1000_0000;
|
||||||
|
buf.writeByte(value);
|
||||||
|
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT16);
|
||||||
|
if (value < 0) value |= 0b1000_0000_0000_0000;
|
||||||
|
buf.writeShort(value);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT32);
|
||||||
|
buf.writeInt(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitLong(long value) {
|
||||||
|
if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
|
||||||
|
visitInt((int) value);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.VARNUM_VARIANT_INT64);
|
||||||
|
buf.writeLong(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeUint6(int value) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.UINT6_TYPE | (value & 0b11_1111));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitString(String value) {
|
||||||
|
if (value.isEmpty()) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.EMPTY_STRING_VALUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
if (bytes.length <= 0b100_0000) {
|
||||||
|
buf.writeByte(ByteBufSerdeConstants.SMALL_STRING_TYPE | (bytes.length - 1));
|
||||||
|
buf.writeBytes(bytes);
|
||||||
|
} else {
|
||||||
|
writeStringBytes(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@NullMarked
|
@NullMarked
|
||||||
package de.siphalor.tweed5.dataapi.api.decoration;
|
package de.siphalor.tweed5.minecraft.networking.api;
|
||||||
|
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package de.siphalor.tweed5.minecraft.networking.impl;
|
||||||
|
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
|
||||||
|
public class ByteBufSerdeConstants {
|
||||||
|
public static final int TYPE_MASK = 0b1111_0000;
|
||||||
|
public static final int VALUE_MASK = 0b0000_1111;
|
||||||
|
|
||||||
|
public static final int CONST_TYPE = 0;
|
||||||
|
public static final int NULL_VALUE = 0;
|
||||||
|
public static final int FALSE_VALUE = 1;
|
||||||
|
public static final int TRUE_VALUE = 0b10;
|
||||||
|
public static final int EMPTY_STRING_VALUE = 0b11;
|
||||||
|
|
||||||
|
public static final int VARNUM_TYPE = 0b0001_0000;
|
||||||
|
public static final int VARNUM_VARIANT_INT8 = VARNUM_TYPE;
|
||||||
|
public static final int VARNUM_VARIANT_INT16 = VARNUM_TYPE | 0b0001;
|
||||||
|
public static final int VARNUM_VARIANT_INT32 = VARNUM_TYPE | 0b0010;
|
||||||
|
public static final int VARNUM_VARIANT_INT64 = VARNUM_TYPE | 0b0011;
|
||||||
|
public static final int VARNUM_VARIANT_FLOAT = VARNUM_TYPE | 0b1000;
|
||||||
|
public static final int VARNUM_VARIANT_DOUBLE = VARNUM_TYPE | 0b1001;
|
||||||
|
|
||||||
|
public static final int COMPLEX_TYPE = 0b0010_0000;
|
||||||
|
public static final int COMPLEX_VARIANT_STRING = COMPLEX_TYPE;
|
||||||
|
public static final int COMPLEX_VARIANT_LIST = COMPLEX_TYPE | 0b0001;
|
||||||
|
public static final int COMPLEX_VARIANT_MAP = COMPLEX_TYPE | 0b0010;
|
||||||
|
public static final int COMPLEX_VARIANT_END = COMPLEX_TYPE | 0b1111;
|
||||||
|
|
||||||
|
// 0b01xx_xxxx is reserved for future use
|
||||||
|
|
||||||
|
public static final int SPECIAL_EMBED_TYPE_MASK = 0b1100_0000;
|
||||||
|
public static final int SPECIAL_EMBED_VALUE_MASK = 0b0011_1111;
|
||||||
|
public static final int UINT6_TYPE = 0b1000_0000;
|
||||||
|
public static final int SMALL_STRING_TYPE = 0b1100_0000;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.minecraft.networking.impl;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
package de.siphalor.tweed5.minecraft.network.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReadException;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataToken;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataWriter;
|
||||||
|
import de.siphalor.tweed5.minecraft.networking.api.ByteBufReader;
|
||||||
|
import de.siphalor.tweed5.minecraft.networking.api.RawByteBufWriter;
|
||||||
|
import de.siphalor.tweed5.minecraft.networking.api.SlightlyCompressedByteBufWriter;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.argumentSet;
|
||||||
|
|
||||||
|
public class ByteBufReaderWriterTest {
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("testParams")
|
||||||
|
@SneakyThrows
|
||||||
|
void test(Function<ByteBuf, TweedDataWriter> writerConstructor) {
|
||||||
|
ByteBuf buffer = Unpooled.buffer();
|
||||||
|
|
||||||
|
try (TweedDataWriter writer = writerConstructor.apply(buffer)) {
|
||||||
|
writer.visitMapStart();
|
||||||
|
writer.visitMapEntryKey("first");
|
||||||
|
writer.visitNull();
|
||||||
|
writer.visitMapEntryKey("kind-of a_weird/key!");
|
||||||
|
writer.visitListStart();
|
||||||
|
writer.visitByte((byte) 12);
|
||||||
|
writer.visitByte((byte) -12);
|
||||||
|
writer.visitByte((byte) 123);
|
||||||
|
writer.visitListEnd();
|
||||||
|
writer.visitMapEntryKey("nums");
|
||||||
|
writer.visitListStart();
|
||||||
|
writer.visitShort((short) 1234);
|
||||||
|
writer.visitInt(4321);
|
||||||
|
writer.visitInt(Integer.MAX_VALUE);
|
||||||
|
writer.visitLong(Long.MAX_VALUE);
|
||||||
|
writer.visitFloat(1234.5678f);
|
||||||
|
writer.visitDouble(1234.5678);
|
||||||
|
writer.visitListEnd();
|
||||||
|
writer.visitMapEntryKey("other");
|
||||||
|
writer.visitString("Hello World!");
|
||||||
|
writer.visitMapEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Buffer size is: " + buffer.writerIndex());
|
||||||
|
assertThat(buffer.readerIndex()).isZero();
|
||||||
|
|
||||||
|
try (ByteBufReader reader = new ByteBufReader(buffer)) {
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isMapStart).isEqualTo(true);
|
||||||
|
assertNextMapKey(reader.readToken(), "first");
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isNull).isEqualTo(true);
|
||||||
|
assertNextMapKey(reader.readToken(), "kind-of a_weird/key!");
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isListStart).isEqualTo(true);
|
||||||
|
assertByteToken(reader.readToken(), (byte) 12);
|
||||||
|
assertByteToken(reader.readToken(), (byte) -12);
|
||||||
|
assertByteToken(reader.readToken(), (byte) 123);
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isListEnd).isEqualTo(true);
|
||||||
|
assertNextMapKey(reader.readToken(), "nums");
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isListStart).isEqualTo(true);
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsByte()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsShort()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsShort()).isEqualTo((short) 1234),
|
||||||
|
token -> assertThat(token.canReadAsInt()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsInt()).isEqualTo(1234),
|
||||||
|
token -> assertThat(token.canReadAsLong()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsLong()).isEqualTo(1234L)
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsByte()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsShort()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsShort()).isEqualTo((short) 4321),
|
||||||
|
token -> assertThat(token.canReadAsInt()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsInt()).isEqualTo(4321),
|
||||||
|
token -> assertThat(token.canReadAsLong()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsLong()).isEqualTo(4321L)
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsByte()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsShort()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsInt()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsInt()).isEqualTo(Integer.MAX_VALUE),
|
||||||
|
token -> assertThat(token.canReadAsLong()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsLong()).isEqualTo(Integer.MAX_VALUE)
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsByte()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsShort()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsInt()).isFalse(),
|
||||||
|
token -> assertThat(token.canReadAsLong()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsLong()).isEqualTo(Long.MAX_VALUE)
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsFloat()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsFloat()).isEqualTo(1234.5678f)
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsDouble()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsDouble()).isEqualTo(1234.5678)
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isListEnd).isEqualTo(true);
|
||||||
|
assertNextMapKey(reader.readToken(), "other");
|
||||||
|
assertThat(reader.readToken()).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsString()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsString()).isEqualTo("Hello World!"),
|
||||||
|
token -> assertThat(token.isMapEntryValue()).isTrue()
|
||||||
|
);
|
||||||
|
assertThat(reader.readToken()).extracting(TweedDataToken::isMapEnd).isEqualTo(true);
|
||||||
|
assertThatThrownBy(reader::readToken).isInstanceOf(TweedDataReadException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNextMapKey(TweedDataToken dataToken, String key) {
|
||||||
|
assertThat(dataToken).satisfies(
|
||||||
|
token -> assertThat(token.isMapEntryKey()).isTrue(),
|
||||||
|
token -> assertThat(token.canReadAsString()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsString()).isEqualTo(key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertByteToken(TweedDataToken dataToken, byte value) {
|
||||||
|
assertThat(dataToken).satisfies(
|
||||||
|
token -> assertThat(token.canReadAsByte()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsByte()).isEqualTo(value),
|
||||||
|
token -> assertThat(token.canReadAsShort()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsShort()).isEqualTo(value),
|
||||||
|
token -> assertThat(token.canReadAsInt()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsInt()).isEqualTo(value),
|
||||||
|
token -> assertThat(token.canReadAsLong()).isTrue(),
|
||||||
|
token -> assertThat(token.readAsLong()).isEqualTo(value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Arguments> testParams() {
|
||||||
|
return Stream.of(
|
||||||
|
argumentSet(
|
||||||
|
RawByteBufWriter.class.getSimpleName(),
|
||||||
|
((Function<ByteBuf, ?>) RawByteBufWriter::new)
|
||||||
|
),
|
||||||
|
argumentSet(
|
||||||
|
SlightlyCompressedByteBufWriter.class.getSimpleName(),
|
||||||
|
((Function<ByteBuf, ?>) SlightlyCompressedByteBufWriter::new)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
create("mcLibs") {
|
create("mcLibs") {
|
||||||
val mcVersionDescriptor = providers.gradleProperty("minecraft.version.descriptor").get()
|
val mcVersionDescriptor = providers.gradleProperty("minecraft.version.descriptor").get()
|
||||||
from(files("gradle/mc-$mcVersionDescriptor/mc.versions.toml"))
|
from(files("gradle/mc-$mcVersionDescriptor/mcLibs.versions.toml"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,7 @@ includeNormalModule("bundle-pojo-weaving")
|
|||||||
includeNormalModule("coat-bridge")
|
includeNormalModule("coat-bridge")
|
||||||
includeNormalModule("fabric-helper")
|
includeNormalModule("fabric-helper")
|
||||||
includeNormalModule("logging")
|
includeNormalModule("logging")
|
||||||
|
includeNormalModule("networking")
|
||||||
|
|
||||||
fun includeNormalModule(name: String) {
|
fun includeNormalModule(name: String) {
|
||||||
includeAs("tweed5-$name", name)
|
includeAs("tweed5-$name", name)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":tweed5-core"))
|
implementation(project(":tweed5-core"))
|
||||||
compileOnly(project(":tweed5-serde-extension"))
|
compileOnly(project(":tweed5-serde-extension"))
|
||||||
|
testImplementation(project(":tweed5-default-extensions"))
|
||||||
testImplementation(project(":tweed5-serde-extension"))
|
testImplementation(project(":tweed5-serde-extension"))
|
||||||
testImplementation(project(":tweed5-serde-hjson"))
|
testImplementation(project(":tweed5-serde-hjson"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,17 +9,20 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
|
||||||
import de.siphalor.tweed5.data.extension.impl.TweedEntryReaderWriterImpls;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.*;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
|
||||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryWriter;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReaderMiddlewareContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.WriterMiddlewareContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
|
import de.siphalor.tweed5.serde.extension.impl.TweedEntryReaderWriterImpls;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.DelegatingTweedDataWriter;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataUnsupportedValueException;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataDecoration;
|
||||||
import de.siphalor.tweed5.utils.api.UniqueSymbol;
|
import de.siphalor.tweed5.utils.api.UniqueSymbol;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -38,6 +41,8 @@ public class AttributesReadWriteFilterExtensionImpl
|
|||||||
private static final Set<String> MIDDLEWARES_MUST_COME_AFTER = Collections.emptySet();
|
private static final Set<String> MIDDLEWARES_MUST_COME_AFTER = Collections.emptySet();
|
||||||
private static final UniqueSymbol TWEED_DATA_NOTHING_VALUE = new UniqueSymbol("nothing (skip value)");
|
private static final UniqueSymbol TWEED_DATA_NOTHING_VALUE = new UniqueSymbol("nothing (skip value)");
|
||||||
|
|
||||||
|
public static final Object NOOP_MARKER = new Object();
|
||||||
|
|
||||||
private final ConfigContainer<?> configContainer;
|
private final ConfigContainer<?> configContainer;
|
||||||
private @Nullable AttributesExtension attributesExtension;
|
private @Nullable AttributesExtension attributesExtension;
|
||||||
private final Set<String> filterableAttributes = new HashSet<>();
|
private final Set<String> filterableAttributes = new HashSet<>();
|
||||||
@@ -155,7 +160,7 @@ public class AttributesReadWriteFilterExtensionImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReaderMiddleware implements Middleware<TweedEntryReader<?, ?>> {
|
private class ReaderMiddleware implements Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext> {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
@@ -172,32 +177,28 @@ public class AttributesReadWriteFilterExtensionImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
|
||||||
assert readWriteContextDataAccess != null;
|
assert readWriteContextDataAccess != null;
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryReader<Object, ConfigEntry<Object>> innerCasted
|
TweedEntryReader<Object, ConfigEntry<Object>> innerCasted
|
||||||
= (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
= (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
|
|
||||||
return new TweedEntryReader<@Nullable Object, ConfigEntry<Object>>() {
|
return (TweedEntryReader<Object, ConfigEntry<Object>>) (reader, entry, readContext) -> {
|
||||||
@Override
|
ReadWriteContextCustomData contextData = readContext.extensionsData().get(readWriteContextDataAccess);
|
||||||
public @Nullable Object read(
|
if (contextData == null) {
|
||||||
TweedDataReader reader,
|
contextData = new ReadWriteContextCustomData();
|
||||||
ConfigEntry<Object> entry,
|
readContext.extensionsData().set(readWriteContextDataAccess, contextData);
|
||||||
TweedReadContext context
|
|
||||||
) throws TweedEntryReadException {
|
|
||||||
ReadWriteContextCustomData contextData = context.extensionsData().get(readWriteContextDataAccess);
|
|
||||||
if (contextData == null || doFiltersMatch(entry, contextData)) {
|
|
||||||
return innerCasted.read(reader, entry, context);
|
|
||||||
}
|
|
||||||
TweedEntryReaderWriterImpls.NOOP_READER_WRITER.read(reader, entry, context);
|
|
||||||
// TODO: this should result in a noop instead of a null value
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
if (!doFiltersMatch(entry, contextData)) {
|
||||||
|
TweedEntryReaderWriterImpls.NOOP_READER_WRITER.read(reader, entry, readContext);
|
||||||
|
return TweedReadResult.empty();
|
||||||
|
}
|
||||||
|
return innerCasted.read(reader, entry, readContext);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WriterMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
|
private class WriterMiddleware implements Middleware<TweedEntryWriter<?, ?>, WriterMiddlewareContext> {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
@@ -214,18 +215,18 @@ public class AttributesReadWriteFilterExtensionImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
|
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner, WriterMiddlewareContext context) {
|
||||||
assert readWriteContextDataAccess != null;
|
assert readWriteContextDataAccess != null;
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted
|
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted
|
||||||
= (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
= (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
|
|
||||||
return (TweedEntryWriter<@Nullable Object, @NonNull ConfigEntry<@Nullable Object>>)
|
return (TweedEntryWriter<@Nullable Object, @NonNull ConfigEntry<@Nullable Object>>)
|
||||||
(writer, value, entry, context) -> {
|
(writer, value, entry, writeContext) -> {
|
||||||
ReadWriteContextCustomData contextData = context.extensionsData()
|
ReadWriteContextCustomData contextData = writeContext.extensionsData()
|
||||||
.get(readWriteContextDataAccess);
|
.get(readWriteContextDataAccess);
|
||||||
if (contextData == null || contextData.attributeFilters().isEmpty()) {
|
if (contextData == null || contextData.attributeFilters().isEmpty()) {
|
||||||
innerCasted.write(writer, value, entry, context);
|
innerCasted.write(writer, value, entry, writeContext);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +236,7 @@ public class AttributesReadWriteFilterExtensionImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (doFiltersMatch(entry, contextData)) {
|
if (doFiltersMatch(entry, contextData)) {
|
||||||
innerCasted.write(writer, value, entry, context);
|
innerCasted.write(writer, value, entry, writeContext);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
writer.visitValue(TWEED_DATA_NOTHING_VALUE);
|
writer.visitValue(TWEED_DATA_NOTHING_VALUE);
|
||||||
@@ -380,5 +381,6 @@ public class AttributesReadWriteFilterExtensionImpl
|
|||||||
private static class ReadWriteContextCustomData {
|
private static class ReadWriteContextCustomData {
|
||||||
private final Map<String, Set<String>> attributeFilters = new HashMap<>();
|
private final Map<String, Set<String>> attributeFilters = new HashMap<>();
|
||||||
private boolean writerInstalled;
|
private boolean writerInstalled;
|
||||||
|
private boolean noopHandlerInstalled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
import de.siphalor.tweed5.serde.hjson.HjsonLexer;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
import de.siphalor.tweed5.serde.hjson.HjsonReader;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonWriter;
|
||||||
import org.jspecify.annotations.NullUnmarked;
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -26,9 +27,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static de.siphalor.tweed5.attributesextension.api.AttributesExtension.attribute;
|
import static de.siphalor.tweed5.attributesextension.api.AttributesExtension.attribute;
|
||||||
import static de.siphalor.tweed5.attributesextension.api.AttributesExtension.attributeDefault;
|
import static de.siphalor.tweed5.attributesextension.api.AttributesExtension.attributeDefault;
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.*;
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.*;
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.compoundReaderWriter;
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.compoundReaderWriter;
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.stringReaderWriter;
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.stringReaderWriter;
|
||||||
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -164,19 +165,21 @@ class AttributesReadWriteFilterExtensionImplTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")));
|
""")));
|
||||||
Map<String, Object> readValue = configContainer.rootEntry().call(read(
|
TweedReadResult<Map<String, Object>> readResult = configContainer.rootEntry().call(read(
|
||||||
reader,
|
reader,
|
||||||
patchwork -> attributesReadWriteFilterExtension.addFilter(patchwork, "type", "a")
|
patchwork -> attributesReadWriteFilterExtension.addFilter(patchwork, "type", "a")
|
||||||
));
|
));
|
||||||
|
|
||||||
assertThat(readValue)
|
assertThat(readResult)
|
||||||
|
.extracting(TweedReadResult::value)
|
||||||
|
.asInstanceOf(map(String.class, Object.class))
|
||||||
.containsEntry("first", "1st")
|
.containsEntry("first", "1st")
|
||||||
.containsEntry("second", null)
|
.doesNotContainKey("second")
|
||||||
.hasEntrySatisfying(
|
.hasEntrySatisfying(
|
||||||
"nested", nested -> assertThat(nested)
|
"nested", nested -> assertThat(nested)
|
||||||
.asInstanceOf(map(String.class, Object.class))
|
.asInstanceOf(map(String.class, Object.class))
|
||||||
.containsEntry("first", "n 1st")
|
.containsEntry("first", "n 1st")
|
||||||
.containsEntry("second", null)
|
.doesNotContainKey("second")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package de.siphalor.tweed5.attributesextension.impl.serde.filter;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
||||||
|
import de.siphalor.tweed5.attributesextension.impl.AttributesExtensionImpl;
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonLexer;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonReader;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static de.siphalor.tweed5.attributesextension.api.AttributesExtension.attribute;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.entryReaderWriter;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.compoundReaderWriter;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.stringReaderWriter;
|
||||||
|
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
||||||
|
import static java.util.Map.entry;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.InstanceOfAssertFactories.map;
|
||||||
|
|
||||||
|
public class AttributesReadWriteFilterExtensionImplWithPatchInfoTest {
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
void testOrder() {
|
||||||
|
ConfigContainer<Map<String, Object>> configContainer = new DefaultConfigContainer<>();
|
||||||
|
configContainer.registerExtension(AttributesReadWriteFilterExtensionImpl.class);
|
||||||
|
configContainer.registerExtension(ReadWriteExtension.class);
|
||||||
|
configContainer.registerExtension(AttributesExtensionImpl.class);
|
||||||
|
configContainer.registerExtension(PatchExtension.class);
|
||||||
|
configContainer.finishExtensionSetup();
|
||||||
|
|
||||||
|
var firstEntry = new SimpleConfigEntryImpl<>(configContainer, String.class)
|
||||||
|
.apply(entryReaderWriter(stringReaderWriter()))
|
||||||
|
.apply(attribute("type", "a"));
|
||||||
|
var secondEntry = new SimpleConfigEntryImpl<>(configContainer, String.class)
|
||||||
|
.apply(entryReaderWriter(stringReaderWriter()));
|
||||||
|
var rootEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>) (Class<?>) Map.class,
|
||||||
|
HashMap::new,
|
||||||
|
sequencedMap(List.of(entry("first", firstEntry), entry("second", secondEntry)))
|
||||||
|
)
|
||||||
|
.apply(entryReaderWriter(compoundReaderWriter()));
|
||||||
|
|
||||||
|
configContainer.attachTree(rootEntry);
|
||||||
|
|
||||||
|
var readWriteFilterExtension = configContainer.extension(AttributesReadWriteFilterExtension.class).orElseThrow();
|
||||||
|
readWriteFilterExtension.markAttributeForFiltering("type");
|
||||||
|
|
||||||
|
configContainer.initialize();
|
||||||
|
|
||||||
|
var readWriteExtension = configContainer.extension(ReadWriteExtension.class).orElseThrow();
|
||||||
|
var patchExtension = configContainer.extension(PatchExtension.class).orElseThrow();
|
||||||
|
var filterExtension = configContainer.extension(AttributesReadWriteFilterExtension.class).orElseThrow();
|
||||||
|
|
||||||
|
var readExtData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
|
var patchInfo = patchExtension.collectPatchInfo(readExtData);
|
||||||
|
filterExtension.addFilter(readExtData, "type", "a");
|
||||||
|
|
||||||
|
var readResult = readWriteExtension.read(
|
||||||
|
new HjsonReader(new HjsonLexer(new StringReader("""
|
||||||
|
{
|
||||||
|
"first": "FIRST",
|
||||||
|
"second": "SECOND"
|
||||||
|
}
|
||||||
|
"""))),
|
||||||
|
configContainer.rootEntry(),
|
||||||
|
readExtData
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(readResult)
|
||||||
|
.extracting(TweedReadResult::value)
|
||||||
|
.asInstanceOf(map(String.class, Object.class))
|
||||||
|
.isEqualTo(Map.of("first", "FIRST"));
|
||||||
|
assertThat(patchInfo.containsEntry(firstEntry)).isTrue();
|
||||||
|
assertThat(patchInfo.containsEntry(secondEntry)).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package de.siphalor.tweed5.commentloaderextension.api;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.commentloaderextension.impl.CommentLoaderExtensionImpl;
|
import de.siphalor.tweed5.commentloaderextension.impl.CommentLoaderExtensionImpl;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
|
|
||||||
public interface CommentLoaderExtension extends TweedExtension {
|
public interface CommentLoaderExtension extends TweedExtension {
|
||||||
Class<? extends CommentLoaderExtension> DEFAULT = CommentLoaderExtensionImpl.class;
|
Class<? extends CommentLoaderExtension> DEFAULT = CommentLoaderExtensionImpl.class;
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
|||||||
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.dataapi.api.IntuitiveVisitingTweedDataReader;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducerMiddlewareContext;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
|
import de.siphalor.tweed5.serde_api.api.IntuitiveVisitingTweedDataReader;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReadException;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataDecoration;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||||
@@ -44,8 +45,8 @@ public class CommentLoaderExtensionImpl implements CommentLoaderExtension, Comme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Middleware<CommentProducer> commentMiddleware() {
|
public Middleware<CommentProducer, CommentProducerMiddlewareContext> commentMiddleware() {
|
||||||
return new Middleware<CommentProducer>() {
|
return new Middleware<CommentProducer, CommentProducerMiddlewareContext>() {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
@@ -62,7 +63,10 @@ public class CommentLoaderExtensionImpl implements CommentLoaderExtension, Comme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommentProducer process(CommentProducer inner) {
|
public CommentProducer process(CommentProducer inner, CommentProducerMiddlewareContext context) {
|
||||||
|
if (context.entry().extensionsData().get(loadedCommentAccess) == null) {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
return entry -> {
|
return entry -> {
|
||||||
String loadedComment = entry.extensionsData().get(loadedCommentAccess);
|
String loadedComment = entry.extensionsData().get(loadedCommentAccess);
|
||||||
String innerComment = inner.createComment(entry);
|
String innerComment = inner.createComment(entry);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
|||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.data.gson.GsonReader;
|
import de.siphalor.tweed5.serde.gson.GsonReader;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.siphalor.tweed5.core.api.entry;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface AddressableStructuredConfigEntry<T> extends StructuredConfigEntry<T> {
|
||||||
|
@Override
|
||||||
|
default AddressableStructuredConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
||||||
|
StructuredConfigEntry.super.apply(function);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (E item : value) {
|
for (E item : value) {
|
||||||
String indexString = Integer.toString(index);
|
SubEntryKey subEntryKey = SubEntryKey.structured("element", Integer.toString(index));
|
||||||
if (visitor.enterStructuredSubEntry("element", indexString)) {
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
elementEntry().visitInOrder(visitor, item);
|
elementEntry().visitInOrder(visitor, item);
|
||||||
visitor.leaveStructuredSubEntry("element", indexString);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,13 @@ import de.siphalor.tweed5.core.api.Arity;
|
|||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public interface CompoundConfigEntry<T> extends StructuredConfigEntry<T> {
|
public interface CompoundConfigEntry<T> extends MutableStructuredConfigEntry<T> {
|
||||||
@Override
|
@Override
|
||||||
default CompoundConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
default CompoundConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
||||||
StructuredConfigEntry.super.apply(function);
|
MutableStructuredConfigEntry.super.apply(function);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
<V> void set(T compoundValue, String key, V value);
|
|
||||||
<V> V get(T compoundValue, String key);
|
|
||||||
|
|
||||||
T instantiateCompoundValue();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void visitInOrder(ConfigEntryVisitor visitor) {
|
default void visitInOrder(ConfigEntryVisitor visitor) {
|
||||||
if (visitor.enterStructuredEntry(this)) {
|
if (visitor.enterStructuredEntry(this)) {
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ package de.siphalor.tweed5.core.api.entry;
|
|||||||
public interface ConfigEntryValueVisitor {
|
public interface ConfigEntryValueVisitor {
|
||||||
<T> void visitEntry(ConfigEntry<T> entry, T value);
|
<T> void visitEntry(ConfigEntry<T> entry, T value);
|
||||||
|
|
||||||
default <T> boolean enterStructuredEntry(ConfigEntry<T> entry, T value) {
|
default <T> boolean enterStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
visitEntry(entry, value);
|
visitEntry(entry, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
default boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
default void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
default void leaveSubEntry(SubEntryKey subEntryKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default <T> void leaveStructuredEntry(ConfigEntry<T> entry, T value) {
|
default <T> void leaveStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package de.siphalor.tweed5.core.api.entry;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface MutableStructuredConfigEntry<T> extends AddressableStructuredConfigEntry<T> {
|
||||||
|
@Override
|
||||||
|
default AddressableStructuredConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
||||||
|
AddressableStructuredConfigEntry.super.apply(function);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull T instantiateValue();
|
||||||
|
void set(T value, String dataKey, Object subValue);
|
||||||
|
}
|
||||||
@@ -5,12 +5,12 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public interface NullableConfigEntry<T extends @Nullable Object> extends StructuredConfigEntry<T> {
|
public interface NullableConfigEntry<T extends @Nullable Object> extends AddressableStructuredConfigEntry<T> {
|
||||||
String NON_NULL_KEY = ":nonNull";
|
String NON_NULL_KEY = ":nonNull";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default NullableConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
default NullableConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
||||||
StructuredConfigEntry.super.apply(function);
|
AddressableStructuredConfigEntry.super.apply(function);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,11 +8,11 @@ import java.util.function.Function;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class DefaultMiddlewareContainer<M> implements MiddlewareContainer<M> {
|
public class DefaultMiddlewareContainer<M, C> implements MiddlewareContainer<M, C> {
|
||||||
private static final String CONTAINER_ID = "";
|
private static final String CONTAINER_ID = "";
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private List<Middleware<M>> middlewares = new ArrayList<>();
|
private List<Middleware<M, C>> middlewares = new ArrayList<>();
|
||||||
private final Set<String> middlewareIds = new HashSet<>();
|
private final Set<String> middlewareIds = new HashSet<>();
|
||||||
private boolean sealed = false;
|
private boolean sealed = false;
|
||||||
|
|
||||||
@@ -22,10 +22,10 @@ public class DefaultMiddlewareContainer<M> implements MiddlewareContainer<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerAll(Collection<Middleware<M>> middlewares) {
|
public void registerAll(Collection<Middleware<M, C>> middlewares) {
|
||||||
requireUnsealed();
|
requireUnsealed();
|
||||||
|
|
||||||
for (Middleware<M> middleware : middlewares) {
|
for (Middleware<M, C> middleware : middlewares) {
|
||||||
if (middleware.id().isEmpty()) {
|
if (middleware.id().isEmpty()) {
|
||||||
throw new IllegalArgumentException("Middleware id cannot be empty");
|
throw new IllegalArgumentException("Middleware id cannot be empty");
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ public class DefaultMiddlewareContainer<M> implements MiddlewareContainer<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void register(Middleware<M> middleware) {
|
public void register(Middleware<M, C> middleware) {
|
||||||
requireUnsealed();
|
requireUnsealed();
|
||||||
|
|
||||||
if (middleware.id().isEmpty()) {
|
if (middleware.id().isEmpty()) {
|
||||||
@@ -76,7 +76,7 @@ public class DefaultMiddlewareContainer<M> implements MiddlewareContainer<M> {
|
|||||||
|
|
||||||
AcyclicGraphSorter sorter = new AcyclicGraphSorter(allMentionedMiddlewareIds.length);
|
AcyclicGraphSorter sorter = new AcyclicGraphSorter(allMentionedMiddlewareIds.length);
|
||||||
|
|
||||||
for (Middleware<M> middleware : middlewares) {
|
for (Middleware<M, C> middleware : middlewares) {
|
||||||
Integer currentIndex = indecesByMiddlewareId.get(middleware.id());
|
Integer currentIndex = indecesByMiddlewareId.get(middleware.id());
|
||||||
|
|
||||||
middleware.mustComeAfter().stream()
|
middleware.mustComeAfter().stream()
|
||||||
@@ -87,7 +87,8 @@ public class DefaultMiddlewareContainer<M> implements MiddlewareContainer<M> {
|
|||||||
.forEach(afterIndex -> sorter.addEdge(currentIndex, afterIndex));
|
.forEach(afterIndex -> sorter.addEdge(currentIndex, afterIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Middleware<M>> middlewaresById = middlewares.stream().collect(Collectors.toMap(Middleware::id, Function.identity()));
|
Map<String, Middleware<M, C>> middlewaresById = middlewares.stream()
|
||||||
|
.collect(Collectors.toMap(Middleware::id, Function.identity()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int[] sortedIndeces = sorter.sort();
|
int[] sortedIndeces = sorter.sort();
|
||||||
@@ -107,13 +108,27 @@ public class DefaultMiddlewareContainer<M> implements MiddlewareContainer<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public M process(M inner, C context) {
|
||||||
|
if (!sealed) {
|
||||||
|
throw new IllegalStateException("Middleware container has not been sealed");
|
||||||
|
}
|
||||||
|
M combined = inner;
|
||||||
|
for (int i = middlewares.size() - 1; i >= 0; i--) {
|
||||||
|
Middleware<M, C> middleware = middlewares.get(i);
|
||||||
|
combined = middleware.process(combined, context);
|
||||||
|
}
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
public M process(M inner) {
|
public M process(M inner) {
|
||||||
if (!sealed) {
|
if (!sealed) {
|
||||||
throw new IllegalStateException("Middleware container has not been sealed");
|
throw new IllegalStateException("Middleware container has not been sealed");
|
||||||
}
|
}
|
||||||
M combined = inner;
|
M combined = inner;
|
||||||
for (int i = middlewares.size() - 1; i >= 0; i--) {
|
for (int i = middlewares.size() - 1; i >= 0; i--) {
|
||||||
Middleware<M> middleware = middlewares.get(i);
|
Middleware<M, C> middleware = middlewares.get(i);
|
||||||
combined = middleware.process(combined);
|
combined = middleware.process(combined);
|
||||||
}
|
}
|
||||||
return combined;
|
return combined;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package de.siphalor.tweed5.core.api.middleware;
|
package de.siphalor.tweed5.core.api.middleware;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public interface Middleware<M> {
|
public interface Middleware<M, C> {
|
||||||
String DEFAULT_START = "$default.start";
|
String DEFAULT_START = "$default.start";
|
||||||
String DEFAULT_END = "$default.end";
|
String DEFAULT_END = "$default.end";
|
||||||
|
|
||||||
@@ -16,5 +18,13 @@ public interface Middleware<M> {
|
|||||||
return Collections.singleton(DEFAULT_START);
|
return Collections.singleton(DEFAULT_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
M process(M inner);
|
default M process(M inner, C context) {
|
||||||
|
return process(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@ApiStatus.OverrideOnly
|
||||||
|
default M process(M inner) {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package de.siphalor.tweed5.core.api.middleware;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface MiddlewareContainer<M> extends Middleware<M> {
|
public interface MiddlewareContainer<M, C> extends Middleware<M, C> {
|
||||||
default void registerAll(Collection<Middleware<M>> middlewares) {
|
default void registerAll(Collection<Middleware<M, C>> middlewares) {
|
||||||
middlewares.forEach(this::register);
|
middlewares.forEach(this::register);
|
||||||
}
|
}
|
||||||
void register(Middleware<M> middleware);
|
void register(Middleware<M, C> middleware);
|
||||||
void seal();
|
void seal();
|
||||||
Collection<Middleware<M>> middlewares();
|
Collection<Middleware<M, C>> middlewares();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package de.siphalor.tweed5.core.impl.entry;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.core.api.entry.*;
|
import de.siphalor.tweed5.core.api.entry.*;
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements CollectionConfigEntry<E, T> {
|
public class CollectionConfigEntryImpl<E, T extends @NonNull Collection<E>> extends BaseConfigEntry<T> implements CollectionConfigEntry<E, T> {
|
||||||
private final IntFunction<T> collectionConstructor;
|
private final IntFunction<T> collectionConstructor;
|
||||||
private final ConfigEntry<E> elementEntry;
|
private final ConfigEntry<E> elementEntry;
|
||||||
|
|
||||||
|
|||||||
@@ -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.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||||
import de.siphalor.tweed5.core.api.entry.NullableConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.NullableConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -24,6 +25,11 @@ public class NullableConfigEntryImpl<T extends @Nullable Object> extends BaseCon
|
|||||||
this.nonNullEntry = nonNullEntry;
|
this.nonNullEntry = nonNullEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get(T value, String dataKey) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, ConfigEntry<?>> subEntries() {
|
public Map<String, ConfigEntry<?>> subEntries() {
|
||||||
return Collections.singletonMap(NON_NULL_KEY, nonNullEntry);
|
return Collections.singletonMap(NON_NULL_KEY, nonNullEntry);
|
||||||
@@ -33,9 +39,10 @@ public class NullableConfigEntryImpl<T extends @Nullable Object> extends BaseCon
|
|||||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (visitor.enterStructuredEntry(this, value)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
if (visitor.enterStructuredSubEntry(NON_NULL_KEY, NON_NULL_KEY)) {
|
SubEntryKey subEntryKey = SubEntryKey.transparentAddressable(NON_NULL_KEY, NON_NULL_KEY);
|
||||||
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
nonNullEntry.visitInOrder(visitor, value);
|
nonNullEntry.visitInOrder(visitor, value);
|
||||||
visitor.leaveStructuredSubEntry(NON_NULL_KEY, NON_NULL_KEY);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
}
|
}
|
||||||
visitor.leaveStructuredEntry(this, value);
|
visitor.leaveStructuredEntry(this, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ package de.siphalor.tweed5.core.impl.entry;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.core.api.entry.*;
|
import de.siphalor.tweed5.core.api.entry.*;
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> extends BaseConfigEntry<T> implements CompoundConfigEntry<T> {
|
public class StaticMapCompoundConfigEntryImpl<T extends @NonNull Map<String, Object>> extends BaseConfigEntry<T> implements CompoundConfigEntry<T> {
|
||||||
private final IntFunction<T> mapConstructor;
|
private final IntFunction<T> mapConstructor;
|
||||||
private final Map<String, ConfigEntry<?>> compoundEntries;
|
private final Map<String, ConfigEntry<?>> compoundEntries;
|
||||||
|
|
||||||
@@ -28,16 +29,15 @@ public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <V> void set(T compoundValue, String key, V value) {
|
public void set(T compoundValue, String dataKey, Object value) {
|
||||||
requireKey(key);
|
requireKey(dataKey);
|
||||||
compoundValue.put(key, value);
|
compoundValue.put(dataKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <V> V get(T compoundValue, String key) {
|
public Object get(T compoundValue, String dataKey) {
|
||||||
requireKey(key);
|
requireKey(dataKey);
|
||||||
//noinspection unchecked
|
return compoundValue.get(dataKey);
|
||||||
return (V) compoundValue.get(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requireKey(String key) {
|
private void requireKey(String key) {
|
||||||
@@ -47,29 +47,28 @@ public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T instantiateCompoundValue() {
|
public T instantiateValue() {
|
||||||
return mapConstructor.apply(compoundEntries.size());
|
return mapConstructor.apply(compoundEntries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||||
if (visitor.enterStructuredEntry(this, value)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
if (value != null) {
|
compoundEntries.forEach((key, entry) -> {
|
||||||
compoundEntries.forEach((key, entry) -> {
|
SubEntryKey subEntryKey = SubEntryKey.addressable(key, key, key);
|
||||||
if (visitor.enterStructuredSubEntry(key, key)) {
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
((ConfigEntry<Object>) entry).visitInOrder(visitor, value.get(key));
|
((ConfigEntry<Object>) entry).visitInOrder(visitor, value.get(key));
|
||||||
visitor.leaveStructuredSubEntry(key, key);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
visitor.leaveStructuredEntry(this, value);
|
visitor.leaveStructuredEntry(this, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T deepCopy(T value) {
|
public T deepCopy(T value) {
|
||||||
T copy = instantiateCompoundValue();
|
T copy = instantiateValue();
|
||||||
value.forEach((String key, Object element) -> {
|
value.forEach((String key, Object element) -> {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
ConfigEntry<Object> elementEntry = (ConfigEntry<Object>) compoundEntries.get(key);
|
ConfigEntry<Object> elementEntry = (ConfigEntry<Object>) compoundEntries.get(key);
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package de.siphalor.tweed5.defaultextensions.comment.api;
|
|||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
|
|
||||||
public interface CommentModifyingExtension {
|
public interface CommentModifyingExtension {
|
||||||
Middleware<CommentProducer> commentMiddleware();
|
Middleware<CommentProducer, CommentProducerMiddlewareContext> commentMiddleware();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.comment.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
@Builder
|
||||||
|
public class CommentProducerMiddlewareContext {
|
||||||
|
ConfigEntry<?> entry;
|
||||||
|
}
|
||||||
@@ -6,8 +6,9 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducerMiddlewareContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||||
@@ -20,7 +21,7 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
|
|||||||
private final ConfigContainer<?> configContainer;
|
private final ConfigContainer<?> configContainer;
|
||||||
@Getter
|
@Getter
|
||||||
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
||||||
private final DefaultMiddlewareContainer<CommentProducer> middlewareContainer;
|
private final DefaultMiddlewareContainer<CommentProducer, CommentProducerMiddlewareContext> middlewareContainer;
|
||||||
@Getter
|
@Getter
|
||||||
private @Nullable PatchworkPartAccess<Boolean> writerInstalledReadWriteContextAccess;
|
private @Nullable PatchworkPartAccess<Boolean> writerInstalledReadWriteContextAccess;
|
||||||
|
|
||||||
@@ -71,7 +72,10 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
|
|||||||
public void recomputeFullComments() {
|
public void recomputeFullComments() {
|
||||||
configContainer.rootEntry().visitInOrder(entry -> {
|
configContainer.rootEntry().visitInOrder(entry -> {
|
||||||
CustomEntryData entryData = getOrCreateCustomEntryData(entry);
|
CustomEntryData entryData = getOrCreateCustomEntryData(entry);
|
||||||
entryData.commentProducer(middlewareContainer.process(_entry -> entryData.baseComment()));
|
entryData.commentProducer(middlewareContainer.process(
|
||||||
|
_entry -> entryData.baseComment(),
|
||||||
|
CommentProducerMiddlewareContext.builder().entry(entry).build()
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package de.siphalor.tweed5.defaultextensions.comment.impl;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryWriter;
|
||||||
import de.siphalor.tweed5.dataapi.api.DelegatingTweedDataWriter;
|
import de.siphalor.tweed5.serde.extension.api.extension.WriterMiddlewareContext;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.serde_api.api.DelegatingTweedDataWriter;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataWriter;
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataCommentDecoration;
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataCommentDecoration;
|
||||||
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataDecoration;
|
||||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
@@ -18,7 +18,7 @@ import java.util.ArrayDeque;
|
|||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
|
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>, WriterMiddlewareContext> {
|
||||||
private final CommentExtensionImpl commentExtension;
|
private final CommentExtensionImpl commentExtension;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,15 +27,15 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
|
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner, WriterMiddlewareContext context) {
|
||||||
PatchworkPartAccess<Boolean> writerInstalledAccess = commentExtension.writerInstalledReadWriteContextAccess();
|
PatchworkPartAccess<Boolean> writerInstalledAccess = commentExtension.writerInstalledReadWriteContextAccess();
|
||||||
assert writerInstalledAccess != null;
|
assert writerInstalledAccess != null;
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
return (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) (writer, value, entry, context) -> {
|
return (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) (writer, value, entry, writeContext) -> {
|
||||||
if (!Boolean.TRUE.equals(context.extensionsData().get(writerInstalledAccess))) {
|
if (!Boolean.TRUE.equals(writeContext.extensionsData().get(writerInstalledAccess))) {
|
||||||
context.extensionsData().set(writerInstalledAccess, Boolean.TRUE);
|
writeContext.extensionsData().set(writerInstalledAccess, Boolean.TRUE);
|
||||||
|
|
||||||
writer = new MapEntryKeyDeferringWriter(writer);
|
writer = new MapEntryKeyDeferringWriter(writer);
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
|
|||||||
writer.visitDecoration(new PiercingCommentDecoration(() -> comment));
|
writer.visitDecoration(new PiercingCommentDecoration(() -> comment));
|
||||||
}
|
}
|
||||||
|
|
||||||
innerCasted.write(writer, value, entry, context);
|
innerCasted.write(writer, value, entry, writeContext);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ package de.siphalor.tweed5.defaultextensions.patch.impl;
|
|||||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReaderMiddlewareContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
|
||||||
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
@@ -62,7 +61,7 @@ public class PatchExtensionImpl implements PatchExtension, ReadWriteRelatedExten
|
|||||||
if (targetValue != null) {
|
if (targetValue != null) {
|
||||||
targetCompoundValue = targetValue;
|
targetCompoundValue = targetValue;
|
||||||
} else {
|
} else {
|
||||||
targetCompoundValue = compoundEntry.instantiateCompoundValue();
|
targetCompoundValue = compoundEntry.instantiateValue();
|
||||||
}
|
}
|
||||||
compoundEntry.subEntries().forEach((key, subEntry) -> {
|
compoundEntry.subEntries().forEach((key, subEntry) -> {
|
||||||
if (!patchInfo.containsEntry(subEntry)) {
|
if (!patchInfo.containsEntry(subEntry)) {
|
||||||
@@ -70,7 +69,7 @@ public class PatchExtensionImpl implements PatchExtension, ReadWriteRelatedExten
|
|||||||
}
|
}
|
||||||
compoundEntry.set(
|
compoundEntry.set(
|
||||||
targetCompoundValue, key, patch(
|
targetCompoundValue, key, patch(
|
||||||
subEntry,
|
(ConfigEntry<Object>) subEntry,
|
||||||
compoundEntry.get(targetCompoundValue, key),
|
compoundEntry.get(targetCompoundValue, key),
|
||||||
compoundEntry.get(patchValue, key),
|
compoundEntry.get(patchValue, key),
|
||||||
patchInfo
|
patchInfo
|
||||||
@@ -83,33 +82,26 @@ public class PatchExtensionImpl implements PatchExtension, ReadWriteRelatedExten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReaderMiddleware implements Middleware<TweedEntryReader<?, ?>> {
|
private class ReaderMiddleware implements Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext> {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return "patch-info-collector";
|
return "patch-info-collector";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
|
||||||
assert readWriteContextDataAccess != null;
|
assert readWriteContextDataAccess != null;
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryReader<Object, ConfigEntry<Object>> innerCasted =
|
TweedEntryReader<Object, ConfigEntry<Object>> innerCasted =
|
||||||
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
return new TweedEntryReader<@Nullable Object, ConfigEntry<Object>>() {
|
return (TweedEntryReader<Object, ConfigEntry<Object>>) (reader, entry, readContext) -> {
|
||||||
@Override
|
TweedReadResult<Object> readResult = innerCasted.read(reader, entry, readContext);
|
||||||
public @Nullable Object read(
|
ReadWriteContextCustomData customData = readContext.extensionsData().get(readWriteContextDataAccess);
|
||||||
TweedDataReader reader,
|
if (customData != null && customData.patchInfo() != null) {
|
||||||
ConfigEntry<Object> entry,
|
customData.patchInfo().addEntry(entry);
|
||||||
TweedReadContext context
|
|
||||||
) throws TweedEntryReadException {
|
|
||||||
Object readValue = innerCasted.read(reader, entry, context);
|
|
||||||
ReadWriteContextCustomData customData = context.extensionsData().get(readWriteContextDataAccess);
|
|
||||||
if (customData != null && customData.patchInfo() != null) {
|
|
||||||
customData.patchInfo().addEntry(entry);
|
|
||||||
}
|
|
||||||
return readValue;
|
|
||||||
}
|
}
|
||||||
|
return readResult;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ public interface PathTracking {
|
|||||||
|
|
||||||
void pushPathPart(String pathPart);
|
void pushPathPart(String pathPart);
|
||||||
|
|
||||||
|
void pushEmptyPathPart();
|
||||||
|
|
||||||
void popPathPart();
|
void popPathPart();
|
||||||
|
|
||||||
String currentPath();
|
String currentPath();
|
||||||
|
|
||||||
|
String[] currentPathParts();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package de.siphalor.tweed5.defaultextensions.pather.api;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
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 lombok.RequiredArgsConstructor;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@@ -16,27 +18,31 @@ public class PathTrackingConfigEntryValueVisitor implements ConfigEntryValueVisi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> boolean enterStructuredEntry(ConfigEntry<T> entry, T value) {
|
public <T> boolean enterStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
return delegate.enterStructuredEntry(entry, value);
|
return delegate.enterStructuredEntry(entry, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
public boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||||
boolean enter = delegate.enterStructuredSubEntry(entryKey, valueKey);
|
boolean enter = delegate.enterSubEntry(subEntryKey);
|
||||||
if (enter) {
|
if (enter) {
|
||||||
pathTracking.pushPathPart(entryKey, valueKey);
|
if (subEntryKey.value() != null) {
|
||||||
|
pathTracking.pushPathPart(subEntryKey.entry(), subEntryKey.value());
|
||||||
|
} else {
|
||||||
|
pathTracking.pushEmptyValuePathPart(subEntryKey.entry());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return enter;
|
return enter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
public void leaveSubEntry(SubEntryKey subEntryKey) {
|
||||||
delegate.leaveStructuredSubEntry(entryKey, valueKey);
|
delegate.leaveSubEntry(subEntryKey);
|
||||||
pathTracking.popPathPart();
|
pathTracking.popPathPart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void leaveStructuredEntry(ConfigEntry<T> entry, T value) {
|
public <T> void leaveStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
delegate.leaveStructuredEntry(entry, value);
|
delegate.leaveStructuredEntry(entry, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||||
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReadException;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataToken;
|
import de.siphalor.tweed5.serde_api.api.TweedDataToken;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||||
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataUnsupportedValueException;
|
import de.siphalor.tweed5.serde_api.api.TweedDataUnsupportedValueException;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
import de.siphalor.tweed5.serde_api.api.decoration.TweedDataDecoration;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||||
|
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
import de.siphalor.tweed5.serde.extension.api.TweedReadContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedWriteContext;
|
import de.siphalor.tweed5.serde.extension.api.TweedWriteContext;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.impl.PatherExtensionImpl;
|
import de.siphalor.tweed5.defaultextensions.pather.impl.PatherExtensionImpl;
|
||||||
|
|
||||||
public interface PatherExtension extends TweedExtension {
|
public interface PatherExtension extends TweedExtension {
|
||||||
|
|||||||
@@ -17,6 +17,17 @@ public final class ValuePathTracking implements PathTracking {
|
|||||||
valuePathTracking.pushPathPart(valuePathPart);
|
valuePathTracking.pushPathPart(valuePathPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushEmptyPathPart() {
|
||||||
|
entryPathTracking.pushEmptyPathPart();
|
||||||
|
valuePathTracking.pushEmptyPathPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushEmptyValuePathPart(String entryPathPart) {
|
||||||
|
entryPathTracking.pushPathPart(entryPathPart);
|
||||||
|
valuePathTracking.pushEmptyPathPart();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void popPathPart() {
|
public void popPathPart() {
|
||||||
valuePathTracking.popPathPart();
|
valuePathTracking.popPathPart();
|
||||||
@@ -31,4 +42,13 @@ public final class ValuePathTracking implements PathTracking {
|
|||||||
public String currentEntryPath() {
|
public String currentEntryPath() {
|
||||||
return entryPathTracking.currentPath();
|
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;
|
package de.siphalor.tweed5.defaultextensions.pather.impl;
|
||||||
|
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
|
||||||
public class PathTrackingImpl implements PathTracking {
|
public class PathTrackingImpl implements PathTracking {
|
||||||
private final StringBuilder pathBuilder = new StringBuilder(256);
|
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
|
@Override
|
||||||
public void pushPathPart(String entryPathPart) {
|
public void pushPathPart(String entryPathPart) {
|
||||||
@@ -15,11 +16,18 @@ public class PathTrackingImpl implements PathTracking {
|
|||||||
pathBuilder.append(".").append(entryPathPart);
|
pathBuilder.append(".").append(entryPathPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushEmptyPathPart() {
|
||||||
|
pathParts.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void popPathPart() {
|
public void popPathPart() {
|
||||||
if (!pathParts.isEmpty()) {
|
if (!pathParts.isEmpty()) {
|
||||||
String poppedPart = pathParts.pop();
|
String poppedPart = pathParts.pop();
|
||||||
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
if (poppedPart != null) {
|
||||||
|
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,4 +35,9 @@ public class PathTrackingImpl implements PathTracking {
|
|||||||
public String currentPath() {
|
public String currentPath() {
|
||||||
return pathBuilder.toString();
|
return pathBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] currentPathParts() {
|
||||||
|
return pathParts.toArray(new String[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package de.siphalor.tweed5.defaultextensions.pather.impl;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.*;
|
import de.siphalor.tweed5.serde.extension.api.*;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReaderMiddlewareContext;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.serde.extension.api.extension.WriterMiddlewareContext;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataReader;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataReader;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataVisitor;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataVisitor;
|
||||||
@@ -48,75 +50,62 @@ public class PatherExtensionImpl implements PatherExtension, ReadWriteRelatedExt
|
|||||||
return pathTracking.currentPath();
|
return pathTracking.currentPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() {
|
private Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext> createEntryReaderMiddleware() {
|
||||||
return new Middleware<TweedEntryReader<?, ?>>() {
|
return new Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext>() {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
|
||||||
assert rwContextPathTrackingAccess != null;
|
assert rwContextPathTrackingAccess != null;
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
val castedInner = (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
val castedInner = (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
|
|
||||||
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) -> {
|
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext readContext) -> {
|
||||||
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
|
PathTracking pathTracking = readContext.extensionsData().get(rwContextPathTrackingAccess);
|
||||||
if (pathTracking != null) {
|
if (pathTracking != null) {
|
||||||
return castedInner.read(reader, entry, context);
|
return castedInner.read(reader, entry, readContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
pathTracking = PathTracking.create();
|
pathTracking = PathTracking.create();
|
||||||
context.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
readContext.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
||||||
try {
|
return castedInner.read(new PathTrackingDataReader(reader, pathTracking), entry, readContext);
|
||||||
return castedInner.read(new PathTrackingDataReader(reader, pathTracking), entry, context);
|
|
||||||
} catch (TweedEntryReadException e) {
|
|
||||||
val exceptionPathTracking = e.context().extensionsData().get(rwContextPathTrackingAccess);
|
|
||||||
if (exceptionPathTracking != null) {
|
|
||||||
throw new TweedEntryReadException(
|
|
||||||
"Exception while reading entry at "
|
|
||||||
+ exceptionPathTracking.currentPath()
|
|
||||||
+ ": " + e.getMessage(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Middleware<TweedEntryWriter<?, ?>> createEntryWriterMiddleware() {
|
private Middleware<TweedEntryWriter<?, ?>, WriterMiddlewareContext> createEntryWriterMiddleware() {
|
||||||
return new Middleware<TweedEntryWriter<?, ?>>() {
|
return new Middleware<TweedEntryWriter<?, ?>, WriterMiddlewareContext>() {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
|
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner, WriterMiddlewareContext context) {
|
||||||
assert rwContextPathTrackingAccess != null;
|
assert rwContextPathTrackingAccess != null;
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
val castedInner = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
val castedInner = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
|
|
||||||
return (TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext context) -> {
|
return (TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext writeContext) -> {
|
||||||
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
|
PathTracking pathTracking = writeContext.extensionsData().get(rwContextPathTrackingAccess);
|
||||||
if (pathTracking != null) {
|
if (pathTracking != null) {
|
||||||
castedInner.write(writer, value, entry, context);
|
castedInner.write(writer, value, entry, writeContext);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pathTracking = PathTracking.create();
|
pathTracking = PathTracking.create();
|
||||||
context.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
writeContext.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
||||||
try {
|
try {
|
||||||
castedInner.write(new PathTrackingDataVisitor(writer, pathTracking), value, entry, context);
|
castedInner.write(new PathTrackingDataVisitor(writer, pathTracking), value, entry, writeContext);
|
||||||
} catch (TweedEntryWriteException e) {
|
} catch (TweedEntryWriteException e) {
|
||||||
val exceptionPathTracking = e.context().extensionsData().get(rwContextPathTrackingAccess);
|
PathTracking exceptionPathTracking =
|
||||||
|
e.context().extensionsData().get(rwContextPathTrackingAccess);
|
||||||
if (exceptionPathTracking != null) {
|
if (exceptionPathTracking != null) {
|
||||||
throw new TweedEntryWriteException(
|
throw new TweedEntryWriteException(
|
||||||
"Exception while writing entry at "
|
"Exception while writing entry at "
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ package de.siphalor.tweed5.defaultextensions.readfallback.impl;
|
|||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReaderMiddlewareContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
import lombok.extern.apachecommons.CommonsLog;
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import org.jspecify.annotations.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
|
|
||||||
@@ -30,9 +31,7 @@ public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWri
|
|||||||
PresetsExtension presetsExtension = configContainer.extension(PresetsExtension.class)
|
PresetsExtension presetsExtension = configContainer.extension(PresetsExtension.class)
|
||||||
.orElseThrow(() -> new IllegalStateException(getClass().getSimpleName()
|
.orElseThrow(() -> new IllegalStateException(getClass().getSimpleName()
|
||||||
+ " requires " + ReadFallbackExtension.class.getSimpleName()));
|
+ " requires " + ReadFallbackExtension.class.getSimpleName()));
|
||||||
PatherExtension patherExtension = configContainer.extension(PatherExtension.class).orElse(null);
|
context.registerReaderMiddleware(new Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext>() {
|
||||||
|
|
||||||
context.registerReaderMiddleware(new Middleware<TweedEntryReader<?, ?>>() {
|
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
@@ -49,26 +48,19 @@ public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWri
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryReader<Object, ConfigEntry<Object>> castedInner =
|
TweedEntryReader<Object, ConfigEntry<Object>> castedInner =
|
||||||
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
return (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) (reader, entry, context) -> {
|
return (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) (reader, entry, readContext) ->
|
||||||
try {
|
castedInner.read(reader, entry, readContext).catchError(
|
||||||
return castedInner.read(reader, entry, context);
|
issues -> {
|
||||||
} catch (TweedEntryReadException e) {
|
Object fallback =
|
||||||
if (patherExtension == null) {
|
presetsExtension.presetValue(entry, PresetsExtension.DEFAULT_PRESET_NAME);
|
||||||
log.error("Failed to read entry: " + e.getMessage(), e);
|
return TweedReadResult.withIssues(fallback, issues);
|
||||||
} else {
|
},
|
||||||
log.error(
|
readContext
|
||||||
"Failed to read entry: " + e.getMessage()
|
);
|
||||||
+ " at " + patherExtension.getPath(context),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return presetsExtension.presetValue(entry, PresetsExtension.DEFAULT_PRESET_NAME);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResu
|
|||||||
import de.siphalor.tweed5.defaultextensions.validation.api.validators.SimpleValidatorMiddleware;
|
import de.siphalor.tweed5.defaultextensions.validation.api.validators.SimpleValidatorMiddleware;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.impl.ValidationExtensionImpl;
|
import de.siphalor.tweed5.defaultextensions.validation.impl.ValidationExtensionImpl;
|
||||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -55,7 +56,10 @@ public interface ValidationExtension extends TweedExtension {
|
|||||||
lastId = id;
|
lastId = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<T> void addValidatorMiddleware(ConfigEntry<T> entry, Middleware<ConfigEntryValidator> validator);
|
<T> void addValidatorMiddleware(
|
||||||
|
ConfigEntry<T> entry,
|
||||||
|
Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> validator
|
||||||
|
);
|
||||||
|
|
||||||
ValidationIssues captureValidationIssues(Patchwork readContextExtensionsData);
|
ValidationIssues captureValidationIssues(Patchwork readContextExtensionsData);
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package de.siphalor.tweed5.defaultextensions.validation.api;
|
|||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
|
|
||||||
public interface ValidationProvidingExtension {
|
public interface ValidationProvidingExtension {
|
||||||
Middleware<ConfigEntryValidator> validationMiddleware();
|
Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> validationMiddleware();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.validation.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor(access = lombok.AccessLevel.PRIVATE)
|
||||||
|
@Builder
|
||||||
|
public class ValidatorMiddlewareContext {
|
||||||
|
ConfigEntry<?> entry;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package de.siphalor.tweed5.defaultextensions.validation.api.validators;
|
|||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidatorMiddlewareContext;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -10,12 +11,12 @@ import org.jspecify.annotations.Nullable;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class SimpleValidatorMiddleware implements Middleware<ConfigEntryValidator> {
|
public class SimpleValidatorMiddleware implements Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> {
|
||||||
String id;
|
String id;
|
||||||
ConfigEntryValidator validator;
|
ConfigEntryValidator validator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigEntryValidator process(ConfigEntryValidator inner) {
|
public ConfigEntryValidator process(ConfigEntryValidator inner, ValidatorMiddlewareContext context) {
|
||||||
return new ConfigEntryValidator() {
|
return new ConfigEntryValidator() {
|
||||||
@Override
|
@Override
|
||||||
public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
||||||
|
|||||||
@@ -3,19 +3,15 @@ package de.siphalor.tweed5.defaultextensions.validation.impl;
|
|||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.StructuredConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.core.api.middleware.MiddlewareContainer;
|
import de.siphalor.tweed5.core.api.middleware.MiddlewareContainer;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducerMiddlewareContext;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryValueVisitor;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryValueVisitor;
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||||
@@ -23,13 +19,23 @@ import de.siphalor.tweed5.defaultextensions.pather.api.ValuePathTracking;
|
|||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidatorMiddlewareContext;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedReadContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.extension.ReaderMiddlewareContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadIssue;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -68,8 +74,8 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
|
|
||||||
private final ConfigContainer<?> configContainer;
|
private final ConfigContainer<?> configContainer;
|
||||||
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
||||||
private final MiddlewareContainer<ConfigEntryValidator> entryValidatorMiddlewareContainer
|
private final MiddlewareContainer<ConfigEntryValidator, ValidatorMiddlewareContext>
|
||||||
= new DefaultMiddlewareContainer<>();
|
entryValidatorMiddlewareContainer = new DefaultMiddlewareContainer<>();
|
||||||
private @Nullable PatchworkPartAccess<ValidationIssues> readContextValidationIssuesAccess;
|
private @Nullable PatchworkPartAccess<ValidationIssues> readContextValidationIssuesAccess;
|
||||||
private @Nullable PatherExtension patherExtension;
|
private @Nullable PatherExtension patherExtension;
|
||||||
|
|
||||||
@@ -95,15 +101,15 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Middleware<CommentProducer> commentMiddleware() {
|
public Middleware<CommentProducer, CommentProducerMiddlewareContext> commentMiddleware() {
|
||||||
return new Middleware<CommentProducer>() {
|
return new Middleware<CommentProducer, CommentProducerMiddlewareContext>() {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommentProducer process(CommentProducer inner) {
|
public CommentProducer process(CommentProducer inner, CommentProducerMiddlewareContext context) {
|
||||||
return entry -> {
|
return entry -> {
|
||||||
String baseComment = inner.createComment(entry);
|
String baseComment = inner.createComment(entry);
|
||||||
CustomEntryData entryData = entry.extensionsData().get(customEntryDataAccess);
|
CustomEntryData entryData = entry.extensionsData().get(customEntryDataAccess);
|
||||||
@@ -133,7 +139,10 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void addValidatorMiddleware(ConfigEntry<T> entry, Middleware<ConfigEntryValidator> validator) {
|
public <T> void addValidatorMiddleware(
|
||||||
|
ConfigEntry<T> entry,
|
||||||
|
Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> validator
|
||||||
|
) {
|
||||||
CustomEntryData entryData = getOrCreateCustomEntryData(entry);
|
CustomEntryData entryData = getOrCreateCustomEntryData(entry);
|
||||||
entryData.addValidator(validator);
|
entryData.addValidator(validator);
|
||||||
}
|
}
|
||||||
@@ -150,13 +159,20 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
CustomEntryData entryData = getOrCreateCustomEntryData(configEntry);
|
CustomEntryData entryData = getOrCreateCustomEntryData(configEntry);
|
||||||
|
|
||||||
if (entryData.validators().isEmpty()) {
|
if (entryData.validators().isEmpty()) {
|
||||||
entryData.completeValidator(entryValidatorMiddlewareContainer.process(baseValidator));
|
entryData.completeValidator(entryValidatorMiddlewareContainer.process(
|
||||||
|
baseValidator,
|
||||||
|
ValidatorMiddlewareContext.builder().entry(configEntry).build()
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
DefaultMiddlewareContainer<ConfigEntryValidator> entrySpecificValidatorContainer = new DefaultMiddlewareContainer<>();
|
DefaultMiddlewareContainer<ConfigEntryValidator, ValidatorMiddlewareContext> entrySpecificValidatorContainer
|
||||||
|
= new DefaultMiddlewareContainer<>();
|
||||||
entrySpecificValidatorContainer.registerAll(entryValidatorMiddlewareContainer.middlewares());
|
entrySpecificValidatorContainer.registerAll(entryValidatorMiddlewareContainer.middlewares());
|
||||||
entrySpecificValidatorContainer.registerAll(entryData.validators());
|
entrySpecificValidatorContainer.registerAll(entryData.validators());
|
||||||
entrySpecificValidatorContainer.seal();
|
entrySpecificValidatorContainer.seal();
|
||||||
entryData.completeValidator(entrySpecificValidatorContainer.process(baseValidator));
|
entryData.completeValidator(entrySpecificValidatorContainer.process(
|
||||||
|
baseValidator,
|
||||||
|
ValidatorMiddlewareContext.builder().entry(configEntry).build()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,14 +213,14 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
@Data
|
@Data
|
||||||
private static class CustomEntryData {
|
private static class CustomEntryData {
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
private @Nullable List<Middleware<ConfigEntryValidator>> validators;
|
private @Nullable List<Middleware<ConfigEntryValidator, ValidatorMiddlewareContext>> validators;
|
||||||
private @Nullable ConfigEntryValidator completeValidator;
|
private @Nullable ConfigEntryValidator completeValidator;
|
||||||
|
|
||||||
public List<Middleware<ConfigEntryValidator>> validators() {
|
public List<Middleware<ConfigEntryValidator, ValidatorMiddlewareContext>> validators() {
|
||||||
return validators == null ? Collections.emptyList() : validators;
|
return validators == null ? Collections.emptyList() : validators;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addValidator(Middleware<ConfigEntryValidator> validator) {
|
public void addValidator(Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> validator) {
|
||||||
if (validators == null) {
|
if (validators == null) {
|
||||||
validators = new ArrayList<>();
|
validators = new ArrayList<>();
|
||||||
}
|
}
|
||||||
@@ -212,7 +228,8 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EntryValidationReaderMiddleware implements Middleware<TweedEntryReader<?, ?>> {
|
private class EntryValidationReaderMiddleware
|
||||||
|
implements Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext> {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
@@ -224,43 +241,55 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
|
||||||
assert readContextValidationIssuesAccess != null && patherExtension != null;
|
assert readContextValidationIssuesAccess != null && patherExtension != null;
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryReader<Object, ConfigEntry<Object>> castedInner = (TweedEntryReader<Object, ConfigEntry<Object>>) inner;
|
TweedEntryReader<Object, ConfigEntry<Object>> castedInner = (TweedEntryReader<Object, ConfigEntry<Object>>) inner;
|
||||||
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) -> {
|
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext readContext) -> {
|
||||||
ValidationIssues validationIssues = getOrCreateValidationIssues(context.extensionsData());
|
ValidationIssues validationIssues = getOrCreateValidationIssues(readContext.extensionsData());
|
||||||
|
|
||||||
Object value = castedInner.read(reader, entry, context);
|
return castedInner.read(reader, entry, readContext).andThen(value -> {
|
||||||
|
ConfigEntryValidator entryValidator = entry.extensionsData()
|
||||||
|
.get(customEntryDataAccess)
|
||||||
|
.completeValidator();
|
||||||
|
assert entryValidator != null;
|
||||||
|
|
||||||
ConfigEntryValidator entryValidator = entry.extensionsData()
|
ValidationResult<Object> validationResult = entryValidator.validate(entry, value);
|
||||||
.get(customEntryDataAccess)
|
|
||||||
.completeValidator();
|
|
||||||
assert entryValidator != null;
|
|
||||||
|
|
||||||
ValidationResult<Object> validationResult = entryValidator.validate(entry, value);
|
if (validationResult.issues().isEmpty()) {
|
||||||
|
return TweedReadResult.ok(validationResult.value());
|
||||||
|
}
|
||||||
|
|
||||||
if (!validationResult.issues().isEmpty()) {
|
String path = patherExtension.getPath(readContext);
|
||||||
String path = patherExtension.getPath(context);
|
|
||||||
validationIssues.issuesByPath().put(path, new ValidationIssues.EntryIssues(
|
validationIssues.issuesByPath().put(path, new ValidationIssues.EntryIssues(
|
||||||
entry,
|
entry,
|
||||||
validationResult.issues()
|
validationResult.issues()
|
||||||
));
|
));
|
||||||
}
|
if (validationResult.hasError()) {
|
||||||
|
return TweedReadResult.failed(
|
||||||
if (validationResult.hasError()) {
|
mapValidationIssuesToReadIssues(validationResult.issues(), readContext)
|
||||||
throw new TweedEntryReadException(
|
);
|
||||||
"Failed to validate entry: " + validationResult.issues(),
|
} else {
|
||||||
context
|
return TweedReadResult.withIssues(
|
||||||
);
|
validationResult.value(),
|
||||||
}
|
mapValidationIssuesToReadIssues(validationResult.issues(), readContext)
|
||||||
|
);
|
||||||
return validationResult.value();
|
}
|
||||||
|
}, readContext);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TweedReadIssue[] mapValidationIssuesToReadIssues(
|
||||||
|
Collection<ValidationIssue> issues,
|
||||||
|
TweedReadContext context
|
||||||
|
) {
|
||||||
|
return issues.stream().map(
|
||||||
|
validationIssue -> TweedReadIssue.error(validationIssue.message(), context)
|
||||||
|
).toArray(TweedReadIssue[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
private ValidationIssues getOrCreateValidationIssues(Patchwork readContextExtensionsData) {
|
private ValidationIssues getOrCreateValidationIssues(Patchwork readContextExtensionsData) {
|
||||||
assert readContextValidationIssuesAccess != null;
|
assert readContextValidationIssuesAccess != null;
|
||||||
ValidationIssues validationIssues = readContextExtensionsData.get(readContextValidationIssuesAccess);
|
ValidationIssues validationIssues = readContextExtensionsData.get(readContextValidationIssuesAccess);
|
||||||
@@ -290,12 +319,12 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> boolean enterStructuredEntry(ConfigEntry<T> entry, T value) {
|
public <T> boolean enterStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void leaveStructuredEntry(ConfigEntry<T> entry, T value) {
|
public <T> void leaveStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
visitEntry(entry, value);
|
visitEntry(entry, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import de.siphalor.tweed5.core.api.middleware.Middleware;
|
|||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidatorMiddlewareContext;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||||
@@ -62,11 +63,11 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Middleware<ConfigEntryValidator> validationMiddleware() {
|
public Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> validationMiddleware() {
|
||||||
return new ValidationFallbackMiddleware();
|
return new ValidationFallbackMiddleware();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ValidationFallbackMiddleware implements Middleware<ConfigEntryValidator> {
|
private class ValidationFallbackMiddleware implements Middleware<ConfigEntryValidator, ValidatorMiddlewareContext> {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
return EXTENSION_ID;
|
return EXTENSION_ID;
|
||||||
@@ -83,7 +84,7 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigEntryValidator process(ConfigEntryValidator inner) {
|
public ConfigEntryValidator process(ConfigEntryValidator inner, ValidatorMiddlewareContext context) {
|
||||||
return new ConfigEntryValidator() {
|
return new ConfigEntryValidator() {
|
||||||
@Override
|
@Override
|
||||||
public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
|||||||
import de.siphalor.tweed5.core.impl.entry.NullableConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.NullableConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducerMiddlewareContext;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonCommentType;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
import de.siphalor.tweed5.serde.hjson.HjsonCommentType;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonWriter;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||||
@@ -26,9 +27,9 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.entryReaderWriter;
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.entryReaderWriter;
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
|
||||||
import static de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension.baseComment;
|
import static de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension.baseComment;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||||
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
@@ -144,7 +145,7 @@ class CommentExtensionImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Middleware<CommentProducer> commentMiddleware() {
|
public Middleware<CommentProducer, CommentProducerMiddlewareContext> commentMiddleware() {
|
||||||
return new Middleware<>() {
|
return new Middleware<>() {
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
@@ -152,7 +153,7 @@ class CommentExtensionImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommentProducer process(CommentProducer inner) {
|
public CommentProducer process(CommentProducer inner, CommentProducerMiddlewareContext context) {
|
||||||
return entry -> "The comment is:\n" + inner.createComment(entry) + "\nEND";
|
return entry -> "The comment is:\n" + inner.createComment(entry) + "\nEND";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import de.siphalor.tweed5.core.impl.entry.CollectionConfigEntryImpl;
|
|||||||
import de.siphalor.tweed5.core.impl.entry.NullableConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.NullableConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
import de.siphalor.tweed5.serde.hjson.HjsonLexer;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonReader;
|
||||||
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@@ -26,9 +27,9 @@ import java.util.*;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.entryReaderWriter;
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.entryReaderWriter;
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.read;
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.read;
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||||
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -150,7 +151,7 @@ class PatchExtensionImplTest {
|
|||||||
PatchExtension patchExtension = configContainer.extension(PatchExtension.class).orElseThrow();
|
PatchExtension patchExtension = configContainer.extension(PatchExtension.class).orElseThrow();
|
||||||
|
|
||||||
var patchInfo = new AtomicReference<@Nullable PatchInfo>();
|
var patchInfo = new AtomicReference<@Nullable PatchInfo>();
|
||||||
Map<String, Object> patchValue = rootEntry.call(read(
|
TweedReadResult<Map<String, Object>> patchResult = rootEntry.call(read(
|
||||||
reader, extensionsData ->
|
reader, extensionsData ->
|
||||||
patchInfo.set(patchExtension.collectPatchInfo(extensionsData))
|
patchInfo.set(patchExtension.collectPatchInfo(extensionsData))
|
||||||
));
|
));
|
||||||
@@ -158,7 +159,7 @@ class PatchExtensionImplTest {
|
|||||||
Map<String, Object> resultValue = patchExtension.patch(
|
Map<String, Object> resultValue = patchExtension.patch(
|
||||||
rootEntry,
|
rootEntry,
|
||||||
baseValue,
|
baseValue,
|
||||||
patchValue,
|
patchResult.value(),
|
||||||
Objects.requireNonNull(patchInfo.get())
|
Objects.requireNonNull(patchInfo.get())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||||
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataToken;
|
import de.siphalor.tweed5.serde_api.api.TweedDataToken;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataTokens;
|
import de.siphalor.tweed5.serde_api.api.TweedDataTokens;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.readfallback.impl;
|
package de.siphalor.tweed5.defaultextensions.readfallback.impl;
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
import ch.qos.logback.classic.Level;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
||||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
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.extension.api.readwrite.TweedEntryReaderWriters;
|
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
|
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedReadContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.TweedWriteContext;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadIssue;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriter;
|
||||||
|
import de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonLexer;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonReader;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReadException;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.serde_api.api.TweedDataWriteException;
|
||||||
import de.siphalor.tweed5.testutils.generic.log.LogCaptureMockitoExtension;
|
import de.siphalor.tweed5.testutils.generic.log.LogCaptureMockitoExtension;
|
||||||
import de.siphalor.tweed5.testutils.generic.log.LogsCaptor;
|
import de.siphalor.tweed5.testutils.generic.log.LogsCaptor;
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -34,12 +34,11 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
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.data.extension.api.readwrite.TweedEntryReaderWriters.compoundReaderWriter;
|
|
||||||
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
|
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.entryReaderWriter;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.read;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.compoundReaderWriter;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
|
|
||||||
|
|
||||||
@ExtendWith(LogCaptureMockitoExtension.class)
|
@ExtendWith(LogCaptureMockitoExtension.class)
|
||||||
@NullMarked
|
@NullMarked
|
||||||
@@ -59,12 +58,18 @@ class ReadFallbackExtensionImplTest {
|
|||||||
configContainer.attachTree(entry);
|
configContainer.attachTree(entry);
|
||||||
configContainer.initialize();
|
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("12"))))))
|
||||||
|
.isEqualTo(TweedReadResult.ok(12));
|
||||||
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).isEmpty();
|
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).isEmpty();
|
||||||
logsCaptor.clear();
|
logsCaptor.clear();
|
||||||
|
|
||||||
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("13")))))).isEqualTo(-1);
|
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("13")))))).satisfies(
|
||||||
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).hasSize(1);
|
r -> assertThat(r).extracting(TweedReadResult::value).isEqualTo(-1),
|
||||||
|
r -> assertThat(r.issues()).singleElement()
|
||||||
|
.extracting(TweedReadIssue::exception)
|
||||||
|
.extracting(Throwable::getMessage)
|
||||||
|
.isEqualTo("Value is not even")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
@@ -105,6 +110,7 @@ class ReadFallbackExtensionImplTest {
|
|||||||
assertThat(root.call(read(new HjsonReader(new HjsonLexer(new StringReader(
|
assertThat(root.call(read(new HjsonReader(new HjsonLexer(new StringReader(
|
||||||
"{first: {second: 12}}"
|
"{first: {second: 12}}"
|
||||||
))))))
|
))))))
|
||||||
|
.extracting(TweedReadResult::value)
|
||||||
.extracting(map -> (Map<String, Object>) map.get("first"))
|
.extracting(map -> (Map<String, Object>) map.get("first"))
|
||||||
.extracting(map -> (Integer) map.get("second"))
|
.extracting(map -> (Integer) map.get("second"))
|
||||||
.isEqualTo(12);
|
.isEqualTo(12);
|
||||||
@@ -114,22 +120,20 @@ class ReadFallbackExtensionImplTest {
|
|||||||
assertThat(root.call(read(new HjsonReader(new HjsonLexer(new StringReader(
|
assertThat(root.call(read(new HjsonReader(new HjsonLexer(new StringReader(
|
||||||
"{first: {second: 13}}"
|
"{first: {second: 13}}"
|
||||||
))))))
|
))))))
|
||||||
|
.extracting(TweedReadResult::value)
|
||||||
.extracting(map -> (Map<String, Object>) map.get("first"))
|
.extracting(map -> (Map<String, Object>) map.get("first"))
|
||||||
.extracting(map -> (Integer) map.get("second"))
|
.extracting(map -> (Integer) map.get("second"))
|
||||||
.isEqualTo(-1);
|
.isEqualTo(-1);
|
||||||
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).singleElement()
|
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).isEmpty();
|
||||||
.extracting(ILoggingEvent::getMessage)
|
|
||||||
.asInstanceOf(STRING)
|
|
||||||
.contains("first.second");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EvenIntReader implements TweedEntryReaderWriter<Integer, ConfigEntry<Integer>> {
|
private static class EvenIntReader implements TweedEntryReaderWriter<Integer, ConfigEntry<Integer>> {
|
||||||
@Override
|
@Override
|
||||||
public Integer read(
|
public TweedReadResult<Integer> read(
|
||||||
TweedDataReader reader,
|
TweedDataReader reader,
|
||||||
ConfigEntry<Integer> entry,
|
ConfigEntry<Integer> entry,
|
||||||
TweedReadContext context
|
TweedReadContext context
|
||||||
) throws TweedEntryReadException {
|
) {
|
||||||
int value;
|
int value;
|
||||||
try {
|
try {
|
||||||
value = reader.readToken().readAsInt();
|
value = reader.readToken().readAsInt();
|
||||||
@@ -137,9 +141,9 @@ class ReadFallbackExtensionImplTest {
|
|||||||
throw new IllegalStateException("Should not be called", e);
|
throw new IllegalStateException("Should not be called", e);
|
||||||
}
|
}
|
||||||
if (value % 2 == 0) {
|
if (value % 2 == 0) {
|
||||||
return value;
|
return TweedReadResult.ok(value);
|
||||||
} else {
|
} else {
|
||||||
throw new TweedEntryReadException("Value is not even", context);
|
return TweedReadResult.error(TweedReadIssue.error("Value is not even", context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonCommentType;
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
import de.siphalor.tweed5.serde.hjson.HjsonCommentType;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
import de.siphalor.tweed5.serde.hjson.HjsonLexer;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
import de.siphalor.tweed5.serde.hjson.HjsonReader;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonWriter;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||||
@@ -31,10 +32,10 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.*;
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
|
||||||
import static de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension.baseComment;
|
import static de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension.baseComment;
|
||||||
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.*;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||||
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -156,12 +157,14 @@ class ValidationExtensionImplTest {
|
|||||||
}
|
}
|
||||||
""")));
|
""")));
|
||||||
var validationIssues = new AtomicReference<@Nullable ValidationIssues>();
|
var validationIssues = new AtomicReference<@Nullable ValidationIssues>();
|
||||||
Map<String, Object> value = configContainer.rootEntry().call(read(
|
TweedReadResult<Map<String, Object>> value = configContainer.rootEntry().call(read(
|
||||||
reader,
|
reader,
|
||||||
extensionsData -> validationIssues.set(validationExtension.captureValidationIssues(extensionsData))
|
extensionsData -> validationIssues.set(validationExtension.captureValidationIssues(extensionsData))
|
||||||
));
|
));
|
||||||
|
|
||||||
assertThat(value).isEqualTo(Map.of("byte", (byte) 11, "int", 123, "double", 0.5));
|
assertThat(value)
|
||||||
|
.extracting(TweedReadResult::value)
|
||||||
|
.isEqualTo(Map.of("byte", (byte) 11, "int", 123, "double", 0.5));
|
||||||
//noinspection DataFlowIssue
|
//noinspection DataFlowIssue
|
||||||
assertThat(validationIssues.get()).isNotNull().satisfies(
|
assertThat(validationIssues.get()).isNotNull().satisfies(
|
||||||
vi -> assertValidationIssue(
|
vi -> assertValidationIssue(
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
||||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonCommentType;
|
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
import de.siphalor.tweed5.serde.hjson.HjsonCommentType;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
import de.siphalor.tweed5.serde.hjson.HjsonLexer;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
import de.siphalor.tweed5.serde.hjson.HjsonReader;
|
||||||
|
import de.siphalor.tweed5.serde.hjson.HjsonWriter;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||||
@@ -26,10 +27,11 @@ import java.io.StringReader;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.*;
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
|
||||||
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
|
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
|
||||||
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.*;
|
||||||
|
import static de.siphalor.tweed5.serde.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
class ValidationFallbackExtensionImplTest {
|
class ValidationFallbackExtensionImplTest {
|
||||||
@@ -114,8 +116,9 @@ class ValidationFallbackExtensionImplTest {
|
|||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {"0", "7", "123", "null"})
|
@ValueSource(strings = {"0", "7", "123", "null"})
|
||||||
void fallbackTriggers(String input) {
|
void fallbackTriggers(String input) {
|
||||||
Integer result = intEntry.call(read(new HjsonReader(new HjsonLexer(new StringReader(input)))));
|
TweedReadResult<Integer> result = intEntry.call(read(new HjsonReader(new HjsonLexer(new StringReader(input)))));
|
||||||
assertEquals(3, result);
|
assertThat(result).extracting(TweedReadResult::value).isEqualTo(3);
|
||||||
|
assertThat(result.issues()).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
2
tweed5/gradle.properties
Normal file
2
tweed5/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
org.gradle.jvmargs = -Xmx2G
|
||||||
|
org.gradle.configuration-cache = true
|
||||||
2
tweed5/lombok.config
Normal file
2
tweed5/lombok.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lombok.accessors.fluent = true
|
||||||
|
lombok.addLombokGeneratedAnnotation = true
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user