Skip to content

Commit

Permalink
nbt: ListBinaryTag from(Iterable) and add(Iterable)
Browse files Browse the repository at this point in the history
  • Loading branch information
kashike committed Dec 16, 2020
1 parent 50482cf commit 409b712
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 28 deletions.
21 changes: 17 additions & 4 deletions nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ public interface ListBinaryTag extends ListTagSetter<ListBinaryTag, BinaryTag>,
return ListBinaryTagImpl.EMPTY;
}

/**
* Creates a list tag from {@code tags}.
*
* <p>The {@link #elementType() element type} of the returned list tag is determined from {@code tags}.</p>
*
* @return a list tag
* @throws IllegalArgumentException if {@code tags} has different tag types within
* @since 4.4.0
*/
static @NonNull ListBinaryTag from(final @NonNull Iterable<? extends BinaryTag> tags) {
return builder().add(tags).build();
}

/**
* Creates a builder.
*
Expand Down Expand Up @@ -130,21 +143,21 @@ public interface ListBinaryTag extends ListTagSetter<ListBinaryTag, BinaryTag>,
*
* @param index the index
* @param tag the tag
* @param removedConsumer a consumer which receives the tag being removed at index {@code index}
* @param removed a consumer which receives the tag being removed at index {@code index}
* @return a list tag
* @since 4.0.0
*/
@NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag tag, final @Nullable Consumer<BinaryTag> removedConsumer);
@NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag tag, final @Nullable Consumer<? super BinaryTag> removed);

/**
* Removes the tag at index {@code index}, optionally providing {@code removedConsumer} with the tag previously at index {@code index}.
*
* @param index the index
* @param removedConsumer a consumer which receives the tag being removed at index {@code index}
* @param removed a consumer which receives the tag being removed at index {@code index}
* @return a list tag
* @since 4.0.0
*/
@NonNull ListBinaryTag remove(final int index, final @Nullable Consumer<BinaryTag> removedConsumer);
@NonNull ListBinaryTag remove(final int index, final @Nullable Consumer<? super BinaryTag> removed);

