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;
+ }
+ };
+ }
}