Skip to content

Commit 91e2bea

Browse files
authored
Nest Send<Action> as Effect<Action>.Send (#1911)
1 parent 56a1e4b commit 91e2bea

File tree

3 files changed

+73
-62
lines changed

3 files changed

+73
-62
lines changed

Sources/ComposableArchitecture/Effect.swift

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public struct EffectPublisher<Action, Failure: Error> {
5757
enum Operation {
5858
case none
5959
case publisher(AnyPublisher<Action, Failure>)
60-
case run(TaskPriority? = nil, @Sendable (Send<Action>) async -> Void)
60+
case run(TaskPriority? = nil, @Sendable (Send) async -> Void)
6161
}
6262

6363
@usableFromInline
@@ -253,8 +253,8 @@ extension EffectPublisher where Failure == Never {
253253
/// - Returns: An effect wrapping the given asynchronous work.
254254
public static func run(
255255
priority: TaskPriority? = nil,
256-
operation: @escaping @Sendable (Send<Action>) async throws -> Void,
257-
catch handler: (@Sendable (Error, Send<Action>) async -> Void)? = nil,
256+
operation: @escaping @Sendable (Send) async throws -> Void,
257+
catch handler: (@Sendable (Error, Send) async -> Void)? = nil,
258258
file: StaticString = #file,
259259
fileID: StaticString = #fileID,
260260
line: UInt = #line
@@ -353,68 +353,70 @@ extension EffectPublisher where Failure == Never {
353353
}
354354
}
355355

356-
/// A type that can send actions back into the system when used from
357-
/// ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)``.
358-
///
359-
/// This type implements [`callAsFunction`][callAsFunction] so that you invoke it as a function
360-
/// rather than calling methods on it:
361-
///
362-
/// ```swift
363-
/// return .run { send in
364-
/// send(.started)
365-
/// defer { send(.finished) }
366-
/// for await event in self.events {
367-
/// send(.event(event))
368-
/// }
369-
/// }
370-
/// ```
371-
///
372-
/// You can also send actions with animation:
373-
///
374-
/// ```swift
375-
/// send(.started, animation: .spring())
376-
/// defer { send(.finished, animation: .default) }
377-
/// ```
378-
///
379-
/// See ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)`` for more information on how to
380-
/// use this value to construct effects that can emit any number of times in an asynchronous
381-
/// context.
382-
///
383-
/// [callAsFunction]: https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID622
384-
@MainActor
385-
public struct Send<Action> {
386-
public let send: @MainActor (Action) -> Void
356+
extension EffectTask {
357+
/// A type that can send actions back into the system when used from
358+
/// ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)``.
359+
///
360+
/// This type implements [`callAsFunction`][callAsFunction] so that you invoke it as a function
361+
/// rather than calling methods on it:
362+
///
363+
/// ```swift
364+
/// return .run { send in
365+
/// send(.started)
366+
/// defer { send(.finished) }
367+
/// for await event in self.events {
368+
/// send(.event(event))
369+
/// }
370+
/// }
371+
/// ```
372+
///
373+
/// You can also send actions with animation:
374+
///
375+
/// ```swift
376+
/// send(.started, animation: .spring())
377+
/// defer { send(.finished, animation: .default) }
378+
/// ```
379+
///
380+
/// See ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)`` for more information on how to
381+
/// use this value to construct effects that can emit any number of times in an asynchronous
382+
/// context.
383+
///
384+
/// [callAsFunction]: https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID622
385+
@MainActor
386+
public struct Send {
387+
public let send: @MainActor (Action) -> Void
387388

388-
public init(send: @escaping @MainActor (Action) -> Void) {
389-
self.send = send
390-
}
389+
public init(send: @escaping @MainActor (Action) -> Void) {
390+
self.send = send
391+
}
391392

392-
/// Sends an action back into the system from an effect.
393-
///
394-
/// - Parameter action: An action.
395-
public func callAsFunction(_ action: Action) {
396-
guard !Task.isCancelled else { return }
397-
self.send(action)
398-
}
393+
/// Sends an action back into the system from an effect.
394+
///
395+
/// - Parameter action: An action.
396+
public func callAsFunction(_ action: Action) {
397+
guard !Task.isCancelled else { return }
398+
self.send(action)
399+
}
399400

400-
/// Sends an action back into the system from an effect with animation.
401-
///
402-
/// - Parameters:
403-
/// - action: An action.
404-
/// - animation: An animation.
405-
public func callAsFunction(_ action: Action, animation: Animation?) {
406-
callAsFunction(action, transaction: Transaction(animation: animation))
407-
}
401+
/// Sends an action back into the system from an effect with animation.
402+
///
403+
/// - Parameters:
404+
/// - action: An action.
405+
/// - animation: An animation.
406+
public func callAsFunction(_ action: Action, animation: Animation?) {
407+
callAsFunction(action, transaction: Transaction(animation: animation))
408+
}
408409

409-
/// Sends an action back into the system from an effect with transaction.
410-
///
411-
/// - Parameters:
412-
/// - action: An action.
413-
/// - transaction: A transaction.
414-
public func callAsFunction(_ action: Action, transaction: Transaction) {
415-
guard !Task.isCancelled else { return }
416-
withTransaction(transaction) {
417-
self(action)
410+
/// Sends an action back into the system from an effect with transaction.
411+
///
412+
/// - Parameters:
413+
/// - action: An action.
414+
/// - transaction: A transaction.
415+
public func callAsFunction(_ action: Action, transaction: Transaction) {
416+
guard !Task.isCancelled else { return }
417+
withTransaction(transaction) {
418+
self(action)
419+
}
418420
}
419421
}
420422
}

Sources/ComposableArchitecture/Internal/Deprecations.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ import Combine
33
import SwiftUI
44
import XCTestDynamicOverlay
55

6+
// MARK: - Deprecated after 0.50.4
7+
8+
@available(
9+
*,
10+
deprecated,
11+
message: "Use 'EffectTask<Action>.Send' instead."
12+
)
13+
public typealias Send<Action> = EffectTask<Action>.Send
14+
615
// MARK: - Deprecated after 0.49.2
716

817
@available(

Sources/ComposableArchitecture/Store.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ public final class Store<State, Action> {
419419
tasks.wrappedValue.append(
420420
Task(priority: priority) {
421421
await operation(
422-
Send {
422+
EffectTask<Action>.Send {
423423
if let task = self.send($0, originatingFrom: action) {
424424
tasks.wrappedValue.append(task)
425425
}

0 commit comments

Comments
 (0)