diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/SlottedStorage.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/SlottedStorage.java index c8d2133a89c..cbd136682fb 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/SlottedStorage.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/SlottedStorage.java @@ -24,8 +24,10 @@ /** * A {@link Storage} implementation made of indexed slots. - * Please note that some storages may not implement this interface: - * checking whether a storage is slotted can be done using {@code instanceof}. + * + *

Please note that some storages may not implement this interface. + * It is up to the storage implementation to decide whether to implement this interface or not. + * Checking whether a storage is slotted can be done using {@code instanceof}. * * @param The type of the stored resources. * diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/Storage.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/Storage.java index 99be6f0407e..727182a84ee 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/Storage.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/Storage.java @@ -18,7 +18,6 @@ import java.util.Iterator; -import com.google.common.collect.Iterators; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -159,10 +158,17 @@ default long simulateExtract(T resource, long maxAmount, @Nullable TransactionCo *

This can provide a large performance benefit over {@link #iterator()} if the caller is only interested in non-empty views, * for example because it is trying to extract resources from the storage. * + *

This function should only be overridden if the storage is able to provide an optimized iterator over non-empty views, + * for example because it is keeping an index of non-empty views. + * Otherwise, the default implementation simply calls {@link #iterator()} and filters out empty views. + * + *

When implementing this function, note that the guarantees of {@link #iterator()} still apply. + * In particular, {@link #insert} and {@link #extract} may be called safely during iteration. + * * @return An iterator over the non-empty views of this storage. Calling remove on the iterator is not allowed. */ default Iterator> nonEmptyIterator() { - return Iterators.filter(iterator(), view -> view.getAmount() > 0 && !view.isResourceBlank()); + return TransferApiImpl.filterEmptyViews(iterator()); } /** diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleSlotStorage.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleSlotStorage.java index 30e12474585..1b53cf330b6 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleSlotStorage.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleSlotStorage.java @@ -20,7 +20,7 @@ import org.jetbrains.annotations.ApiStatus; -import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.fabricmc.fabric.api.transfer.v1.storage.SlottedStorage; import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; import net.fabricmc.fabric.impl.transfer.TransferApiImpl; @@ -34,9 +34,23 @@ * The transfer API is a complex addition, and we want to be able to correct possible design mistakes. */ @ApiStatus.Experimental -public interface SingleSlotStorage extends Storage, StorageView { +public interface SingleSlotStorage extends SlottedStorage, StorageView { @Override default Iterator> iterator() { return TransferApiImpl.singletonIterator(this); } + + @Override + default int getSlotCount() { + return 1; + } + + @Override + default SingleSlotStorage getSlot(int slot) { + if (slot != 0) { + throw new IndexOutOfBoundsException("Slot " + slot + " does not exist in a single-slot storage."); + } + + return this; + } } diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java index 600c349171d..170194f8268 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java @@ -89,4 +89,40 @@ public T next() { } }; } + + public static Iterator> filterEmptyViews(Iterator> iterator) { + return new Iterator<>() { + StorageView next; + + { + findNext(); + } + + private void findNext() { + while (iterator.hasNext()) { + next = iterator.next(); + + if (next.getAmount() > 0 && !next.isResourceBlank()) { + return; + } + } + + next = null; + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public StorageView next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + return next; + } + }; + } }