From 1d9ecb36199c95f3b5d22f60cb9127cd3ebf6d69 Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Thu, 23 Apr 2026 00:04:04 -0600 Subject: [PATCH 1/2] Revert "chore: Remove AsyncCollections dependency" This reverts commit 12b481e10848a6da6c0a6ad37b2bd0b1c87ea941. --- Benchmarks/Package.resolved | 12 ++++++++++-- Package.resolved | 11 ++++++++++- Package.swift | 2 ++ Sources/AsyncDataLoader/DataLoader.swift | 17 +++-------------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Benchmarks/Package.resolved b/Benchmarks/Package.resolved index e66137d..ff8ee56 100644 --- a/Benchmarks/Package.resolved +++ b/Benchmarks/Package.resolved @@ -1,6 +1,14 @@ { - "originHash" : "291df3327aad87228cf28f3cc39ec8b92e332c285db9b81b29cb92cb71d46837", "pins" : [ + { + "identity" : "async-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/adam-fowler/async-collections", + "state" : { + "revision" : "726af96095a19df6b8053ddbaed0a727aa70ccb2", + "version" : "0.1.0" + } + }, { "identity" : "hdrhistogram-swift", "kind" : "remoteSourceControl", @@ -101,5 +109,5 @@ } } ], - "version" : 3 + "version" : 2 } diff --git a/Package.resolved b/Package.resolved index db677ca..1c1dc60 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "cd234e013443e6dda35a41eb3c534540f5fa8abb6b1146f8037e768f237caa39", + "originHash" : "34ed11cdeebef1b2864a6db79a150ffe000d97cca7e36c30e30939d14f609619", "pins" : [ + { + "identity" : "async-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/adam-fowler/async-collections", + "state" : { + "revision" : "726af96095a19df6b8053ddbaed0a727aa70ccb2", + "version" : "0.1.0" + } + }, { "identity" : "swift-algorithms", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 92b2b32..67bd8e7 100644 --- a/Package.swift +++ b/Package.swift @@ -12,6 +12,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-algorithms.git", from: "1.0.0"), + .package(url: "https://github.com/adam-fowler/async-collections", from: "0.0.1"), .package(url: "https://github.com/apple/swift-nio.git", from: "2.84.0"), ], targets: [ @@ -26,6 +27,7 @@ let package = Package( name: "AsyncDataLoader", dependencies: [ .product(name: "Algorithms", package: "swift-algorithms"), + .product(name: "AsyncCollections", package: "async-collections"), ] ), .testTarget( diff --git a/Sources/AsyncDataLoader/DataLoader.swift b/Sources/AsyncDataLoader/DataLoader.swift index 4a40360..5ee591f 100644 --- a/Sources/AsyncDataLoader/DataLoader.swift +++ b/Sources/AsyncDataLoader/DataLoader.swift @@ -1,4 +1,5 @@ import Algorithms +import AsyncCollections public enum DataLoaderValue: Sendable { case success(T) @@ -116,19 +117,7 @@ public actor DataLoader { return [] } - // This buffer pointer allows us to initialize a pre-sized non-nullable list - // that we can populate by index as `load` results stream in asyncronously - let buffer = UnsafeMutableBufferPointer.allocate(capacity: keys.count) - try await withThrowingTaskGroup { group in - for (index, element) in keys.enumerated() { - group.addTask { - let result = try await self.load(key: element) - buffer[index] = result - } - } - try await group.waitForAll() - } - return Array(buffer) + return try await keys.concurrentMap { try await self.load(key: $0) } } /// Clears the value at `key` from the cache, if it exists. Returns itself for @@ -184,7 +173,7 @@ public actor DataLoader { // If a maxBatchSize was provided and the queue is longer, then segment the // queue into multiple batches, otherwise treat the queue as a single batch. if let maxBatchSize = options.maxBatchSize, maxBatchSize > 0, maxBatchSize < batch.count { - for slicedBatch in batch.chunks(ofCount: maxBatchSize) { + try await batch.chunks(ofCount: maxBatchSize).asyncForEach { slicedBatch in try await self.executeBatch(batch: Array(slicedBatch)) } } else { From 77a5166bc3d78632f01ddc61fcb533667cb8863a Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Thu, 23 Apr 2026 00:12:25 -0600 Subject: [PATCH 2/2] chore: Simplifies `execute` to use a standard for loop --- Sources/AsyncDataLoader/DataLoader.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/AsyncDataLoader/DataLoader.swift b/Sources/AsyncDataLoader/DataLoader.swift index 5ee591f..dad898d 100644 --- a/Sources/AsyncDataLoader/DataLoader.swift +++ b/Sources/AsyncDataLoader/DataLoader.swift @@ -173,7 +173,7 @@ public actor DataLoader { // If a maxBatchSize was provided and the queue is longer, then segment the // queue into multiple batches, otherwise treat the queue as a single batch. if let maxBatchSize = options.maxBatchSize, maxBatchSize > 0, maxBatchSize < batch.count { - try await batch.chunks(ofCount: maxBatchSize).asyncForEach { slicedBatch in + for slicedBatch in batch.chunks(ofCount: maxBatchSize) { try await self.executeBatch(batch: Array(slicedBatch)) } } else {