From 81afdcfc560468406077a05f1838448e91d28085 Mon Sep 17 00:00:00 2001 From: Octavia Togami Date: Fri, 25 Oct 2024 18:20:15 -0700 Subject: [PATCH] Add some helpful transform methods Fixes #12 --- .../enginehub/linbus/tree/LinCompoundTag.java | 49 +++++++++++++++++++ .../org/enginehub/linbus/tree/LinListTag.java | 14 ++++++ .../enginehub/linbus/tree/LinRootEntry.java | 21 ++++++++ .../linbus/tree/LinCompoundTagTest.java | 19 +++++++ .../enginehub/linbus/tree/LinListTagTest.java | 14 ++++++ .../tree/NestedTransformShowcaseTest.java | 29 +++++++++++ 6 files changed, 146 insertions(+) create mode 100644 tree/src/test/java/org/enginehub/linbus/tree/NestedTransformShowcaseTest.java diff --git a/tree/src/main/java/org/enginehub/linbus/tree/LinCompoundTag.java b/tree/src/main/java/org/enginehub/linbus/tree/LinCompoundTag.java index 774d568..5c288a1 100644 --- a/tree/src/main/java/org/enginehub/linbus/tree/LinCompoundTag.java +++ b/tree/src/main/java/org/enginehub/linbus/tree/LinCompoundTag.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.function.Function; /** * Represents a compound tag. @@ -395,6 +396,54 @@ public > LinListTag getListTag( return cast; } + private LinCompoundTag withChangedTag(String name, LinTag value) { + LinkedHashMap> newMap = new LinkedHashMap<>(this.value); + newMap.put(name, value); + return new LinCompoundTag(Collections.unmodifiableMap(newMap), false); + } + + /** + * Transform a value in the compound tag. You may change the type of the tag. + * + *

