Skip to content

Nest Send<Action> as Effect<Action>.Send #1911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 63 additions & 61 deletions Sources/ComposableArchitecture/Effect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public struct EffectPublisher<Action, Failure: Error> {
enum Operation {
case none
case publisher(AnyPublisher<Action, Failure>)
case run(TaskPriority? = nil, @Sendable (Send<Action>) async -> Void)
case run(TaskPriority? = nil, @Sendable (Send) async -> Void)
}

@usableFromInline
Expand Down Expand Up @@ -253,8 +253,8 @@ extension EffectPublisher where Failure == Never {
/// - Returns: An effect wrapping the given asynchronous work.
public static func run(
priority: TaskPriority? = nil,
operation: @escaping @Sendable (Send<Action>) async throws -> Void,
catch handler: (@Sendable (Error, Send<Action>) async -> Void)? = nil,
operation: @escaping @Sendable (Send) async throws -> Void,
catch handler: (@Sendable (Error, Send) async -> Void)? = nil,
file: StaticString = #file,
fileID: StaticString = #fileID,
line: UInt = #line
Expand Down Expand Up @@ -353,68 +353,70 @@ extension EffectPublisher where Failure == Never {
}
}

/// A type that can send actions back into the system when used from
/// ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)``.
///
/// This type implements [`callAsFunction`][callAsFunction] so that you invoke it as a function
/// rather than calling methods on it:
///
/// ```swift
/// return .run { send in
/// send(.started)
/// defer { send(.finished) }
/// for await event in self.events {
/// send(.event(event))
/// }
/// }
/// ```
///
/// You can also send actions with animation:
///
/// ```swift
/// send(.started, animation: .spring())
/// defer { send(.finished, animation: .default) }
/// ```
///
/// See ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)`` for more information on how to
/// use this value to construct effects that can emit any number of times in an asynchronous
/// context.
///
/// [callAsFunction]: https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID622
@MainActor
public struct Send<Action> {
public let send: @MainActor (Action) -> Void
extension EffectTask {
/// A type that can send actions back into the system when used from
/// ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)``.
///
/// This type implements [`callAsFunction`][callAsFunction] so that you invoke it as a function
/// rather than calling methods on it:
///
/// ```swift
/// return .run { send in
/// send(.started)
/// defer { send(.finished) }
/// for await event in self.events {
/// send(.event(event))
/// }
/// }
/// ```
///
/// You can also send actions with animation:
///
/// ```swift
/// send(.started, animation: .spring())
/// defer { send(.finished, animation: .default) }
/// ```
///
/// See ``EffectPublisher/run(priority:operation:catch:file:fileID:line:)`` for more information on how to
/// use this value to construct effects that can emit any number of times in an asynchronous
/// context.
///
/// [callAsFunction]: https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID622
@MainActor
public struct Send {
public let send: @MainActor (Action) -> Void

public init(send: @escaping @MainActor (Action) -> Void) {
self.send = send
}
public init(send: @escaping @MainActor (Action) -> Void) {
self.send = send
}

/// Sends an action back into the system from an effect.
///
/// - Parameter action: An action.
public func callAsFunction(_ action: Action) {
guard !Task.isCancelled else { return }
self.send(action)
}
/// Sends an action back into the system from an effect.
///
/// - Parameter action: An action.
public func callAsFunction(_ action: Action) {
guard !Task.isCancelled else { return }
self.send(action)
}

/// Sends an action back into the system from an effect with animation.
///
/// - Parameters:
/// - action: An action.
/// - animation: An animation.
public func callAsFunction(_ action: Action, animation: Animation?) {
callAsFunction(action, transaction: Transaction(animation: animation))
}
/// Sends an action back into the system from an effect with animation.
///
/// - Parameters:
/// - action: An action.
/// - animation: An animation.
public func callAsFunction(_ action: Action, animation: Animation?) {
callAsFunction(action, transaction: Transaction(animation: animation))
}

/// Sends an action back into the system from an effect with transaction.
///
/// - Parameters:
/// - action: An action.
/// - transaction: A transaction.
public func callAsFunction(_ action: Action, transaction: Transaction) {
guard !Task.isCancelled else { return }
withTransaction(transaction) {
self(action)
/// Sends an action back into the system from an effect with transaction.
///
/// - Parameters:
/// - action: An action.
/// - transaction: A transaction.
public func callAsFunction(_ action: Action, transaction: Transaction) {
guard !Task.isCancelled else { return }
withTransaction(transaction) {
self(action)
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions Sources/ComposableArchitecture/Internal/Deprecations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import Combine
import SwiftUI
import XCTestDynamicOverlay

// MARK: - Deprecated after 0.50.4

@available(
*,
deprecated,
message: "Use 'EffectTask<Action>.Send' instead."
)
public typealias Send<Action> = EffectTask<Action>.Send

// MARK: - Deprecated after 0.49.2

@available(
Expand Down
2 changes: 1 addition & 1 deletion Sources/ComposableArchitecture/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ public final class Store<State, Action> {
tasks.wrappedValue.append(
Task(priority: priority) {
await operation(
Send {
EffectTask<Action>.Send {
if let task = self.send($0, originatingFrom: action) {
tasks.wrappedValue.append(task)
}
Expand Down