Skip to content

Commit 57427e9

Browse files
committed
Add asynchronous effect handling routes
1 parent 1ac08e3 commit 57427e9

File tree

2 files changed

+649
-0
lines changed

2 files changed

+649
-0
lines changed
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
// Copyright 2019-2024 Spotify AB.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
16+
public extension _PartialEffectRouter {
17+
/// Routes the `Effect` to an asynchronous closure.
18+
///
19+
/// - Parameter handler: An asynchronous closure receiving the `Effect`'s parameters as input.
20+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
21+
func to(_ handler: @escaping (EffectParameters) async -> Void) -> EffectRouter<Effect, Event> {
22+
to { parameters, _ in
23+
await handler(parameters)
24+
}
25+
}
26+
27+
/// Routes the `Effect` to an asynchronous throwing closure.
28+
///
29+
/// - Parameter handler: An asynchronous throwing closure receiving the `Effect`'s parameters as input.
30+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
31+
func to(_ handler: @escaping (EffectParameters) async throws -> Void) -> EffectRouter<Effect, Event> {
32+
to { parameters, _ in
33+
try await handler(parameters)
34+
}
35+
}
36+
}
37+
38+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
39+
public extension _PartialEffectRouter where EffectParameters == Void {
40+
/// Routes the `Effect` to an asynchronous closure.
41+
///
42+
/// - Parameter handler: An asynchronous closure.
43+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
44+
func to(_ handler: @escaping () async -> Void) -> EffectRouter<Effect, Event> {
45+
to { _, _ in
46+
await handler()
47+
}
48+
}
49+
50+
/// Routes the `Effect` to an asynchronous throwing closure.
51+
///
52+
/// - Parameter handler: An asynchronous throwing closure.
53+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
54+
func to(_ handler: @escaping () async throws -> Void) -> EffectRouter<Effect, Event> {
55+
to { _, _ in
56+
try await handler()
57+
}
58+
}
59+
}
60+
61+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
62+
public extension _PartialEffectRouter {
63+
/// Routes the `Effect` to an asynchronous closure producing a single `Event`.
64+
///
65+
/// - Parameter handler: An asynchronous closure receiving the `Effect`'s parameters as input and producing a single `Event` as output.
66+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
67+
func to(_ handler: @escaping (EffectParameters) async -> Event) -> EffectRouter<Effect, Event> {
68+
to { parameters, callback in
69+
await callback(handler(parameters))
70+
}
71+
}
72+
73+
/// Routes the `Effect` to an asynchronous throwing closure producing a single `Event`.
74+
///
75+
/// - Parameter handler: An asynchronous throwing closure receiving the `Effect`'s parameters as input and producing a single `Event` as output.
76+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
77+
func to(_ handler: @escaping (EffectParameters) async throws -> Event) -> EffectRouter<Effect, Event> {
78+
to { parameters, callback in
79+
try await callback(handler(parameters))
80+
}
81+
}
82+
}
83+
84+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
85+
public extension _PartialEffectRouter where EffectParameters == Void {
86+
/// Routes the `Effect` to an asynchronous closure producing a single `Event`.
87+
///
88+
/// - Parameter handler: An asynchronous closure producing a single `Event` as output.
89+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
90+
func to(_ handler: @escaping () async -> Event) -> EffectRouter<Effect, Event> {
91+
to { _, callback in
92+
await callback(handler())
93+
}
94+
}
95+
96+
/// Routes the `Effect` to an asynchronous throwing closure producing a single `Event`.
97+
///
98+
/// - Parameter handler: An asynchronous throwing closure producing a single `Event` as output.
99+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
100+
func to(_ handler: @escaping () async throws -> Event) -> EffectRouter<Effect, Event> {
101+
to { _, callback in
102+
try await callback(handler())
103+
}
104+
}
105+
}
106+
107+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
108+
public extension _PartialEffectRouter {
109+
/// Routes the `Effect` to an asynchronous closure producing a sequence of `Event`s.
110+
///
111+
/// - Parameter handler: An asynchronous closure receiving the `Effect`'s parameters as input and producing an `AsyncSequence` of `Event`s as output.
112+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
113+
func to<S: AsyncSequence>(
114+
_ handler: @escaping (EffectParameters) async -> S
115+
) -> EffectRouter<Effect, Event> where S.Element == Event {
116+
to { parameters, callback in
117+
for try await output in await handler(parameters) {
118+
callback(output)
119+
}
120+
}
121+
}
122+
}
123+
124+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
125+
public extension _PartialEffectRouter where EffectParameters == Void {
126+
/// Routes the `Effect` to an asynchronous closure producing a sequence of `Event`s.
127+
///
128+
/// - Parameter handler: An asynchronous closure producing an `AsyncSequence` of `Event`s as output.
129+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
130+
func to<S: AsyncSequence>(
131+
_ handler: @escaping () async -> S
132+
) -> EffectRouter<Effect, Event> where S.Element == Event {
133+
to { _, callback in
134+
for try await output in await handler() {
135+
callback(output)
136+
}
137+
}
138+
}
139+
}
140+
141+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
142+
public extension _PartialEffectRouter {
143+
/// Routes the `Effect` to an `Actor`'s closure.
144+
///
145+
/// - Parameter actor: An `Actor` providing the `Effect` handling closure.
146+
/// - Parameter handler: An isolated asynchronous closure receiving the `Effect`'s parameters as input.
147+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
148+
func to<A: Actor>(
149+
_ actor: A,
150+
_ handler: @escaping (isolated A) -> (EffectParameters) async -> Void
151+
) -> EffectRouter<Effect, Event> {
152+
to { parameters, _ in
153+
await handler(actor)(parameters)
154+
}
155+
}
156+
157+
/// Routes the `Effect` to an `Actor`'s throwing closure.
158+
///
159+
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure.
160+
/// - Parameter handler: An isolated asynchronous throwing closure receiving the `Effect`'s parameters as input.
161+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
162+
func to<A: Actor>(
163+
_ actor: A,
164+
_ handler: @escaping (isolated A) -> (EffectParameters) async throws -> Void
165+
) -> EffectRouter<Effect, Event> {
166+
to { parameters, _ in
167+
try await handler(actor)(parameters)
168+
}
169+
}
170+
}
171+
172+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
173+
public extension _PartialEffectRouter where EffectParameters == Void {
174+
/// Routes the `Effect` to an `Actor`'s closure.
175+
///
176+
/// - Parameter actor: An `Actor` providing the `Effect` handling closure.
177+
/// - Parameter handler: An isolated asynchronous closure.
178+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
179+
func to<A: Actor>(
180+
_ actor: A,
181+
_ handler: @escaping (isolated A) -> () async -> Void
182+
) -> EffectRouter<Effect, Event> {
183+
to { _, _ in
184+
await handler(actor)()
185+
}
186+
}
187+
188+
/// Routes the `Effect` to an `Actor`'s closure.
189+
///
190+
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure.
191+
/// - Parameter handler: An isolated asynchronous throwing closure.
192+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
193+
func to<A: Actor>(
194+
_ actor: A,
195+
_ handler: @escaping (isolated A) -> () async throws -> Void
196+
) -> EffectRouter<Effect, Event> {
197+
to { _, _ in
198+
try await handler(actor)()
199+
}
200+
}
201+
}
202+
203+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
204+
public extension _PartialEffectRouter {
205+
/// Routes the `Effect` to an `Actor`'s closure producing a single `Event`.
206+
///
207+
/// - Parameter actor: An `Actor` providing the `Effect` handling closure.
208+
/// - Parameter handler: An isolated asynchronous closure receiving the `Effect`'s parameters as input and producing a single `Event` as output.
209+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
210+
func to<A: Actor>(
211+
_ actor: A,
212+
_ handler: @escaping (isolated A) -> (EffectParameters) async -> Event
213+
) -> EffectRouter<Effect, Event> {
214+
to { parameters, callback in
215+
await callback(handler(actor)(parameters))
216+
}
217+
}
218+
219+
/// Routes the `Effect` to an `Actor`'s throwing closure producing a single `Event`.
220+
///
221+
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure.
222+
/// - Parameter handler: An isolated asynchronous throwing closure receiving the `Effect`'s parameters as input and producing a single `Event` as output.
223+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
224+
func to<A: Actor>(
225+
_ actor: A,
226+
_ handler: @escaping (isolated A) -> (EffectParameters) async throws -> Event
227+
) -> EffectRouter<Effect, Event> {
228+
to { parameters, callback in
229+
try await callback(handler(actor)(parameters))
230+
}
231+
}
232+
}
233+
234+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
235+
public extension _PartialEffectRouter where EffectParameters == Void {
236+
/// Routes the `Effect` to an `Actor`'s closure producing a single `Event`.
237+
///
238+
/// - Parameter actor: An `Actor` providing the `Effect` handling closure.
239+
/// - Parameter handler: An isolated asynchronous closure producing a single `Event` as output.
240+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
241+
func to<A: Actor>(
242+
_ actor: A,
243+
_ handler: @escaping (isolated A) -> () async -> Event
244+
) -> EffectRouter<Effect, Event> {
245+
to { _, callback in
246+
await callback(handler(actor)())
247+
}
248+
}
249+
250+
/// Routes the `Effect` to an `Actor`'s throwing closure producing a single `Event`.
251+
///
252+
/// - Parameter actor: An `Actor` providing the `Effect` handling throwing closure.
253+
/// - Parameter handler: An isolated asynchronous throwing closure producing a single `Event` as output.
254+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
255+
func to<A: Actor>(
256+
_ actor: A,
257+
_ handler: @escaping (isolated A) -> () async throws -> Event
258+
) -> EffectRouter<Effect, Event> {
259+
to { _, callback in
260+
try await callback(handler(actor)())
261+
}
262+
}
263+
}
264+
265+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
266+
public extension _PartialEffectRouter {
267+
/// Routes the `Effect` to an `Actor`'s closure producing a sequence of `Event`s.
268+
///
269+
/// - Parameter actor: An `Actor` providing the `Effect` handling closure.
270+
/// - Parameter handler: An isolated asynchronous closure receiving the `Effect`'s parameters as input and producing an `AsyncSequence` of `Event`s as output.
271+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
272+
func to<A: Actor, S: AsyncSequence>(
273+
_ actor: A,
274+
_ handler: @escaping (isolated A) -> (EffectParameters) async -> S
275+
) -> EffectRouter<Effect, Event> where S.Element == Event {
276+
to { parameters, callback in
277+
for try await output in await handler(actor)(parameters) {
278+
callback(output)
279+
}
280+
}
281+
}
282+
}
283+
284+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
285+
public extension _PartialEffectRouter where EffectParameters == Void {
286+
/// Routes the `Effect` to an `Actor`'s closure producing a sequence of `Event`s.
287+
///
288+
/// - Parameter actor: An `Actor` providing the `Effect` handling closure.
289+
/// - Parameter handler: An isolated asynchronous closure producing an `AsyncSequence` of `Event`s as output.
290+
/// - Returns: An `EffectRouter` that includes a handler for the given `Effect`.
291+
func to<A: Actor, S: AsyncSequence>(
292+
_ actor: A,
293+
_ handler: @escaping (isolated A) -> () async -> S
294+
) -> EffectRouter<Effect, Event> where S.Element == Event {
295+
to { _, callback in
296+
for try await output in await handler(actor)() {
297+
callback(output)
298+
}
299+
}
300+
}
301+
}
302+
303+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
304+
private extension _PartialEffectRouter {
305+
func to(
306+
_ handler: @Sendable @escaping (EffectParameters, Consumer<Event>) async -> Void
307+
) -> EffectRouter<Effect, Event> {
308+
to { parameters, callback in
309+
let task = Task.detached {
310+
defer { callback.end() }
311+
await handler(parameters, callback.send)
312+
}
313+
314+
return AnonymousDisposable {
315+
task.cancel()
316+
}
317+
}
318+
}
319+
320+
func to(
321+
_ handler: @Sendable @escaping (EffectParameters, Consumer<Event>) async throws -> Void
322+
) -> EffectRouter<Effect, Event> {
323+
to { parameters, callback in
324+
let task = Task.detached {
325+
defer { callback.end() }
326+
try await handler(parameters, callback.send)
327+
}
328+
329+
return AnonymousDisposable {
330+
task.cancel()
331+
}
332+
}
333+
}
334+
}

0 commit comments

Comments
 (0)