Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nbt: ListBinaryTag.add(Iterable) #248

Merged
merged 1 commit into from
Dec 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
kashike marked this conversation as resolved.
Show resolved Hide resolved
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);
}