-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add asynchronous effect handling routes
- Loading branch information
Showing
2 changed files
with
649 additions
and
0 deletions.
There are no files selected for viewing
334 changes: 334 additions & 0 deletions
334
MobiusCore/Source/EffectHandlers/EffectRouterDSL+Concurrency.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
// Copyright 2019-2024 Spotify AB. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter { | ||
/// Routes the `Effect` to an asynchronous closure. | ||
/// | ||
/// - Parameter handler: An asynchronous closure receiving the `Effect`'s parameters as input. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping (EffectParameters) async -> Void) -> EffectRouter<Effect, Event> { | ||
to { parameters, _ in | ||
await handler(parameters) | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an asynchronous throwing closure. | ||
/// | ||
/// - Parameter handler: An asynchronous throwing closure receiving the `Effect`'s parameters as input. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping (EffectParameters) async throws -> Void) -> EffectRouter<Effect, Event> { | ||
to { parameters, _ in | ||
try await handler(parameters) | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter where EffectParameters == Void { | ||
/// Routes the `Effect` to an asynchronous closure. | ||
/// | ||
/// - Parameter handler: An asynchronous closure. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping () async -> Void) -> EffectRouter<Effect, Event> { | ||
to { _, _ in | ||
await handler() | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an asynchronous throwing closure. | ||
/// | ||
/// - Parameter handler: An asynchronous throwing closure. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping () async throws -> Void) -> EffectRouter<Effect, Event> { | ||
to { _, _ in | ||
try await handler() | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter { | ||
/// Routes the `Effect` to an asynchronous closure producing a single `Event`. | ||
/// | ||
/// - Parameter handler: An asynchronous closure receiving the `Effect`'s parameters as input and producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping (EffectParameters) async -> Event) -> EffectRouter<Effect, Event> { | ||
to { parameters, callback in | ||
await callback(handler(parameters)) | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an asynchronous throwing closure producing a single `Event`. | ||
/// | ||
/// - Parameter handler: An asynchronous throwing closure receiving the `Effect`'s parameters as input and producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping (EffectParameters) async throws -> Event) -> EffectRouter<Effect, Event> { | ||
to { parameters, callback in | ||
try await callback(handler(parameters)) | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter where EffectParameters == Void { | ||
/// Routes the `Effect` to an asynchronous closure producing a single `Event`. | ||
/// | ||
/// - Parameter handler: An asynchronous closure producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping () async -> Event) -> EffectRouter<Effect, Event> { | ||
to { _, callback in | ||
await callback(handler()) | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an asynchronous throwing closure producing a single `Event`. | ||
/// | ||
/// - Parameter handler: An asynchronous throwing closure producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to(_ handler: @escaping () async throws -> Event) -> EffectRouter<Effect, Event> { | ||
to { _, callback in | ||
try await callback(handler()) | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter { | ||
/// Routes the `Effect` to an asynchronous closure producing a sequence of `Event`s. | ||
/// | ||
/// - Parameter handler: An asynchronous closure receiving the `Effect`'s parameters as input and producing an `AsyncSequence` of `Event`s as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<S: AsyncSequence>( | ||
_ handler: @escaping (EffectParameters) async -> S | ||
) -> EffectRouter<Effect, Event> where S.Element == Event { | ||
to { parameters, callback in | ||
for try await output in await handler(parameters) { | ||
callback(output) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter where EffectParameters == Void { | ||
/// Routes the `Effect` to an asynchronous closure producing a sequence of `Event`s. | ||
/// | ||
/// - Parameter handler: An asynchronous closure producing an `AsyncSequence` of `Event`s as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<S: AsyncSequence>( | ||
_ handler: @escaping () async -> S | ||
) -> EffectRouter<Effect, Event> where S.Element == Event { | ||
to { _, callback in | ||
for try await output in await handler() { | ||
callback(output) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter { | ||
/// Routes the `Effect` to an `Actor`'s closure. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling closure. | ||
/// - Parameter handler: An isolated asynchronous closure receiving the `Effect`'s parameters as input. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> (EffectParameters) async -> Void | ||
) -> EffectRouter<Effect, Event> { | ||
to { parameters, _ in | ||
await handler(actor)(parameters) | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an `Actor`'s throwing closure. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure. | ||
/// - Parameter handler: An isolated asynchronous throwing closure receiving the `Effect`'s parameters as input. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
Check failure on line 162 in MobiusCore/Source/EffectHandlers/EffectRouterDSL+Concurrency.swift GitHub Actions / swiftlint
|
||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> (EffectParameters) async throws -> Void | ||
) -> EffectRouter<Effect, Event> { | ||
to { parameters, _ in | ||
try await handler(actor)(parameters) | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter where EffectParameters == Void { | ||
/// Routes the `Effect` to an `Actor`'s closure. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling closure. | ||
/// - Parameter handler: An isolated asynchronous closure. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> () async -> Void | ||
) -> EffectRouter<Effect, Event> { | ||
to { _, _ in | ||
await handler(actor)() | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an `Actor`'s closure. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure. | ||
/// - Parameter handler: An isolated asynchronous throwing closure. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
Check failure on line 193 in MobiusCore/Source/EffectHandlers/EffectRouterDSL+Concurrency.swift GitHub Actions / swiftlint
|
||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> () async throws -> Void | ||
) -> EffectRouter<Effect, Event> { | ||
to { _, _ in | ||
try await handler(actor)() | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter { | ||
/// Routes the `Effect` to an `Actor`'s closure producing a single `Event`. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling closure. | ||
/// - Parameter handler: An isolated asynchronous closure receiving the `Effect`'s parameters as input and producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> (EffectParameters) async -> Event | ||
) -> EffectRouter<Effect, Event> { | ||
to { parameters, callback in | ||
await callback(handler(actor)(parameters)) | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an `Actor`'s throwing closure producing a single `Event`. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure. | ||
/// - Parameter handler: An isolated asynchronous throwing closure receiving the `Effect`'s parameters as input and producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
Check failure on line 224 in MobiusCore/Source/EffectHandlers/EffectRouterDSL+Concurrency.swift GitHub Actions / swiftlint
|
||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> (EffectParameters) async throws -> Event | ||
) -> EffectRouter<Effect, Event> { | ||
to { parameters, callback in | ||
try await callback(handler(actor)(parameters)) | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter where EffectParameters == Void { | ||
/// Routes the `Effect` to an `Actor`'s closure producing a single `Event`. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling closure. | ||
/// - Parameter handler: An isolated asynchronous closure producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> () async -> Event | ||
) -> EffectRouter<Effect, Event> { | ||
to { _, callback in | ||
await callback(handler(actor)()) | ||
} | ||
} | ||
|
||
/// Routes the `Effect` to an `Actor`'s throwing closure producing a single `Event`. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure. | ||
/// - Parameter handler: An isolated asynchronous throwing closure producing a single `Event` as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor>( | ||
Check failure on line 255 in MobiusCore/Source/EffectHandlers/EffectRouterDSL+Concurrency.swift GitHub Actions / swiftlint
|
||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> () async throws -> Event | ||
) -> EffectRouter<Effect, Event> { | ||
to { _, callback in | ||
try await callback(handler(actor)()) | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter { | ||
/// Routes the `Effect` to an `Actor`'s closure producing a sequence of `Event`s. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling closure. | ||
/// - Parameter handler: An isolated asynchronous closure receiving the `Effect`'s parameters as input and producing an `AsyncSequence` of `Event`s as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor, S: AsyncSequence>( | ||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> (EffectParameters) async -> S | ||
) -> EffectRouter<Effect, Event> where S.Element == Event { | ||
to { parameters, callback in | ||
for try await output in await handler(actor)(parameters) { | ||
callback(output) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public extension _PartialEffectRouter where EffectParameters == Void { | ||
/// Routes the `Effect` to an `Actor`'s closure producing a sequence of `Event`s. | ||
/// | ||
/// - Parameter actor: An `Actor` providing the `Effect` handling closure. | ||
/// - Parameter handler: An isolated asynchronous closure producing an `AsyncSequence` of `Event`s as output. | ||
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`. | ||
func to<A: Actor, S: AsyncSequence>( | ||
_ actor: A, | ||
_ handler: @escaping (isolated A) -> () async -> S | ||
) -> EffectRouter<Effect, Event> where S.Element == Event { | ||
to { _, callback in | ||
for try await output in await handler(actor)() { | ||
callback(output) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
private extension _PartialEffectRouter { | ||
func to( | ||
_ handler: @Sendable @escaping (EffectParameters, Consumer<Event>) async -> Void | ||
) -> EffectRouter<Effect, Event> { | ||
to { parameters, callback in | ||
let task = Task.detached { | ||
defer { callback.end() } | ||
await handler(parameters, callback.send) | ||
} | ||
|
||
return AnonymousDisposable { | ||
task.cancel() | ||
} | ||
} | ||
} | ||
|
||
func to( | ||
_ handler: @Sendable @escaping (EffectParameters, Consumer<Event>) async throws -> Void | ||
) -> EffectRouter<Effect, Event> { | ||
to { parameters, callback in | ||
let task = Task.detached { | ||
defer { callback.end() } | ||
try await handler(parameters, callback.send) | ||
} | ||
|
||
return AnonymousDisposable { | ||
task.cancel() | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.