Skip to content
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
12 changes: 11 additions & 1 deletion Sources/Flow/ActionHandler/ActionHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,17 @@ import Foundation
///
/// The Facade pattern here is a feature, not a code smell. It provides clean abstraction
/// and hides implementation complexity from users while maintaining full testability.
public final class ActionHandler<Action, State, ActionResult: Sendable> {
///
/// ## Type Constraints
///
/// Type parameters are constrained to match Feature protocol requirements:
/// - `Action: Sendable` ensures safe concurrent action dispatching
/// - `State: AnyObject` ensures reference semantics for direct state mutation
/// - `ActionResult: Sendable` ensures safe concurrent result handling
///
/// These constraints prevent common errors like using value-type State (which wouldn't
/// support mutation) or non-Sendable actions (which could cause data races).
public final class ActionHandler<Action: Sendable, State: AnyObject, ActionResult: Sendable> {
private let processor: ActionProcessor<Action, State, ActionResult>

/// Creates a ActionHandler with the given action processing logic.
Expand Down
11 changes: 9 additions & 2 deletions Sources/Flow/ActionHandler/ActionProcessor.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Foundation

/// Action execution closure that mutates state and returns a task.
public typealias ActionExecution<Action, State, ActionResult> =
///
/// - Note: Type constraints match Feature protocol requirements to ensure consistency.
public typealias ActionExecution<Action: Sendable, State: AnyObject, ActionResult: Sendable> =
@MainActor (Action, State) async ->
ActionTask<Action, State, ActionResult>

Expand All @@ -25,7 +27,12 @@ public typealias StateErrorHandler<State> = (Error, State) -> Void
/// .use(LoggingMiddleware())
/// .onError { error, state in state.errorMessage = "\(error)" }
/// ```
public final class ActionProcessor<Action, State, ActionResult: Sendable> {
///
/// - Note: Type constraints match Feature protocol requirements:
/// - `Action: Sendable` for safe concurrency across tasks
/// - `State: AnyObject` ensures reference semantics for state mutation
/// - `ActionResult: Sendable` for safe concurrency of operation results
public final class ActionProcessor<Action: Sendable, State: AnyObject, ActionResult: Sendable> {
private let baseExecution: ActionExecution<Action, State, ActionResult>
private let errorHandler: StateErrorHandler<State>?
private let middlewareManager: MiddlewareManager<Action, State>
Expand Down
Loading