+ * This uses {@link #getTag(String, LinTagType)}, so it will throw an exception if the tag does not exist + * or is of the wrong type. + *

+ * + * @param name the name of the tag to transform + * @param type the type of the tag to transform + * @param transformer the function to transform the tag + * @return the new compound tag + */ + public > LinCompoundTag transformTag( + String name, LinTagType type, Function> transformer + ) { + T tag = getTag(name, type); + LinTag transformed = transformer.apply(tag); + return withChangedTag(name, transformed); + } + + /** + * Transform a list value in the compound tag. You may change the type of the tag. + * + *

+ * This uses {@link #getListTag(String, LinTagType)}, so it will throw an exception if the tag does not exist + * or is of the wrong type. + *

+ * + * @param name the name of the tag to transform + * @param elementType the element type of the list tag to transform + * @param transformer the function to transform the tag + * @return the new compound tag + */ + public > LinCompoundTag transformListTag( + String name, LinTagType elementType, Function, ? extends LinTag> transformer + ) { + LinListTag tag = getListTag(name, elementType); + LinTag transform = transformer.apply(tag); + return withChangedTag(name, transform); + } + /** * Converts this tag into a {@link Builder}. * diff --git a/tree/src/main/java/org/enginehub/linbus/tree/LinListTag.java b/tree/src/main/java/org/enginehub/linbus/tree/LinListTag.java index 4816281..fb59c1c 100644 --- a/tree/src/main/java/org/enginehub/linbus/tree/LinListTag.java +++ b/tree/src/main/java/org/enginehub/linbus/tree/LinListTag.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.function.Function; /** * Represents a list of {@link LinTag LinTags}. @@ -219,6 +220,19 @@ public T get(int index) { return value.get(index); } + /** + * Transform the tag at the given index. + * + * @param index the index of the tag to transform + * @param transformer the function to transform the tag + * @return the new list tag + */ + public LinListTag transformTag(int index, Function transformer) { + var newValue = new ArrayList<>(value); + newValue.set(index, transformer.apply(value.get(index))); + return new LinListTag<>(elementType, List.copyOf(newValue)); + } + /** * Converts this tag into a {@link Builder}. * diff --git a/tree/src/main/java/org/enginehub/linbus/tree/LinRootEntry.java b/tree/src/main/java/org/enginehub/linbus/tree/LinRootEntry.java index f7d67f6..06494de 100644 --- a/tree/src/main/java/org/enginehub/linbus/tree/LinRootEntry.java +++ b/tree/src/main/java/org/enginehub/linbus/tree/LinRootEntry.java @@ -32,6 +32,7 @@ import java.io.UncheckedIOException; import java.util.Map; import java.util.Objects; +import java.util.function.Function; /** * Represents the root implicit-compound-tag entry. @@ -65,6 +66,26 @@ public static LinRootEntry readFrom(LinStream tokens) throws IOException { Objects.requireNonNull(value); } + /** + * Transform the name of this entry. + * + * @param nameTransformer the function to transform the name + * @return the new entry + */ + public LinRootEntry transformName(Function nameTransformer) { + return new LinRootEntry(nameTransformer.apply(name), value); + } + + /** + * Transform the value of this entry. + * + * @param valueTransformer the function to transform the value + * @return the new entry + */ + public LinRootEntry transformValue(Function valueTransformer) { + return new LinRootEntry(name, valueTransformer.apply(value)); + } + /** * Write this entry to a byte array. * diff --git a/tree/src/test/java/org/enginehub/linbus/tree/LinCompoundTagTest.java b/tree/src/test/java/org/enginehub/linbus/tree/LinCompoundTagTest.java index a41aa37..05f5011 100644 --- a/tree/src/test/java/org/enginehub/linbus/tree/LinCompoundTagTest.java +++ b/tree/src/test/java/org/enginehub/linbus/tree/LinCompoundTagTest.java @@ -137,6 +137,25 @@ void getByName() { } } + @Test + void transformByName() { + var tag = LinCompoundTag.of(new LinkedHashMap<>() {{ + put("Hello", LinStringTag.of("World!")); + put("Goodbye", LinIntArrayTag.of(0xCAFE, 0xBABE)); + }}); + var transformed = tag.transformTag("Hello", LinTagType.stringTag(), t -> LinStringTag.of("New World!")); + assertThat(transformed).isEqualTo(LinCompoundTag.of(new LinkedHashMap<>() {{ + put("Hello", LinStringTag.of("New World!")); + put("Goodbye", LinIntArrayTag.of(0xCAFE, 0xBABE)); + }})); + + var transformedToNewType = tag.transformTag("Hello", LinTagType.stringTag(), t -> LinIntArrayTag.of(0xDEAD, 0xBEEF)); + assertThat(transformedToNewType).isEqualTo(LinCompoundTag.of(new LinkedHashMap<>() {{ + put("Hello", LinIntArrayTag.of(0xDEAD, 0xBEEF)); + put("Goodbye", LinIntArrayTag.of(0xCAFE, 0xBABE)); + }})); + } + @Test void findByName() { var tag = LinCompoundTag.of(new LinkedHashMap<>() {{ diff --git a/tree/src/test/java/org/enginehub/linbus/tree/LinListTagTest.java b/tree/src/test/java/org/enginehub/linbus/tree/LinListTagTest.java index be4a66a..8fe496f 100644 --- a/tree/src/test/java/org/enginehub/linbus/tree/LinListTagTest.java +++ b/tree/src/test/java/org/enginehub/linbus/tree/LinListTagTest.java @@ -64,6 +64,20 @@ void setOnBuilder() { ).isEqualTo(initial.toBuilder().set(0, LinStringTag.of("Goodbye...")).build()); } + @Test + void transformByIndex() { + var initial = LinListTag.of(LinTagType.stringTag(), List.of( + LinStringTag.of("Hello"), + LinStringTag.of("World!") + )); + assertThat( + LinListTag.of(LinTagType.stringTag(), List.of( + LinStringTag.of("Hello"), + LinStringTag.of("Goodbye...") + )) + ).isEqualTo(initial.transformTag(1, s -> LinStringTag.of("Goodbye..."))); + } + @Test void emptyImplementation() { var empty = LinListTag.empty(LinTagType.stringTag()); diff --git a/tree/src/test/java/org/enginehub/linbus/tree/NestedTransformShowcaseTest.java b/tree/src/test/java/org/enginehub/linbus/tree/NestedTransformShowcaseTest.java new file mode 100644 index 0000000..ab4aebc --- /dev/null +++ b/tree/src/test/java/org/enginehub/linbus/tree/NestedTransformShowcaseTest.java @@ -0,0 +1,29 @@ +package org.enginehub.linbus.tree; + +import org.junit.jupiter.api.Test; + +public class NestedTransformShowcaseTest { + @Test + void transformSchematicMetadata() { + LinRootEntry root = new LinRootEntry( + "", + LinCompoundTag.builder() + .put("Schematic", LinCompoundTag.builder() + .put("Metadata", LinCompoundTag.builder() + .put("Name", LinStringTag.of("My Schematic")) + .put("Author", LinStringTag.of("Linbus")) + .build()) + .build()) + .build() + ); + LinRootEntry withNewName = root.transformValue(v -> + v.transformTag("Schematic", LinTagType.compoundTag(), schematic -> + schematic.transformTag("Metadata", LinTagType.compoundTag(), metadata -> + metadata.transformTag("Name", LinTagType.stringTag(), name -> + LinStringTag.of("My New Schematic") + ) + ) + ) + ); + } +}