From 42d8c30f88fe655c9117403f6473f75ea419581b Mon Sep 17 00:00:00 2001 From: Hiroshi Kimura Date: Sat, 11 Nov 2023 02:54:18 +0900 Subject: [PATCH] Refine AsyncStore (#452) --- Sources/Verge/Store/IsolatedStore.swift | 71 +++++++++++++------ .../Isolated/IsolatedStoreTests.swift | 4 +- Tests/VergeTests/TransactionTests.swift | 2 +- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/Sources/Verge/Store/IsolatedStore.swift b/Sources/Verge/Store/IsolatedStore.swift index fa3daa6674..e5002a6f64 100644 --- a/Sources/Verge/Store/IsolatedStore.swift +++ b/Sources/Verge/Store/IsolatedStore.swift @@ -154,24 +154,49 @@ public final class AsyncStore: DerivedMaking, Sendab self.backingStore = .init(initialState: initialState, storeOperation: .atomic(.init()), logger: nil, sanitizer: nil) } - public func backgroundCommit( - mutation: (inout InoutRef) throws -> Result + public func commit( + mutation: @Sendable (inout InoutRef) throws -> Result ) async rethrows -> Result { - try await writer.perform { _ in try backingStore._receive(mutation: { state, _ in try mutation(&state) }) } - } - public func backgroundCommit( - mutation: (inout InoutRef, inout Transaction) throws -> Result + public func commit( + mutation: @Sendable (inout InoutRef, inout Transaction) throws -> Result ) async rethrows -> Result { - try await writer.perform { _ in try backingStore._receive(mutation: mutation) } + } + + /** + Adds an asynchronous task to perform. + + Use this function to perform an asynchronous task with a lifetime that matches that of this store. + If this store is deallocated ealier than the given task finished, that asynchronous task will be cancelled. + + Carefully use this function - If the task retains this store, it will continue to live until the task is finished. + + - Parameters: + - key: + - mode: + - priority: + - action + - Returns: A Task for tracking given async operation's completion. + */ + @discardableResult + public func task( + key: ConcurrencyTaskManager.TaskKey = .distinct(), + mode: ConcurrencyTaskManager.TaskManagerActor.Mode = .dropCurrent, + priority: TaskPriority = .userInitiated, + @_inheritActorContext _ action: @Sendable @escaping () async throws -> Return + ) -> Task { + backingStore.task(key: key, mode: mode, priority: priority, action) + } + public func add(middleware: some StoreMiddlewareType) { + backingStore.add(middleware: middleware) } /// Send activity @@ -413,12 +438,12 @@ public protocol AsyncStoreDriverType { var store: AsyncStore { get } var scope: WritableKeyPath { get } - func backgroundCommit( - mutation: (inout InoutRef) throws -> Result + func commit( + mutation: @Sendable (inout InoutRef) throws -> Result ) async rethrows -> Result - func backgroundCommit( - mutation: (inout InoutRef, inout Transaction) throws -> Result + func commit( + mutation: @Sendable (inout InoutRef, inout Transaction) throws -> Result ) async rethrows -> Result } @@ -446,11 +471,11 @@ extension AsyncStoreDriverType { /// Run Mutation that created inline /// /// Throwable - public func backgroundCommit( - mutation: (inout InoutRef) throws -> Result + public func commit( + mutation: @Sendable (inout InoutRef) throws -> Result ) async rethrows -> Result { - return try await store.backgroundCommit { ref in + return try await store.commit { ref in try ref.map(keyPath: scope, perform: mutation) } @@ -459,11 +484,11 @@ extension AsyncStoreDriverType { /// Run Mutation that created inline /// /// Throwable - public func backgroundCommit( - mutation: (inout InoutRef, inout Transaction) throws -> Result + public func commit( + mutation: @Sendable (inout InoutRef, inout Transaction) throws -> Result ) async rethrows -> Result { - return try await store.backgroundCommit { ref, transaction in + return try await store.commit { ref, transaction in try ref.map(keyPath: scope, perform: { try mutation(&$0, &transaction) }) @@ -522,22 +547,22 @@ extension AsyncStoreDriverType where Scope == State { /// Run Mutation that created inline /// /// Throwable - public func backgroundCommit( - mutation: (inout InoutRef) throws -> Result + public func commit( + mutation: @Sendable (inout InoutRef) throws -> Result ) async rethrows -> Result { - return try await store.backgroundCommit(mutation: mutation) + return try await store.commit(mutation: mutation) } /// Run Mutation that created inline /// /// Throwable - public func backgroundCommit( - mutation: (inout InoutRef, inout Transaction) throws -> Result + public func commit( + mutation: @Sendable (inout InoutRef, inout Transaction) throws -> Result ) async rethrows -> Result { - return try await store.backgroundCommit(mutation: mutation) + return try await store.commit(mutation: mutation) } } diff --git a/Tests/VergeTests/Isolated/IsolatedStoreTests.swift b/Tests/VergeTests/Isolated/IsolatedStoreTests.swift index 9abe0f5a6e..1460278d2b 100644 --- a/Tests/VergeTests/Isolated/IsolatedStoreTests.swift +++ b/Tests/VergeTests/Isolated/IsolatedStoreTests.swift @@ -117,7 +117,7 @@ final class ActorIsolatedStoreTests: XCTestCase { XCTAssertEqual(store.state.count, 0) - await store.backgroundCommit { + await store.commit { $0.count = 1 } @@ -131,7 +131,7 @@ final class ActorIsolatedStoreTests: XCTestCase { XCTAssertEqual(store.state.count, 0) - await store.backgroundCommit { + await store.commit { $0.count = 1 } diff --git a/Tests/VergeTests/TransactionTests.swift b/Tests/VergeTests/TransactionTests.swift index fe7a967319..e32266c13a 100644 --- a/Tests/VergeTests/TransactionTests.swift +++ b/Tests/VergeTests/TransactionTests.swift @@ -13,7 +13,7 @@ final class TransactionTests: XCTestCase { let store = AsyncStore(initialState: .init()) - await store.backgroundCommit { + await store.commit { $0.markAsModified() $1[MyKey.self] = "first commit" }