/**
* Gets a byte.
Expand Down
61 changes: 43 additions & 18 deletions nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTagImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package net.kyori.adventure.nbt;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
Expand All @@ -43,7 +44,7 @@ final class ListBinaryTagImpl extends AbstractBinaryTag implements ListBinaryTag
private final int hashCode;

ListBinaryTagImpl(final BinaryTagType<? extends BinaryTag> elementType, final List<BinaryTag> tags) {
this.tags = tags;
this.tags = Collections.unmodifiableList(tags);
this.elementType = elementType;
this.hashCode = tags.hashCode();
}
Expand All @@ -64,34 +65,45 @@ public int size() {
}

@Override
public @NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag newTag, final @Nullable Consumer<BinaryTag> removedConsumer) {
public @NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag newTag, final @Nullable Consumer<? super BinaryTag> removed) {
return this.edit(tags -> {
final BinaryTag oldTag = tags.set(index, newTag);
if(removedConsumer != null) {
removedConsumer.accept(oldTag);
if(removed != null) {
removed.accept(oldTag);
}
}, newTag.type());
}

@Override
public @NonNull ListBinaryTag remove(final int index, final @Nullable Consumer<BinaryTag> removedConsumer) {
public @NonNull ListBinaryTag remove(final int index, final @Nullable Consumer<? super BinaryTag> removed) {
return this.edit(tags -> {
final BinaryTag tag = tags.remove(index);
if(removedConsumer != null) {
removedConsumer.accept(tag);
final BinaryTag oldTag = tags.remove(index);
if(removed != null) {
removed.accept(oldTag);
}
}, null);
}

@Override
public @NonNull ListBinaryTag add(final BinaryTag tag) {
noAddEnd(tag);
if(this.elementType != BinaryTagTypes.END) {
mustBeSameType(tag, this.elementType);
}
return this.edit(tags -> tags.add(tag), tag.type());
}

@Override
public @NonNull ListBinaryTag add(final Iterable<? extends BinaryTag> tagsToAdd) {
if(tagsToAdd instanceof Collection<?> && ((Collection<?>) tagsToAdd).isEmpty()) {
return this;
}
final BinaryTagType<?> type = ListBinaryTagImpl.mustBeSameType(tagsToAdd);
return this.edit(tags -> {
noAddEnd(tag);
if(this.elementType != BinaryTagTypes.END) {
mustBeSameType(tag, this.elementType);
for(final BinaryTag tag : tagsToAdd) {
tags.add(tag);
}
tags.add(tag);
}, tag.type());
}, type);
}

// An end tag cannot be an element in a list tag
Expand All @@ -101,22 +113,35 @@ static void noAddEnd(final BinaryTag tag) {
}
}

// Cannot have different element types in a list tag
static BinaryTagType<?> mustBeSameType(final Iterable<? extends BinaryTag> tags) {
BinaryTagType<?> type = null;
for(final BinaryTag tag : tags) {
if(type == null) {
type = tag.type();
} else {
mustBeSameType(tag, type);
}
}
return type;
}

// Cannot have different element types in a list tag
static void mustBeSameType(final BinaryTag tag, final BinaryTagType<? extends BinaryTag> type) {
if(tag.type() != type) {
throw new IllegalArgumentException(String.format("Trying to add tag of type %s to list of %s", tag.type(), type));
}
}

private ListBinaryTag edit(final Consumer<List<BinaryTag>> consumer, final @Nullable BinaryTagType<? extends BinaryTag> maybeType) {
private ListBinaryTag edit(final Consumer<List<BinaryTag>> consumer, final @Nullable BinaryTagType<? extends BinaryTag> maybeElementType) {
final List<BinaryTag> tags = new ArrayList<>(this.tags);
consumer.accept(tags);
BinaryTagType<? extends BinaryTag> type = this.elementType;
BinaryTagType<? extends BinaryTag> elementType = this.elementType;
// set the type if it has not yet been set
if(maybeType != null && type == BinaryTagTypes.END) {
type = maybeType;
if(maybeElementType != null && elementType == BinaryTagTypes.END) {
elementType = maybeElementType;
}
return new ListBinaryTagImpl(type, tags);
return new ListBinaryTagImpl(elementType, tags);
}

@Override
Expand Down
20 changes: 14 additions & 6 deletions nbt/src/main/java/net/kyori/adventure/nbt/ListTagBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,43 @@

final class ListTagBuilder<T extends BinaryTag> implements ListBinaryTag.Builder<T> {
private @MonotonicNonNull List<BinaryTag> tags;
private BinaryTagType<? extends BinaryTag> type;
private BinaryTagType<? extends BinaryTag> elementType;

ListTagBuilder() {
this(BinaryTagTypes.END);
}

ListTagBuilder(final BinaryTagType<? extends BinaryTag> type) {
this.type = type;
this.elementType = type;
}

@Override
public ListBinaryTag.@NonNull Builder<T> add(final BinaryTag tag) {
ListBinaryTagImpl.noAddEnd(tag);
// set the type if it has not yet been set
if(this.type == BinaryTagTypes.END) {
this.type = tag.type();
if(this.elementType == BinaryTagTypes.END) {
this.elementType = tag.type();
}
// check after changing from an empty tag
ListBinaryTagImpl.mustBeSameType(tag, this.type);
ListBinaryTagImpl.mustBeSameType(tag, this.elementType);
if(this.tags == null) {
this.tags = new ArrayList<>();
}
this.tags.add(tag);
return this;
}

@Override
public ListBinaryTag.@NonNull Builder<T> add(final Iterable<? extends T> tagsToAdd) {
for(final T tag : tagsToAdd) {
this.add(tag);
}
return this;
}

@Override
public @NonNull ListBinaryTag build() {
if(this.tags == null) return ListBinaryTag.empty();
return new ListBinaryTagImpl(this.type, new ArrayList<>(this.tags));
return new ListBinaryTagImpl(this.elementType, new ArrayList<>(this.tags));
}
}
9 changes: 9 additions & 0 deletions nbt/src/main/java/net/kyori/adventure/nbt/ListTagSetter.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,13 @@ public interface ListTagSetter<R, T extends BinaryTag> {
* @since 4.0.0
*/
@NonNull R add(final T tag);

/**
* Adds multiple tags.
*
* @param tags the tags
* @return a list tag
* @since 4.4.0
*/
@NonNull R add(final Iterable<? extends T> tags);
}

0 comments on commit 409b712

Please sign in to comment.