AsyncTabCompleteEvent

Let plugins be able to control tab completion of commands and chat async.

This will be useful for frameworks like ACF so we can define async safe completion handlers,
and avoid going to main for tab completions.

Especially useful if you need to query a database in order to obtain the results for tab
completion, such as offline players.

Also Enforces mutability of the existing TabCompleteEvent.

Co-authored-by: Aikar <aikar@aikar.co>
This commit is contained in:
Jason Penilla
2017-11-26 13:17:09 -05:00
parent 8306cc5b4f
commit 7132df4810
4 changed files with 537 additions and 2 deletions

View File

@@ -0,0 +1,172 @@
package io.papermc.paper.util;
import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.function.Function;
import java.util.function.Predicate;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Modified version of the Guava class with the same name to support add operations.
*
* @param <F> backing list element type
* @param <T> transformed list element type
*/
@NullMarked
@ApiStatus.Internal
public final class TransformingRandomAccessList<F, T> extends AbstractList<T> implements RandomAccess {
final List<F> fromList;
final Function<? super F, ? extends T> toFunction;
final Function<? super T, ? extends F> fromFunction;
/**
* Create a new {@link TransformingRandomAccessList}.
*
* @param fromList backing list
* @param toFunction function mapping backing list element type to transformed list element type
* @param fromFunction function mapping transformed list element type to backing list element type
*/
public TransformingRandomAccessList(
final List<F> fromList,
final Function<? super F, ? extends T> toFunction,
final Function<? super T, ? extends F> fromFunction
) {
this.fromList = checkNotNull(fromList);
this.toFunction = checkNotNull(toFunction);
this.fromFunction = checkNotNull(fromFunction);
}
@Override
public void clear() {
this.fromList.clear();
}
@Override
public T get(final int index) {
return this.toFunction.apply(this.fromList.get(index));
}
@Override
public Iterator<T> iterator() {
return this.listIterator();
}
@Override
public ListIterator<T> listIterator(final int index) {
return new TransformedListIterator<>(this.fromList.listIterator(index)) {
@Override
T transform(final F from) {
return TransformingRandomAccessList.this.toFunction.apply(from);
}
@Override
F transformBack(final T from) {
return TransformingRandomAccessList.this.fromFunction.apply(from);
}
};
}
@Override
public boolean isEmpty() {
return this.fromList.isEmpty();
}
@Override
public boolean removeIf(final Predicate<? super T> filter) {
checkNotNull(filter);
return this.fromList.removeIf(element -> filter.test(this.toFunction.apply(element)));
}
@Override
public T remove(final int index) {
return this.toFunction.apply(this.fromList.remove(index));
}
@Override
public int size() {
return this.fromList.size();
}
@Override
public T set(final int i, final T t) {
return this.toFunction.apply(this.fromList.set(i, this.fromFunction.apply(t)));
}
@Override
public void add(final int i, final T t) {
this.fromList.add(i, this.fromFunction.apply(t));
}
abstract static class TransformedListIterator<F, T> implements ListIterator<T>, Iterator<T> {
final Iterator<F> backingIterator;
TransformedListIterator(final ListIterator<F> backingIterator) {
this.backingIterator = checkNotNull((Iterator<F>) backingIterator);
}
private ListIterator<F> backingIterator() {
return cast(this.backingIterator);
}
static <A> ListIterator<A> cast(final Iterator<A> iterator) {
return (ListIterator<A>) iterator;
}
@Override
public final boolean hasPrevious() {
return this.backingIterator().hasPrevious();
}
@Override
public final T previous() {
return this.transform(this.backingIterator().previous());
}
@Override
public final int nextIndex() {
return this.backingIterator().nextIndex();
}
@Override
public final int previousIndex() {
return this.backingIterator().previousIndex();
}
@Override
public void set(final T element) {
this.backingIterator().set(this.transformBack(element));
}
@Override
public void add(final T element) {
this.backingIterator().add(this.transformBack(element));
}
abstract T transform(F from);
abstract F transformBack(T to);
@Override
public final boolean hasNext() {
return this.backingIterator.hasNext();
}
@Override
public final T next() {
return this.transform(this.backingIterator.next());
}
@Override
public final void remove() {
this.backingIterator.remove();
}
}
}