Coverage Report

Created: 2026-09-14 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/swift-nio/Sources/NIOCore/EventLoopFuture.swift
Line
Count
Source
1
//===----------------------------------------------------------------------===//
2
//
3
// This source file is part of the SwiftNIO open source project
4
//
5
// Copyright (c) 2017-2024 Apple Inc. and the SwiftNIO project authors
6
// Licensed under Apache License v2.0
7
//
8
// See LICENSE.txt for license information
9
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
10
//
11
// SPDX-License-Identifier: Apache-2.0
12
//
13
//===----------------------------------------------------------------------===//
14
15
import NIOConcurrencyHelpers
16
17
#if canImport(Dispatch)
18
import Dispatch
19
#endif
20
21
/// Internal list of callbacks.
22
///
23
/// Most of these are closures that pull a value from one future, call a user callback, push the
24
/// result into another, then return a list of callbacks from the target future that are now ready to be invoked.
25
///
26
/// In particular, note that `_run()` here continues to obtain and execute lists of callbacks until it completes.
27
/// This eliminates recursion when processing `flatMap()` chains.
28
@usableFromInline
29
internal struct CallbackList {
30
    @usableFromInline
31
    internal typealias Element = Wrapper
32
33
    // The compiler is able to better optimize a struct holding a closure than just a raw closure
34
    // when used as a generic parameter.
35
    @usableFromInline
36
    struct Wrapper {
37
        @usableFromInline
38
        var callback: () -> CallbackList
39
40
        @inlinable
41
0
        init(_ callback: @escaping () -> CallbackList) {
42
0
            self.callback = callback
43
0
        }
44
    }
45
46
    @usableFromInline
47
    internal var firstCallback: Optional<Element>
48
    @usableFromInline
49
    internal var furtherCallbacks: Optional<[Element]>
50
51
    @inlinable
52
76.2M
    internal init() {
53
76.2M
        self.firstCallback = nil
54
76.2M
        self.furtherCallbacks = nil
55
76.2M
    }
56
57
    @inlinable
58
0
    internal mutating func append(_ callback: @escaping () -> CallbackList) {
59
0
        if self.firstCallback == nil {
60
0
            self.firstCallback = Wrapper(callback)
61
0
        } else {
62
0
            if self.furtherCallbacks != nil {
63
0
                self.furtherCallbacks!.append(Wrapper(callback))
64
0
            } else {
65
0
                self.furtherCallbacks = [Wrapper(callback)]
66
0
            }
67
0
        }
68
0
    }
69
70
    @inlinable
71
0
    internal func _allCallbacks() -> CircularBuffer<Element> {
72
0
        switch (self.firstCallback, self.furtherCallbacks) {
73
0
        case (.none, _):
74
0
            return []
75
0
        case (.some(let onlyCallback), .none):
76
0
            return [onlyCallback]
77
0
        default:
78
0
            var array: CircularBuffer<Element> = []
79
0
            self.appendAllCallbacks(&array)
80
0
            return array
81
0
        }
82
0
    }
83
84
    @inlinable
85
0
    internal func appendAllCallbacks(_ array: inout CircularBuffer<Element>) {
86
0
        switch (self.firstCallback, self.furtherCallbacks) {
87
0
        case (.none, _):
88
0
            return
89
0
        case (.some(let onlyCallback), .none):
90
0
            array.append(onlyCallback)
91
0
        case (.some(let first), .some(let others)):
92
0
            array.reserveCapacity(array.count + 1 + others.count)
93
0
            array.append(first)
94
0
            array.append(contentsOf: others)
95
0
        }
96
0
    }
97
98
    @inlinable
99
276k
    internal func _run() {
100
276k
        switch (self.firstCallback, self.furtherCallbacks) {
101
276k
        case (.none, _):
102
276k
            return
103
276k
        case (.some(let onlyCallback), .none):
104
0
            var onlyCallback = onlyCallback
105
0
            loop: while true {
106
0
                let cbl = onlyCallback.callback()
107
0
                switch (cbl.firstCallback, cbl.furtherCallbacks) {
108
0
                case (.none, _):
109
0
                    break loop
110
0
                case (.some(let ocb), .none):
111
0
                    onlyCallback = ocb
112
0
                    continue loop
113
0
                case (.some(_), .some(_)):
114
0
                    var pending = cbl._allCallbacks()
115
0
                    while let f = pending.popFirst() {
116
0
                        let next = f.callback()
117
0
                        next.appendAllCallbacks(&pending)
118
0
                    }
119
0
                    break loop
120
0
                }
121
0
            }
122
276k
        default:
123
0
            var pending = self._allCallbacks()
124
0
            while let f = pending.popFirst() {
125
0
                let next = f.callback()
126
0
                next.appendAllCallbacks(&pending)
127
0
            }
128
276k
        }
129
0
    }
130
}
131
132
@available(*, unavailable)
133
extension CallbackList: Sendable {}
134
135
@available(*, unavailable)
136
extension CallbackList.Wrapper: Sendable {}
137
138
/// Internal error for operations that return results that were not replaced
139
@usableFromInline
140
internal struct OperationPlaceholderError: Error {
141
    @usableFromInline
142
0
    internal init() {}
143
}
144
145
/// A promise to provide a result later.
146
///
147
/// This is the provider API for `EventLoopFuture<Value>`. If you want to return an
148
/// unfulfilled `EventLoopFuture<Value>` -- presumably because you are interfacing to
149
/// some asynchronous service that will return a real result later, follow this
150
/// pattern:
151
///
152
/// ```
153
/// func someAsyncOperation(args) -> EventLoopFuture<ResultType> {
154
///     let promise = eventLoop.makePromise(of: ResultType.self)
155
///     someAsyncOperationWithACallback(args) { result -> Void in
156
///         // when finished...
157
///         promise.succeed(result)
158
///         // if error...
159
///         promise.fail(error)
160
///     }
161
///     return promise.futureResult
162
/// }
163
/// ```
164
///
165
/// Note that the future result is returned before the async process has provided a value.
166
///
167
/// It's actually not very common to use this directly. Usually, you really want one
168
/// of the following:
169
///
170
/// * If you have an `EventLoopFuture` and want to do something else after it completes,
171
///     use `.flatMap()`
172
/// * If you already have a value and need an `EventLoopFuture<>` object to plug into
173
///     some other API, create an already-resolved object with `eventLoop.makeSucceededFuture(result)`
174
///     or `eventLoop.newFailedFuture(error:)`.
175
///
176
/// - Note: `EventLoopPromise` has reference semantics.
177
public struct EventLoopPromise<Value> {
178
    /// The `EventLoopFuture` which is used by the `EventLoopPromise`. You can use it to add callbacks which are notified once the
179
    /// `EventLoopPromise` is completed.
180
    public let futureResult: EventLoopFuture<Value>
181
182
    @inlinable
183
0
    internal static func makeUnleakablePromise(eventLoop: EventLoop, line: UInt = #line) -> EventLoopPromise<Value> {
184
0
        EventLoopPromise<Value>(
185
0
            eventLoop: eventLoop,
186
0
            file: """
187
0
                EventLoopGroup shut down with unfulfilled promises remaining. \
188
0
                This suggests that the EventLoopGroup was shut down with unfinished work outstanding which is \
189
0
                illegal. Either switch to using the singleton EventLoopGroups or fix the issue by only shutting down \
190
0
                the EventLoopGroups when all the work associated with them has finished.
191
0
                """,
192
0
            line: line
193
0
        )
194
0
    }
195
196
    /// General initializer
197
    ///
198
    /// - Parameters:
199
    ///   - eventLoop: The event loop this promise is tied to.
200
    ///   - file: The file this promise was allocated in, for debugging purposes.
201
    ///   - line: The line this promise was allocated on, for debugging purposes.
202
    @inlinable
203
6.29M
    internal init(eventLoop: EventLoop, file: StaticString, line: UInt) {
204
6.29M
        self.futureResult = EventLoopFuture<Value>(_eventLoop: eventLoop, file: file, line: line)
205
6.29M
    }
206
207
    /// Deliver a successful result to the associated `EventLoopFuture<Value>` object.
208
    ///
209
    /// - Parameters:
210
    ///   - value: The successful result of the operation.
211
    @preconcurrency
212
    @inlinable
213
9.05M
    public func succeed(_ value: Value) where Value: Sendable {
214
9.05M
        self._resolve(value: .success(value))
215
9.05M
    }
216
217
    /// Deliver an error to the associated `EventLoopFuture<Value>` object.
218
    ///
219
    /// - Parameters:
220
    ///      - error: The error from the operation.
221
    @inlinable
222
0
    public func fail(_ error: Error) {
223
0
        if self.futureResult.eventLoop.inEventLoop {
224
0
            self.futureResult._setError(error)._run()
225
0
        } else {
226
0
            self.futureResult.eventLoop.execute {
227
0
                self.futureResult._setError(error)._run()
228
0
            }
229
0
        }
230
0
    }
231
232
    /// Complete the promise with the passed in `EventLoopFuture<Value>`.
233
    ///
234
    /// This method is equivalent to invoking `future.cascade(to: promise)`,
235
    /// but sometimes may read better than its cascade counterpart.
236
    ///
237
    /// - Note: The `Value` must be `Sendable` since the isolation domains of the passed future and this promise might differ i.e.
238
    /// they might be bound to different event loops.
239
    ///
240
    /// - Parameters:
241
    ///   - future: The future whose value will be used to succeed or fail this promise.
242
    /// - seealso: `EventLoopFuture.cascade(to:)`
243
    @preconcurrency
244
    @inlinable
245
0
    public func completeWith(_ future: EventLoopFuture<Value>) where Value: Sendable {
246
0
        future.cascade(to: self)
247
0
    }
248
249
    /// Complete the promise with the passed in `Result<Value, Error>`.
250
    ///
251
    /// This method is equivalent to invoking:
252
    /// ```
253
    /// switch result {
254
    /// case .success(let value):
255
    ///     promise.succeed(value)
256
    /// case .failure(let error):
257
    ///     promise.fail(error)
258
    /// }
259
    /// ```
260
    ///
261
    /// - Parameters:
262
    ///   - result: The result which will be used to succeed or fail this promise.
263
    @preconcurrency
264
    @inlinable
265
0
    public func completeWith(_ result: Result<Value, Error>) where Value: Sendable {
266
0
        self._resolve(value: result)
267
0
    }
268
269
    /// Fire the associated `EventLoopFuture` on the appropriate event loop.
270
    ///
271
    /// This method provides the primary difference between the `EventLoopPromise` and most
272
    /// other `Promise` implementations: specifically, all callbacks fire on the `EventLoop`
273
    /// that was used to create the promise.
274
    ///
275
    /// - Parameters:
276
    ///   - value: The value to fire the future with.
277
    @inlinable
278
1.39M
    internal func _resolve(value: Result<Value, Error>) where Value: Sendable {
279
1.39M
        if self.futureResult.eventLoop.inEventLoop {
280
1.39M
            self._setValue(value: value)._run()
281
1.39M
        } else {
282
0
            self.futureResult.eventLoop.execute {
283
0
                self._setValue(value: value)._run()
284
0
            }
285
0
        }
286
1.39M
    }
287
288
    /// Set the future result and get the associated callbacks.
289
    ///
290
    /// - Parameters:
291
    ///   - value: The result of the promise.
292
    /// - Returns: The callback list to run.
293
    @inlinable
294
11.3M
    internal func _setValue(value: Result<Value, Error>) -> CallbackList {
295
11.3M
        self.futureResult._setValue(value: value)
296
11.3M
    }
297
}
298
299
extension EventLoopPromise: Equatable {}
300
301
/// Holder for a result that will be provided later.
302
///
303
/// Functions that promise to do work asynchronously can return an `EventLoopFuture<Value>`.
304
/// The recipient of such an object can then observe it to be notified when the operation completes.
305
///
306
/// The provider of a `EventLoopFuture<Value>` can create and return a placeholder object
307
/// before the actual result is available. For example:
308
///
309
/// ```
310
/// func getNetworkData(args) -> EventLoopFuture<NetworkResponse> {
311
///     let promise = eventLoop.makePromise(of: NetworkResponse.self)
312
///     queue.async {
313
///         . . . do some work . . .
314
///         promise.succeed(response)
315
///         . . . if it fails, instead . . .
316
///         promise.fail(error)
317
///     }
318
///     return promise.futureResult
319
/// }
320
/// ```
321
///
322
/// Note that this function returns immediately; the promise object will be given a value
323
/// later on. This behaviour is common to Future/Promise implementations in many programming
324
/// languages. If you are unfamiliar with this kind of object, the following resources may be
325
/// helpful:
326
///
327
/// - [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises)
328
/// - [Scala](http://docs.scala-lang.org/overviews/core/futures.html)
329
/// - [Python](https://docs.google.com/document/d/10WOZgLQaYNpOrag-eTbUm-JUCCfdyfravZ4qSOQPg1M/edit)
330
///
331
/// If you receive a `EventLoopFuture<Value>` from another function, you have a number of options:
332
/// The most common operation is to use `flatMap()` or `map()` to add a function that will be called
333
/// with the eventual result.  Both methods returns a new `EventLoopFuture<Value>` immediately
334
/// that will receive the return value from your function, but they behave differently. If you have
335
/// a function that can return synchronously, the `map` function will transform the result of type
336
/// `Value` to a the new result of type `NewValue` and return an `EventLoopFuture<NewValue>`.
337
///
338
/// ```
339
/// let networkData = getNetworkData(args)
340
///
341
/// // When network data is received, convert it.
342
/// let processedResult: EventLoopFuture<Processed> = networkData.map { (n: NetworkResponse) -> Processed in
343
///     ... parse network data ....
344
///     return processedResult
345
/// }
346
/// ```
347
///
348
/// If however you need to do more asynchronous processing, you can call `flatMap()`. The return value of the
349
/// function passed to `flatMap` must be a new `EventLoopFuture<NewValue>` object: the return value of `flatMap()` is
350
/// a new `EventLoopFuture<NewValue>` that will contain the eventual result of both the original operation and
351
/// the subsequent one.
352
///
353
/// ```
354
/// // When converted network data is available, begin the database operation.
355
/// let databaseResult: EventLoopFuture<DBResult> = processedResult.flatMap { (p: Processed) -> EventLoopFuture<DBResult> in
356
///     return someDatabaseOperation(p)
357
/// }
358
/// ```
359
///
360
/// In essence, future chains created via `flatMap()` provide a form of data-driven asynchronous programming
361
/// that allows you to dynamically declare data dependencies for your various operations.
362
///
363
/// `EventLoopFuture` chains created via `flatMap()` are sufficient for most purposes. All of the registered
364
/// functions will eventually run in order. If one of those functions throws an error, that error will
365
/// bypass the remaining functions. You can use `flatMapError()` to handle and optionally recover from
366
/// errors in the middle of a chain.
367
///
368
/// At the end of an `EventLoopFuture` chain, you can use `whenSuccess()` or `whenFailure()` to add an
369
/// observer callback that will be invoked with the result or error at that point. (Note: If you ever
370
/// find yourself invoking `promise.succeed()` from inside a `whenSuccess()` callback, you probably should
371
/// use `flatMap()` or `cascade(to:)` instead.)
372
///
373
/// `EventLoopFuture` objects are typically obtained by:
374
/// * Using `.flatMap()` on an existing future to create a new future for the next step in a series of operations.
375
/// * Initializing an `EventLoopFuture` that already has a value or an error
376
///
377
/// ### Threading and Futures
378
///
379
/// One of the major performance advantages of NIO over something like Node.js or Python’s asyncio is that NIO will
380
/// by default run multiple event loops at once, on different threads. As most network protocols do not require
381
/// blocking operation, at least in their low level implementations, this provides enormous speedups on machines
382
/// with many cores such as most modern servers.
383
///
384
/// However, it can present a challenge at higher levels of abstraction when coordination between those threads
385
/// becomes necessary. This is usually the case whenever the events on one connection (that is, one `Channel`) depend
386
/// on events on another one. As these `Channel`s may be scheduled on different event loops (and so different threads)
387
/// care needs to be taken to ensure that communication between the two loops is done in a thread-safe manner that
388
/// avoids concurrent mutation of shared state from multiple loops at once.
389
///
390
/// The main primitives NIO provides for this use are the `EventLoopPromise` and `EventLoopFuture`. As their names
391
/// suggest, these two objects are aware of event loops, and so can help manage the safety and correctness of your
392
/// programs. However, understanding the exact semantics of these objects is critical to ensuring the safety of your code.
393
///
394
/// ####  Callbacks
395
///
396
/// The most important principle of the `EventLoopPromise` and `EventLoopFuture` is this: all callbacks registered on
397
/// an `EventLoopFuture` will execute on the thread corresponding to the event loop that created the `Future`,
398
/// *regardless* of what thread succeeds or fails the corresponding `EventLoopPromise`.
399
///
400
/// This means that if *your code* created the `EventLoopPromise`, you can be extremely confident of what thread the
401
/// callback will execute on: after all, you held the event loop in hand when you created the `EventLoopPromise`.
402
/// However, if your code is handed an `EventLoopFuture` or `EventLoopPromise`, and you want to register callbacks
403
/// on those objects, you cannot be confident that those callbacks will execute on the same `EventLoop` that your
404
/// code does.
405
///
406
/// This presents a problem: how do you ensure thread-safety when registering callbacks on an arbitrary
407
/// `EventLoopFuture`? The short answer is that when you are holding an `EventLoopFuture`, you can always obtain a
408
/// new `EventLoopFuture` whose callbacks will execute on your event loop. You do this by calling
409
/// `EventLoopFuture.hop(to:)`. This function returns a new `EventLoopFuture` whose callbacks are guaranteed
410
/// to fire on the provided event loop. As an added bonus, `hopTo` will check whether the provided `EventLoopFuture`
411
/// was already scheduled to dispatch on the event loop in question, and avoid doing any work if that was the case.
412
///
413
/// This means that for any `EventLoopFuture` that your code did not create itself (via
414
/// `EventLoopPromise.futureResult`), use of `hopTo` is **strongly encouraged** to help guarantee thread-safety. It
415
/// should only be elided when thread-safety is provably not needed.
416
///
417
/// The "thread affinity" of `EventLoopFuture`s is critical to writing safe, performant concurrent code without
418
/// boilerplate. It allows you to avoid needing to write or use locks in your own code, instead using the natural
419
/// synchronization of the `EventLoop` to manage your thread-safety. In general, if any of your `ChannelHandler`s
420
/// or `EventLoopFuture` callbacks need to invoke a lock (either directly or in the form of `DispatchQueue`) this
421
/// should be considered a code smell worth investigating: the `EventLoop`-based synchronization guarantees of
422
/// `EventLoopFuture` should be sufficient to guarantee thread-safety.
423
public final class EventLoopFuture<Value> {
424
    // TODO: Provide a tracing facility.  It would be nice to be able to set '.debugTrace = true' on any EventLoopFuture or EventLoopPromise and have every subsequent chained EventLoopFuture report the success result or failure error.  That would simplify some debugging scenarios.
425
    @usableFromInline
426
    internal var _value: Optional<Result<Value, Error>>
427
428
    /// The `EventLoop` which is tied to the `EventLoopFuture` and is used to notify all registered callbacks.
429
    public let eventLoop: EventLoop
430
431
    /// Callbacks that should be run when this `EventLoopFuture<Value>` gets a value.
432
    /// These callbacks may give values to other `EventLoopFuture`s; if that happens,
433
    /// they return any callbacks from those `EventLoopFuture`s so that we can run
434
    /// the entire chain from the top without recursing.
435
    @usableFromInline
436
    internal var _callbacks: CallbackList
437
438
    @inlinable
439
6.29M
    internal init(_eventLoop eventLoop: EventLoop, file: StaticString, line: UInt) {
440
6.29M
        self.eventLoop = eventLoop
441
6.29M
        self._value = nil
442
6.29M
        self._callbacks = .init()
443
6.29M
444
6.29M
        debugOnly {
445
26.7k
            eventLoop._promiseCreated(futureIdentifier: _NIOEventLoopFutureIdentifier(self), file: file, line: line)
446
26.7k
        }
447
6.29M
    }
448
449
    /// A EventLoopFuture<Value> that has already succeeded
450
    @inlinable
451
180k
    internal init(eventLoop: EventLoop, value: Value) where Value: Sendable {
452
180k
        self.eventLoop = eventLoop
453
180k
        self._value = .success(value)
454
180k
        self._callbacks = .init()
455
180k
    }
456
457
    /// A EventLoopFuture<Value> that has already succeeded with an isolated (not-necessarily-sendable) value
458
    @inlinable
459
0
    internal init(eventLoop: EventLoop, isolatedValue value: Value) {
460
0
        eventLoop.assertInEventLoop()
461
0
462
0
        self.eventLoop = eventLoop
463
0
        self._value = .success(value)
464
0
        self._callbacks = .init()
465
0
    }
466
467
    /// A EventLoopFuture<Value> that has already failed
468
    @inlinable
469
0
    internal init(eventLoop: EventLoop, error: Error) {
470
0
        self.eventLoop = eventLoop
471
0
        self._value = .failure(error)
472
0
        self._callbacks = .init()
473
0
    }
474
475
68.3k
    deinit {
476
68.3k
        debugOnly {
477
33.4k
            if let creation = eventLoop._promiseCompleted(futureIdentifier: _NIOEventLoopFutureIdentifier(self)) {
478
26.7k
                if self._value == nil {
479
0
                    fatalError("leaking promise created at \(creation)", file: creation.file, line: creation.line)
480
0
                }
481
26.7k
            } else {
482
6.69k
                precondition(self._value != nil, "leaking an unfulfilled Promise")
483
6.69k
            }
484
33.4k
        }
485
68.3k
    }
486
}
487
488
extension EventLoopFuture: Equatable {
489
0
    public static func == (lhs: EventLoopFuture, rhs: EventLoopFuture) -> Bool {
490
0
        lhs === rhs
491
0
    }
492
}
493
494
// MARK: flatMap and map
495
496
// 'flatMap' and 'map' implementations. This is really the key of the entire system.
497
extension EventLoopFuture {
498
    /// When the current `EventLoopFuture<Value>` is fulfilled, run the provided callback,
499
    /// which will provide a new `EventLoopFuture`.
500
    ///
501
    /// This allows you to dynamically dispatch new asynchronous tasks as phases in a
502
    /// longer series of processing steps. Note that you can use the results of the
503
    /// current `EventLoopFuture<Value>` when determining how to dispatch the next operation.
504
    ///
505
    /// This works well when you have APIs that already know how to return `EventLoopFuture`s.
506
    /// You can do something with the result of one and just return the next future:
507
    ///
508
    /// ```
509
    /// let d1 = networkRequest(args).future()
510
    /// let d2 = d1.flatMap { t -> EventLoopFuture<NewValue> in
511
    ///     . . . something with t . . .
512
    ///     return netWorkRequest(args)
513
    /// }
514
    /// d2.whenSuccess { u in
515
    ///     NSLog("Result of second request: \(u)")
516
    /// }
517
    /// ```
518
    ///
519
    /// Note: In a sense, the `EventLoopFuture<NewValue>` is returned before it's created.
520
    ///
521
    /// - Note: The `NewValue` must be `Sendable` since the isolation domains of this future and the future returned from the callback
522
    /// might differ i.e. they might be bound to different event loops.
523
    ///
524
    /// - Parameters:
525
    ///   - callback: Function that will receive the value of this `EventLoopFuture` and return
526
    ///         a new `EventLoopFuture`.
527
    /// - Returns: A future that will receive the eventual value.
528
    @inlinable
529
    @preconcurrency
530
    public func flatMap<NewValue: Sendable>(
531
        _ callback: @escaping @Sendable (Value) -> EventLoopFuture<NewValue>
532
0
    ) -> EventLoopFuture<NewValue> {
533
0
        self._flatMap(callback)
534
0
    }
535
    @usableFromInline typealias FlatMapCallback<NewValue> = @Sendable (Value) -> EventLoopFuture<NewValue>
536
537
    @inlinable
538
0
    func _flatMap<NewValue: Sendable>(_ callback: @escaping FlatMapCallback<NewValue>) -> EventLoopFuture<NewValue> {
539
0
        let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
540
0
        self._whenComplete {
541
0
            switch self._value! {
542
0
            case .success(let t):
543
0
                let futureU = callback(t)
544
0
                if futureU.eventLoop.inEventLoop {
545
0
                    return futureU._addCallback {
546
0
                        next._setValue(value: futureU._value!)
547
0
                    }
548
0
                } else {
549
0
                    futureU.cascade(to: next)
550
0
                    return CallbackList()
551
0
                }
552
0
            case .failure(let error):
553
0
                return next._setValue(value: .failure(error))
554
0
            }
555
0
        }
556
0
        return next.futureResult
557
0
    }
558
559
    /// When the current `EventLoopFuture<Value>` is fulfilled, run the provided callback,
560
    /// which will provide a new `EventLoopFuture.Isolated`.
561
    ///
562
    /// This is a variant of ``flatMap(_:)`` for cases where the inner future is known to be bound
563
    /// to the same ``EventLoop`` as this future. Because the callback returns an
564
    /// `EventLoopFuture<NewValue>.Isolated`, the caller is asserting that the future returned from
565
    /// the callback is bound to the same ``EventLoop`` as this future.
566
    /// `EventLoopFuture<NewValue>.Isolated` can only be constructed via
567
    /// ``EventLoopFuture/assumeIsolated()``, which requires being on the future's event loop —
568
    /// the callback runs on this future's event loop, so that construction is always safe.
569
    ///
570
    /// - Note: The `NewValue` need not be `Sendable` since the isolation domains of this future
571
    /// and the future returned from the callback must be the same.
572
    ///
573
    /// - Parameters:
574
    ///   - callback: Function that will receive the value of this `EventLoopFuture` and return
575
    ///         a new `EventLoopFuture.Isolated`.
576
    /// - Returns: A future that will receive the eventual value.
577
    @inlinable
578
    public func flatMapIsolated<NewValue>(
579
        _ callback: @escaping @Sendable (Value) -> EventLoopFuture<NewValue>.Isolated
580
0
    ) -> EventLoopFuture<NewValue> {
581
0
        let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
582
0
        self._whenComplete {
583
0
            switch self._value! {
584
0
            case .success(let t):
585
0
                let futureU = callback(t)
586
0
                futureU._wrapped.eventLoop.assertInEventLoop()
587
0
                return futureU._wrapped._addCallback {
588
0
                    next._setValue(value: futureU._wrapped._value!)
589
0
                }
590
0
            case .failure(let error):
591
0
                return next._setValue(value: .failure(error))
592
0
            }
593
0
        }
594
0
        return next.futureResult
595
0
    }
596
597
    /// When the current `EventLoopFuture<Value>` is fulfilled, run the provided callback, which
598
    /// performs a synchronous computation and returns a new value of type `NewValue`. The provided
599
    /// callback may optionally `throw`.
600
    ///
601
    /// Operations performed in `flatMapThrowing` should not block, or they will block the entire
602
    /// event loop. `flatMapThrowing` is intended for use when you have a data-driven function that
603
    /// performs a simple data transformation that can potentially error.
604
    ///
605
    /// If your callback function throws, the returned `EventLoopFuture` will error.
606
    ///
607
    /// - Note: The `NewValue` must be `Sendable` since the isolation domains of this future and the future returned from the callback
608
    /// might differ i.e. they might be bound to different event loops.
609
    ///
610
    /// - Parameters:
611
    ///   - callback: Function that will receive the value of this `EventLoopFuture` and return
612
    ///         a new value lifted into a new `EventLoopFuture`.
613
    /// - Returns: A future that will receive the eventual value.
614
    @inlinable
615
    @preconcurrency
616
    public func flatMapThrowing<NewValue>(
617
        _ callback: @escaping @Sendable (Value) throws -> NewValue
618
0
    ) -> EventLoopFuture<NewValue> {
619
0
        self._flatMapThrowing(callback)
620
0
    }
621
    @usableFromInline typealias FlatMapThrowingCallback<NewValue> = @Sendable (Value) throws -> NewValue
622
623
    @inlinable
624
    func _flatMapThrowing<NewValue>(
625
        _ callback: @escaping FlatMapThrowingCallback<NewValue>
626
0
    ) -> EventLoopFuture<NewValue> {
627
0
        let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
628
0
        self._whenComplete {
629
0
            switch self._value! {
630
0
            case .success(let t):
631
0
                do {
632
0
                    let r = try callback(t)
633
0
                    return next._setValue(value: .success(r))
634
0
                } catch {
635
0
                    return next._setValue(value: .failure(error))
636
0
                }
637
0
            case .failure(let e):
638
0
                return next._setValue(value: .failure(e))
639
0
            }
640
0
        }
641
0
        return next.futureResult
642
0
    }
643
644
    /// When the current `EventLoopFuture<Value>` is in an error state, run the provided callback, which
645
    /// may recover from the error and returns a new value of type `Value`. The provided callback may optionally `throw`,
646
    /// in which case the `EventLoopFuture` will be in a failed state with the new thrown error.
647
    ///
648
    /// Operations performed in `flatMapErrorThrowing` should not block, or they will block the entire
649
    /// event loop. `flatMapErrorThrowing` is intended for use when you have the ability to synchronously
650
    /// recover from errors.
651
    ///
652
    /// If your callback function throws, the returned `EventLoopFuture` will error.
653
    ///
654
    /// - Parameters:
655
    ///   - callback: Function that will receive the error value of this `EventLoopFuture` and return
656
    ///         a new value lifted into a new `EventLoopFuture`.
657
    /// - Returns: A future that will receive the eventual value or a rethrown error.
658
    @inlinable
659
    @preconcurrency
660
    public func flatMapErrorThrowing(
661
        _ callback: @escaping @Sendable (Error) throws -> Value
662
0
    ) -> EventLoopFuture<Value> {
663
0
        self._flatMapErrorThrowing(callback)
664
0
    }
665
    @usableFromInline typealias FlatMapErrorThrowingCallback = @Sendable (Error) throws -> Value
666
667
    @inlinable
668
0
    func _flatMapErrorThrowing(_ callback: @escaping FlatMapErrorThrowingCallback) -> EventLoopFuture<Value> {
669
0
        let next = EventLoopPromise<Value>.makeUnleakablePromise(eventLoop: self.eventLoop)
670
0
        self._whenComplete {
671
0
            switch self._value! {
672
0
            case .success(let t):
673
0
                return next._setValue(value: .success(t))
674
0
            case .failure(let e):
675
0
                do {
676
0
                    let r = try callback(e)
677
0
                    return next._setValue(value: .success(r))
678
0
                } catch {
679
0
                    return next._setValue(value: .failure(error))
680
0
                }
681
0
            }
682
0
        }
683
0
        return next.futureResult
684
0
    }
685
686
    /// When the current `EventLoopFuture<Value>` is fulfilled, run the provided callback, which
687
    /// performs a synchronous computation and returns a new value of type `NewValue`.
688
    ///
689
    /// Operations performed in `map` should not block, or they will block the entire event
690
    /// loop. `map` is intended for use when you have a data-driven function that performs
691
    /// a simple data transformation that cannot error.
692
    ///
693
    /// If you have a data-driven function that can throw, you should use `flatMapThrowing`
694
    /// instead.
695
    ///
696
    /// ```
697
    /// let future1 = eventually()
698
    /// let future2 = future1.map { T -> U in
699
    ///     ... stuff ...
700
    ///     return u
701
    /// }
702
    /// let future3 = future2.map { U -> V in
703
    ///     ... stuff ...
704
    ///     return v
705
    /// }
706
    /// ```
707
    ///
708
    /// - Parameters:
709
    ///   - callback: Function that will receive the value of this `EventLoopFuture` and return
710
    ///         a new value lifted into a new `EventLoopFuture`.
711
    /// - Returns: A future that will receive the eventual value.
712
    @inlinable
713
    @preconcurrency
714
    public func map<NewValue>(
715
        _ callback: @escaping @Sendable (Value) -> (NewValue)
716
0
    ) -> EventLoopFuture<NewValue> {
717
0
        self._map(callback)
718
0
    }
719
    @usableFromInline typealias MapCallback<NewValue> = @Sendable (Value) -> (NewValue)
720
721
    @inlinable
722
    func _map<NewValue>(
723
        _ callback: @escaping @Sendable (Value) -> (NewValue)
724
0
    ) -> EventLoopFuture<NewValue> {
725
0
        if NewValue.self == Value.self && NewValue.self == Void.self {
726
0
            self.whenSuccess(callback as! @Sendable (Value) -> Void)
727
0
            return self as! EventLoopFuture<NewValue>
728
0
        } else {
729
0
            let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
730
0
            self._whenComplete {
731
0
                next._setValue(value: self._value!.map(callback))
732
0
            }
733
0
            return next.futureResult
734
0
        }
735
0
    }
736
737
    /// When the current `EventLoopFuture<Value>` is in an error state, run the provided callback, which
738
    /// may recover from the error by returning an `EventLoopFuture<NewValue>`. The callback is intended to potentially
739
    /// recover from the error by returning a new `EventLoopFuture` that will eventually contain the recovered
740
    /// result.
741
    ///
742
    /// If the callback cannot recover it should return a failed `EventLoopFuture`.
743
    ///
744
    /// - Note: The `Value` must be `Sendable` since the isolation domains of this future and the future returned from the callback
745
    /// might differ i.e. they might be bound to different event loops.
746
    ///
747
    /// - Parameters:
748
    ///   - callback: Function that will receive the error value of this `EventLoopFuture` and return
749
    ///         a new value lifted into a new `EventLoopFuture`.
750
    /// - Returns: A future that will receive the recovered value.
751
    @inlinable
752
    @preconcurrency
753
    public func flatMapError(
754
        _ callback: @escaping @Sendable (Error) -> EventLoopFuture<Value>
755
0
    ) -> EventLoopFuture<Value> where Value: Sendable {
756
0
        let next = EventLoopPromise<Value>.makeUnleakablePromise(eventLoop: self.eventLoop)
757
0
        self._whenComplete {
758
0
            switch self._value! {
759
0
            case .success(let t):
760
0
                return next._setValue(value: .success(t))
761
0
            case .failure(let e):
762
0
                let t = callback(e)
763
0
                if t.eventLoop.inEventLoop {
764
0
                    return t._addCallback {
765
0
                        next._setValue(value: t._value!)
766
0
                    }
767
0
                } else {
768
0
                    t.cascade(to: next)
769
0
                    return CallbackList()
770
0
                }
771
0
            }
772
0
        }
773
0
        return next.futureResult
774
0
    }
775
776
    /// When the current `EventLoopFuture<Value>` is fulfilled, run the provided callback, which
777
    /// performs a synchronous computation and returns either a new value (of type `NewValue`) or
778
    /// an error depending on the `Result` returned by the closure.
779
    ///
780
    /// Operations performed in `flatMapResult` should not block, or they will block the entire
781
    /// event loop. `flatMapResult` is intended for use when you have a data-driven function that
782
    /// performs a simple data transformation that can potentially error.
783
    ///
784
    ///
785
    /// - Parameters:
786
    ///   - body: Function that will receive the value of this `EventLoopFuture` and return
787
    ///         a new value or error lifted into a new `EventLoopFuture`.
788
    /// - Returns: A future that will receive the eventual value.
789
    @inlinable
790
    @preconcurrency
791
    public func flatMapResult<NewValue, SomeError: Error>(
792
        _ body: @escaping @Sendable (Value) -> Result<NewValue, SomeError>
793
0
    ) -> EventLoopFuture<NewValue> {
794
0
        self._flatMapResult(body)
795
0
    }
796
    @usableFromInline typealias FlatMapResultCallback<NewValue, SomeError: Error> =
797
        @Sendable (Value) -> Result<
798
            NewValue, SomeError
799
        >
800
801
    @inlinable
802
    func _flatMapResult<NewValue, SomeError: Error>(
803
        _ body: @escaping FlatMapResultCallback<NewValue, SomeError>
804
0
    ) -> EventLoopFuture<NewValue> {
805
0
        let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
806
0
        self._whenComplete {
807
0
            switch self._value! {
808
0
            case .success(let value):
809
0
                switch body(value) {
810
0
                case .success(let newValue):
811
0
                    return next._setValue(value: .success(newValue))
812
0
                case .failure(let error):
813
0
                    return next._setValue(value: .failure(error))
814
0
                }
815
0
            case .failure(let e):
816
0
                return next._setValue(value: .failure(e))
817
0
            }
818
0
        }
819
0
        return next.futureResult
820
0
    }
821
822
    /// When the current `EventLoopFuture<Value>` is in an error state, run the provided callback, which
823
    /// can recover from the error and return a new value of type `Value`. The provided callback may not `throw`,
824
    /// so this function should be used when the error is always recoverable.
825
    ///
826
    /// Operations performed in `recover` should not block, or they will block the entire
827
    /// event loop. `recover` is intended for use when you have the ability to synchronously
828
    /// recover from errors.
829
    ///
830
    /// - Parameters:
831
    ///   - callback: Function that will receive the error value of this `EventLoopFuture` and return
832
    ///         a new value lifted into a new `EventLoopFuture`.
833
    /// - Returns: A future that will receive the recovered value.
834
    @inlinable
835
    @preconcurrency
836
0
    public func recover(_ callback: @escaping @Sendable (Error) -> Value) -> EventLoopFuture<Value> {
837
0
        let next = EventLoopPromise<Value>.makeUnleakablePromise(eventLoop: self.eventLoop)
838
0
        self._whenComplete {
839
0
            switch self._value! {
840
0
            case .success(let t):
841
0
                return next._setValue(value: .success(t))
842
0
            case .failure(let e):
843
0
                return next._setValue(value: .success(callback(e)))
844
0
            }
845
0
        }
846
0
        return next.futureResult
847
0
    }
848
849
    /// Add a callback.  If there's already a value, invoke it and return the resulting list of new callback functions.
850
    @inlinable
851
13.0M
    internal func _addCallback(_ callback: @escaping () -> CallbackList) -> CallbackList {
852
13.0M
        self.eventLoop.assertInEventLoop()
853
13.0M
        if self._value == nil {
854
0
            self._callbacks.append(callback)
855
0
            return CallbackList()
856
13.0M
        }
857
13.0M
        return callback()
858
13.0M
    }
859
860
    /// Add a callback.  If there's already a value, run as much of the chain as we can.
861
    @inlinable
862
    // TODO: We want to remove @preconcurrency but it results in more allocations in 1000_udpconnections
863
    @preconcurrency
864
10.1M
    internal func _whenComplete(_ callback: @escaping @Sendable () -> CallbackList) {
865
10.1M
        self._internalWhenComplete(callback)
866
10.1M
    }
867
868
    /// Add a callback.  If there's already a value, run as much of the chain as we can.
869
    @inlinable
870
10.1M
    internal func _internalWhenComplete(_ callback: @escaping @Sendable () -> CallbackList) {
871
10.1M
        if self.eventLoop.inEventLoop {
872
10.1M
            self._whenCompleteIsolated(callback)
873
10.1M
        } else {
874
0
            self.eventLoop.execute {
875
0
                self._whenCompleteIsolated(callback)
876
0
            }
877
0
        }
878
10.1M
    }
879
880
    /// Add a callback.  If there's already a value, run as much of the chain as we can.
881
    @inlinable
882
13.0M
    internal func _whenCompleteIsolated(_ callback: @escaping () -> CallbackList) {
883
13.0M
        self.eventLoop.assertInEventLoop()
884
13.0M
        self._addCallback(callback)._run()
885
13.0M
    }
886
887
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
888
    /// `EventLoopFuture` has a success result.
889
    ///
890
    /// An observer callback cannot return a value, meaning that this function cannot be chained
891
    /// from. If you are attempting to create a computation pipeline, consider `map` or `flatMap`.
892
    /// If you find yourself passing the results from this `EventLoopFuture` to a new `EventLoopPromise`
893
    /// in the body of this function, consider using `cascade` instead.
894
    ///
895
    /// - Parameters:
896
    ///   - callback: The callback that is called with the successful result of the `EventLoopFuture`.
897
    @inlinable
898
    @preconcurrency
899
0
    public func whenSuccess(_ callback: @escaping @Sendable (Value) -> Void) {
900
0
        self._whenComplete {
901
0
            if case .success(let t) = self._value! {
902
0
                callback(t)
903
0
            }
904
0
            return CallbackList()
905
0
        }
906
0
    }
907
908
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
909
    /// `EventLoopFuture` has a failure result.
910
    ///
911
    /// An observer callback cannot return a value, meaning that this function cannot be chained
912
    /// from. If you are attempting to create a computation pipeline, consider `recover` or `flatMapError`.
913
    /// If you find yourself passing the results from this `EventLoopFuture` to a new `EventLoopPromise`
914
    /// in the body of this function, consider using `cascade` instead.
915
    ///
916
    /// - Parameters:
917
    ///   - callback: The callback that is called with the failed result of the `EventLoopFuture`.
918
    @inlinable
919
    @preconcurrency
920
0
    public func whenFailure(_ callback: @escaping @Sendable (Error) -> Void) {
921
0
        self._whenComplete {
922
0
            if case .failure(let e) = self._value! {
923
0
                callback(e)
924
0
            }
925
0
            return CallbackList()
926
0
        }
927
0
    }
928
929
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
930
    /// `EventLoopFuture` has any result.
931
    ///
932
    /// - Parameters:
933
    ///   - callback: The callback that is called when the `EventLoopFuture` is fulfilled.
934
    @inlinable
935
    @preconcurrency
936
0
    public func whenComplete(_ callback: @escaping @Sendable (Result<Value, Error>) -> Void) {
937
0
        self._whenComplete {
938
0
            callback(self._value!)
939
0
            return CallbackList()
940
0
        }
941
0
    }
942
943
    /// Internal: Set the value and return a list of callbacks that should be invoked as a result.
944
    @inlinable
945
1.28M
    internal func _setValue(value: Result<Value, Error>) -> CallbackList {
946
1.28M
        self.eventLoop.assertInEventLoop()
947
1.28M
        if self._value == nil {
948
1.03M
            self._value = value
949
1.03M
            let callbacks = self._callbacks
950
1.03M
            self._callbacks = CallbackList()
951
1.03M
            return callbacks
952
1.03M
        }
953
257k
        return CallbackList()
954
1.28M
    }
955
956
    /// Internal: Set the value and return a list of callbacks that should be invoked as a result.
957
    ///
958
    /// We need a separate method for setting the error to avoid Sendable checking of `Value`
959
    @inlinable
960
0
    internal func _setError(_ error: Error) -> CallbackList {
961
0
        self.eventLoop.assertInEventLoop()
962
0
        if self._value == nil {
963
0
            self._value = .failure(error)
964
0
            let callbacks = self._callbacks
965
0
            self._callbacks = CallbackList()
966
0
            return callbacks
967
0
        }
968
0
        return CallbackList()
969
0
    }
970
}
971
972
// MARK: and
973
974
extension EventLoopFuture {
975
    /// Return a new `EventLoopFuture` that succeeds when this "and" another
976
    /// provided `EventLoopFuture` both succeed. It then provides the pair
977
    /// of results. If either one fails, the combined `EventLoopFuture` will fail with
978
    /// the first error encountered.
979
    ///
980
    /// - Note: The `NewValue` must be `Sendable` since the isolation domains of this future and the other future might differ i.e.
981
    /// they might be bound to different event loops.
982
    @preconcurrency
983
    @inlinable
984
    public func and<OtherValue: Sendable>(
985
        _ other: EventLoopFuture<OtherValue>
986
0
    ) -> EventLoopFuture<(Value, OtherValue)> {
987
0
        let promise = EventLoopPromise<(Value, OtherValue)>.makeUnleakablePromise(eventLoop: self.eventLoop)
988
0
        let box: UnsafeMutableTransferBox<(t: Value?, u: OtherValue?)> = .init((nil, nil))
989
0
990
0
        assert(self.eventLoop === promise.futureResult.eventLoop)
991
0
        self._whenComplete { () -> CallbackList in
992
0
            switch self._value! {
993
0
            case .failure(let error):
994
0
                return promise._setValue(value: .failure(error))
995
0
            case .success(let t):
996
0
                if let u = box.wrappedValue.u {
997
0
                    return promise._setValue(value: .success((t, u)))
998
0
                } else {
999
0
                    box.wrappedValue.t = t
1000
0
                }
1001
0
            }
1002
0
            return CallbackList()
1003
0
        }
1004
0
1005
0
        let hopOver = other.hop(to: self.eventLoop)
1006
0
        hopOver._whenComplete { () -> CallbackList in
1007
0
            self.eventLoop.assertInEventLoop()
1008
0
            switch other._value! {
1009
0
            case .failure(let error):
1010
0
                return promise._setValue(value: .failure(error))
1011
0
            case .success(let u):
1012
0
                if let t = box.wrappedValue.t {
1013
0
                    return promise._setValue(value: .success((t, u)))
1014
0
                } else {
1015
0
                    box.wrappedValue.u = u
1016
0
                }
1017
0
            }
1018
0
            return CallbackList()
1019
0
        }
1020
0
1021
0
        return promise.futureResult
1022
0
    }
1023
1024
    /// Return a new EventLoopFuture that contains this "and" another value.
1025
    /// This is just syntactic sugar for `future.and(loop.makeSucceedFuture(value))`.
1026
    @preconcurrency
1027
    @inlinable
1028
    public func and<OtherValue: Sendable>(
1029
        value: OtherValue  // TODO: This should be transferring
1030
0
    ) -> EventLoopFuture<(Value, OtherValue)> {
1031
0
        self.and(EventLoopFuture<OtherValue>(eventLoop: self.eventLoop, value: value))
1032
0
    }
1033
}
1034
1035
// MARK: cascade
1036
1037
extension EventLoopFuture {
1038
    /// Fulfills the given `EventLoopPromise` with the results from this `EventLoopFuture`.
1039
    ///
1040
    /// This is useful when allowing users to provide promises for you to fulfill, but
1041
    /// when you are calling functions that return their own promises. They allow you to
1042
    /// tidy up your computational pipelines.
1043
    ///
1044
    /// For example:
1045
    /// ```
1046
    /// doWork().flatMap {
1047
    ///     doMoreWork($0)
1048
    /// }.flatMap {
1049
    ///     doYetMoreWork($0)
1050
    /// }.flatMapError {
1051
    ///     maybeRecoverFromError($0)
1052
    /// }.map {
1053
    ///     transformData($0)
1054
    /// }.cascade(to: userPromise)
1055
    /// ```
1056
    ///
1057
    /// - Note: The `Value` must be `Sendable` since the isolation domains of this future and the promise might differ i.e.
1058
    /// they might be bound to different event loops.
1059
    ///
1060
    /// - Parameter promise: The `EventLoopPromise` to fulfill with the results of this future.
1061
    /// - SeeAlso: `EventLoopPromise.completeWith(_:)`
1062
    @preconcurrency
1063
    @inlinable
1064
0
    public func cascade(to promise: EventLoopPromise<Value>?) where Value: Sendable {
1065
0
        guard let promise = promise else { return }
1066
0
        self.whenComplete { result in
1067
0
            switch result {
1068
0
            case let .success(value): promise.succeed(value)
1069
0
            case let .failure(error): promise.fail(error)
1070
0
            }
1071
0
        }
1072
0
    }
1073
1074
    /// Fulfills the given `EventLoopPromise` only when this `EventLoopFuture` succeeds.
1075
    ///
1076
    /// If you are doing work that fulfills a type that doesn't match the expected `EventLoopPromise` value, add an
1077
    /// intermediate `map`.
1078
    ///
1079
    /// For example:
1080
    /// ```
1081
    /// let boolPromise = eventLoop.makePromise(of: Bool.self)
1082
    /// doWorkReturningInt().map({ $0 >= 0 }).cascade(to: boolPromise)
1083
    /// ```
1084
    ///
1085
    /// - Note: The `Value` must be `Sendable` since the isolation domains of this future and the promise might differ i.e.
1086
    /// they might be bound to different event loops.
1087
    ///
1088
    /// - Parameter promise: The `EventLoopPromise` to fulfill when a successful result is available.
1089
    @preconcurrency
1090
    @inlinable
1091
0
    public func cascadeSuccess(to promise: EventLoopPromise<Value>?) where Value: Sendable {
1092
0
        guard let promise = promise else { return }
1093
0
        self.whenSuccess { promise.succeed($0) }
1094
0
    }
1095
1096
    /// Fails the given `EventLoopPromise` with the error from this `EventLoopFuture` if encountered.
1097
    ///
1098
    /// This is an alternative variant of `cascade` that allows you to potentially return early failures in
1099
    /// error cases, while passing the user `EventLoopPromise` onwards.
1100
    ///
1101
    ///
1102
    /// - Parameter promise: The `EventLoopPromise` that should fail with the error of this `EventLoopFuture`.
1103
    @inlinable
1104
0
    public func cascadeFailure<NewValue>(to promise: EventLoopPromise<NewValue>?) {
1105
0
        guard let promise = promise else { return }
1106
0
        self.whenFailure { promise.fail($0) }
1107
0
    }
1108
}
1109
1110
// MARK: wait
1111
1112
extension EventLoopFuture {
1113
    /// Wait for the resolution of this `EventLoopFuture` by blocking the current thread until it
1114
    /// resolves.
1115
    ///
1116
    /// If the `EventLoopFuture` resolves with a value, that value is returned from `wait()`. If
1117
    /// the `EventLoopFuture` resolves with an error, that error will be thrown instead.
1118
    /// `wait()` will block whatever thread it is called on, so it must not be called on event loop
1119
    /// threads: it is primarily useful for testing, or for building interfaces between blocking
1120
    /// and non-blocking code.
1121
    ///
1122
    /// This is also forbidden in async contexts: prefer ``EventLoopFuture/get()``.
1123
    ///
1124
    /// - Note: The `Value` must be `Sendable` since it is shared outside of the isolation domain of the event loop.
1125
    ///
1126
    /// - Returns: The value of the `EventLoopFuture` when it completes.
1127
    /// - Throws: The error value of the `EventLoopFuture` if it errors.
1128
    @available(*, noasync, message: "wait() can block indefinitely, prefer get()", renamed: "get()")
1129
    @preconcurrency
1130
    @inlinable
1131
354k
    public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value where Value: Sendable {
1132
        #if os(WASI)
1133
        // NOTE: As of July 22, 2025 `wait()` calling wait() is not supported on WASI platforms.
1134
        //
1135
        // This may change down the road if and when true multi-threading evolves. But right now
1136
        // calling wait here results in the following runtime crash:
1137
        //
1138
        // ```
1139
        // SomeExecutable.wasm:0x123456 Uncaught (in promise) RuntimeError: Atomics.wait cannot be called in this context
1140
        // ```
1141
        //
1142
        // Using the following fatal error here gives wasm runtime users a much more clear error message
1143
        // to identify the issue.
1144
        //
1145
        // If you're running into this error on WASI, refactoring to `get()` instead of `wait()` will
1146
        // likely solve the issue.
1147
        fatalError(
1148
            "NIO's wait() function should not be called on WASI platforms. It will freeze or crash. Use get() instead."
1149
        )
1150
        #else
1151
354k
        try self._blockingWaitForFutureCompletion(file: file, line: line)
1152
        #endif
1153
354k
    }
1154
1155
    @inlinable
1156
    @inline(never)
1157
208k
    func _blockingWaitForFutureCompletion(file: StaticString, line: UInt) throws -> Value where Value: Sendable {
1158
208k
        self.eventLoop._preconditionSafeToWait(file: file, line: line)
1159
208k
1160
208k
        let v: UnsafeMutableTransferBox<Result<Value, Error>?> = .init(nil)
1161
208k
        let lock = ConditionLock(value: 0)
1162
208k
        self._whenComplete { () -> CallbackList in
1163
208k
            lock.lock()
1164
208k
            v.wrappedValue = self._value
1165
208k
            lock.unlock(withValue: 1)
1166
208k
            return CallbackList()
1167
208k
        }
1168
208k
        lock.lock(whenValue: 1)
1169
208k
        lock.unlock()
1170
208k
1171
208k
        switch v.wrappedValue! {
1172
208k
        case .success(let result):
1173
208k
            return result
1174
208k
        case .failure(let error):
1175
0
            throw error
1176
208k
        }
1177
208k
    }
1178
}
1179
1180
// MARK: fold
1181
1182
extension EventLoopFuture {
1183
    /// Returns a new `EventLoopFuture` that fires only when this `EventLoopFuture` and
1184
    /// all the provided `futures` complete. It then provides the result of folding the value of this
1185
    /// `EventLoopFuture` with the values of all the provided `futures`.
1186
    ///
1187
    /// This function is suited when you have APIs that already know how to return `EventLoopFuture`s.
1188
    ///
1189
    /// The returned `EventLoopFuture` will fail as soon as the a failure is encountered in any of the
1190
    /// `futures` (or in this one). However, the failure will not occur until all preceding
1191
    /// `EventLoopFutures` have completed. At the point the failure is encountered, all subsequent
1192
    /// `EventLoopFuture` objects will no longer be waited for. This function therefore fails fast: once
1193
    /// a failure is encountered, it will immediately fail the overall EventLoopFuture.
1194
    ///
1195
    /// - Note: The `Value` and `NewValue` must be `Sendable` since the isolation domains of this future and the other futures might differ i.e.
1196
    /// they might be bound to different event loops.
1197
    ///
1198
    /// - Parameters:
1199
    ///   - futures: An array of `EventLoopFuture<NewValue>` to wait for.
1200
    ///   - combiningFunction: A function that will be used to fold the values of two `EventLoopFuture`s and return a new value wrapped in an `EventLoopFuture`.
1201
    /// - Returns: A new `EventLoopFuture` with the folded value whose callbacks run on `self.eventLoop`.
1202
    @inlinable
1203
    @preconcurrency
1204
    public func fold<OtherValue: Sendable>(
1205
        _ futures: [EventLoopFuture<OtherValue>],
1206
        with combiningFunction: @escaping @Sendable (Value, OtherValue) -> EventLoopFuture<Value>
1207
0
    ) -> EventLoopFuture<Value> where Value: Sendable {
1208
0
        @Sendable
1209
0
        func fold0() -> EventLoopFuture<Value> {
1210
0
            let body = futures.reduce(self) {
1211
0
                (f1: EventLoopFuture<Value>, f2: EventLoopFuture<OtherValue>) -> EventLoopFuture<Value> in
1212
0
                let newFuture = f1.and(f2).flatMap { (args: (Value, OtherValue)) -> EventLoopFuture<Value> in
1213
0
                    let (f1Value, f2Value) = args
1214
0
                    self.eventLoop.assertInEventLoop()
1215
0
                    return combiningFunction(f1Value, f2Value)
1216
0
                }
1217
0
                assert(newFuture.eventLoop === self.eventLoop)
1218
0
                return newFuture
1219
0
            }
1220
0
            return body
1221
0
        }
1222
0
1223
0
        if self.eventLoop.inEventLoop {
1224
0
            return fold0()
1225
0
        } else {
1226
0
            let promise = self.eventLoop.makePromise(of: Value.self)
1227
0
            self.eventLoop.execute {
1228
0
                fold0().cascade(to: promise)
1229
0
            }
1230
0
            return promise.futureResult
1231
0
        }
1232
0
    }
1233
}
1234
1235
// MARK: reduce
1236
1237
extension EventLoopFuture {
1238
    /// Returns a new `EventLoopFuture` that fires only when all the provided futures complete.
1239
    /// The new `EventLoopFuture` contains the result of reducing the `initialResult` with the
1240
    /// values of the `[EventLoopFuture<NewValue>]`.
1241
    ///
1242
    /// This function makes copies of the result for each EventLoopFuture, for a version which avoids
1243
    /// making copies, check out `reduce<NewValue>(into:)`.
1244
    ///
1245
    /// The returned `EventLoopFuture` will fail as soon as a failure is encountered in any of the
1246
    /// `futures`. However, the failure will not occur until all preceding
1247
    /// `EventLoopFutures` have completed. At the point the failure is encountered, all subsequent
1248
    /// `EventLoopFuture` objects will no longer be waited for. This function therefore fails fast: once
1249
    /// a failure is encountered, it will immediately fail the overall `EventLoopFuture`.
1250
    ///
1251
    /// - Note: The `Value` and `InputValue` must be `Sendable` since the isolation domains of this future and the other futures might differ i.e.
1252
    /// they might be bound to different event loops.
1253
    ///
1254
    /// - Parameters:
1255
    ///   - initialResult: An initial result to begin the reduction.
1256
    ///   - futures: An array of `EventLoopFuture` to wait for.
1257
    ///   - eventLoop: The `EventLoop` on which the new `EventLoopFuture` callbacks will fire.
1258
    ///   - nextPartialResult: The bifunction used to produce partial results.
1259
    /// - Returns: A new `EventLoopFuture` with the reduced value.
1260
    @preconcurrency
1261
    @inlinable
1262
    public static func reduce<InputValue: Sendable>(
1263
        _ initialResult: Value,
1264
        _ futures: [EventLoopFuture<InputValue>],
1265
        on eventLoop: EventLoop,
1266
        _ nextPartialResult: @escaping @Sendable (Value, InputValue) -> Value
1267
0
    ) -> EventLoopFuture<Value> where Value: Sendable {
1268
0
        Self._reduce(initialResult, futures, on: eventLoop, nextPartialResult)
1269
0
    }
1270
    @usableFromInline typealias ReduceCallback<InputValue> = @Sendable (Value, InputValue) -> Value
1271
1272
    @inlinable
1273
    static func _reduce<InputValue: Sendable>(
1274
        _ initialResult: Value,
1275
        _ futures: [EventLoopFuture<InputValue>],
1276
        on eventLoop: EventLoop,
1277
        _ nextPartialResult: @escaping ReduceCallback<InputValue>
1278
0
    ) -> EventLoopFuture<Value> where Value: Sendable {
1279
0
        let f0 = eventLoop.makeSucceededFuture(initialResult)
1280
0
1281
0
        let body = f0.fold(futures) { (t: Value, u: InputValue) -> EventLoopFuture<Value> in
1282
0
            eventLoop.makeSucceededFuture(nextPartialResult(t, u))
1283
0
        }
1284
0
1285
0
        return body
1286
0
    }
1287
1288
    /// Returns a new `EventLoopFuture` that fires only when all the provided futures complete.
1289
    /// The new `EventLoopFuture` contains the result of combining the `initialResult` with the
1290
    /// values of the `[EventLoopFuture<NewValue>]`. This function is analogous to the standard library's
1291
    /// `reduce(into:)`, which does not make copies of the result type for each `EventLoopFuture`.
1292
    ///
1293
    /// The returned `EventLoopFuture` will fail as soon as a failure is encountered in any of the
1294
    /// `futures`. However, the failure will not occur until all preceding
1295
    /// `EventLoopFutures` have completed. At the point the failure is encountered, all subsequent
1296
    /// `EventLoopFuture` objects will no longer be waited for. This function therefore fails fast: once
1297
    /// a failure is encountered, it will immediately fail the overall `EventLoopFuture`.
1298
    ///
1299
    /// - Note: The `Value` and `InputValue` must be `Sendable` since the isolation domains of this future and the other futures might differ i.e.
1300
    /// they might be bound to different event loops.
1301
    ///
1302
    /// - Parameters:
1303
    ///   - initialResult: An initial result to begin the reduction.
1304
    ///   - futures: An array of `EventLoopFuture` to wait for.
1305
    ///   - eventLoop: The `EventLoop` on which the new `EventLoopFuture` callbacks will fire.
1306
    ///   - updateAccumulatingResult: The bifunction used to combine partialResults with new elements.
1307
    /// - Returns: A new `EventLoopFuture` with the combined value.
1308
    @inlinable
1309
    @preconcurrency
1310
    public static func reduce<InputValue: Sendable>(
1311
        into initialResult: Value,
1312
        _ futures: [EventLoopFuture<InputValue>],
1313
        on eventLoop: EventLoop,
1314
        _ updateAccumulatingResult: @escaping @Sendable (inout Value, InputValue) -> Void
1315
0
    ) -> EventLoopFuture<Value> where Value: Sendable {
1316
0
        let p0 = eventLoop.makePromise(of: Value.self)
1317
0
        let value = NIOLoopBoundBox<Value>(_value: initialResult, uncheckedEventLoop: eventLoop)
1318
0
1319
0
        let f0 = eventLoop.makeSucceededFuture(())
1320
0
        let future = f0.fold(futures) { (_: (), newValue: InputValue) -> EventLoopFuture<Void> in
1321
0
            eventLoop.assertInEventLoop()
1322
0
            var v = value.value
1323
0
            updateAccumulatingResult(&v, newValue)
1324
0
            value.value = v
1325
0
            return eventLoop.makeSucceededFuture(())
1326
0
        }
1327
0
1328
0
        future.whenSuccess {
1329
0
            eventLoop.assertInEventLoop()
1330
0
            p0.succeed(value.value)
1331
0
        }
1332
0
        future.whenFailure { (error) in
1333
0
            eventLoop.assertInEventLoop()
1334
0
            p0.fail(error)
1335
0
        }
1336
0
        return p0.futureResult
1337
0
    }
1338
}
1339
1340
// MARK: "fail fast" reduce
1341
1342
extension EventLoopFuture {
1343
    /// Returns a new `EventLoopFuture` that succeeds only if all of the provided futures succeed.
1344
    ///
1345
    /// This method acts as a successful completion notifier - values fulfilled by each future are discarded.
1346
    ///
1347
    /// The returned `EventLoopFuture` fails as soon as any of the provided futures fail.
1348
    ///
1349
    /// If it is desired to always succeed, regardless of failures, use `andAllComplete` instead.
1350
    /// - Parameters:
1351
    ///   - futures: An array of homogenous `EventLoopFutures`s to wait for.
1352
    ///   - eventLoop: The `EventLoop` on which the new `EventLoopFuture` callbacks will execute on.
1353
    /// - Returns: A new `EventLoopFuture` that waits for the other futures to succeed.
1354
    @inlinable
1355
    public static func andAllSucceed(
1356
        _ futures: [EventLoopFuture<Value>],
1357
        on eventLoop: EventLoop
1358
0
    ) -> EventLoopFuture<Void> {
1359
0
        let promise = eventLoop.makePromise(of: Void.self)
1360
0
        EventLoopFuture.andAllSucceed(futures, promise: promise)
1361
0
        return promise.futureResult
1362
0
    }
1363
1364
    /// Succeeds the promise if all of the provided futures succeed. If any of the provided
1365
    /// futures fail then the `promise` will be failed -- even if some futures are yet to complete.
1366
    ///
1367
    /// If the results of all futures should be collected use `andAllComplete` instead.
1368
    ///
1369
    /// - Parameters:
1370
    ///   - futures: An array of homogenous `EventLoopFutures`s to wait for.
1371
    ///   - promise: The `EventLoopPromise` to complete with the result of this call.
1372
    @inlinable
1373
    public static func andAllSucceed(
1374
        _ futures: [EventLoopFuture<Value>],
1375
        promise: EventLoopPromise<Void>
1376
0
    ) {
1377
0
        let eventLoop = promise.futureResult.eventLoop
1378
0
1379
0
        if eventLoop.inEventLoop {
1380
0
            self._reduceSuccesses0(promise, futures, eventLoop)
1381
0
        } else {
1382
0
            eventLoop.execute {
1383
0
                self._reduceSuccesses0(promise, futures, eventLoop)
1384
0
            }
1385
0
        }
1386
0
    }
1387
1388
    /// Returns a new `EventLoopFuture` that succeeds only if all of the provided futures succeed.
1389
    /// The new `EventLoopFuture` will contain all of the values fulfilled by the futures.
1390
    ///
1391
    /// The returned `EventLoopFuture` will fail as soon as any of the futures fails.
1392
    ///
1393
    /// - Note: The `Value` must be `Sendable` since the isolation domains of the futures might differ i.e.
1394
    /// they might be bound to different event loops.
1395
    ///
1396
    /// - Parameters:
1397
    ///   - futures: An array of homogenous `EventLoopFuture`s to wait on for fulfilled values.
1398
    ///   - eventLoop: The `EventLoop` on which the new `EventLoopFuture` callbacks will fire.
1399
    /// - Returns: A new `EventLoopFuture` with all of the values fulfilled by the provided futures.
1400
    @preconcurrency
1401
    public static func whenAllSucceed(
1402
        _ futures: [EventLoopFuture<Value>],
1403
        on eventLoop: EventLoop
1404
0
    ) -> EventLoopFuture<[Value]> where Value: Sendable {
1405
0
        let promise = eventLoop.makePromise(of: [Value].self)
1406
0
        EventLoopFuture.whenAllSucceed(futures, promise: promise)
1407
0
        return promise.futureResult
1408
0
    }
1409
1410
    /// Completes the `promise` with the values of all `futures` if all provided futures succeed. If
1411
    /// any of the provided futures fail then `promise` will be failed.
1412
    ///
1413
    /// If the _results of all futures should be collected use `andAllComplete` instead.
1414
    ///
1415
    /// - Note: The `Value` must be `Sendable` since the isolation domains of the futures might differ i.e.
1416
    /// they might be bound to different event loops.
1417
    ///
1418
    /// - Parameters:
1419
    ///   - futures: An array of homogenous `EventLoopFutures`s to wait for.
1420
    ///   - promise: The `EventLoopPromise` to complete with the result of this call.
1421
    @preconcurrency
1422
    public static func whenAllSucceed(
1423
        _ futures: [EventLoopFuture<Value>],
1424
        promise: EventLoopPromise<[Value]>
1425
0
    ) where Value: Sendable {
1426
0
        let eventLoop = promise.futureResult.eventLoop
1427
0
        let reduced = eventLoop.makePromise(of: Void.self)
1428
0
1429
0
        let results: UnsafeMutableTransferBox<[Value?]> = .init(.init(repeating: nil, count: futures.count))
1430
0
        let callback = { @Sendable (index: Int, result: Value) in
1431
0
            results.wrappedValue[index] = result
1432
0
        }
1433
0
1434
0
        if eventLoop.inEventLoop {
1435
0
            self._reduceSuccesses0(reduced, futures, eventLoop, onValue: callback)
1436
0
        } else {
1437
0
            eventLoop.execute {
1438
0
                self._reduceSuccesses0(reduced, futures, eventLoop, onValue: callback)
1439
0
            }
1440
0
        }
1441
0
1442
0
        reduced.futureResult.whenComplete { result in
1443
0
            switch result {
1444
0
            case .success:
1445
0
                // verify that all operations have been completed
1446
0
                assert(!results.wrappedValue.contains(where: { $0 == nil }))
1447
0
                promise.succeed(results.wrappedValue.map { $0! })
1448
0
            case .failure(let error):
1449
0
                promise.fail(error)
1450
0
            }
1451
0
        }
1452
0
    }
1453
1454
    /// Loops through the futures array and attaches callbacks to execute `onValue` on the provided `EventLoop` when
1455
    /// they succeed. The `onValue` will receive the index of the future that fulfilled the provided `Result`.
1456
    ///
1457
    /// Once all the futures have succeed, the provided promise will succeed.
1458
    /// Once any future fails, the provided promise will fail.
1459
    @inlinable
1460
    internal static func _reduceSuccesses0<InputValue>(
1461
        _ promise: EventLoopPromise<Void>,
1462
        _ futures: [EventLoopFuture<InputValue>],
1463
        _ eventLoop: EventLoop,
1464
        onValue: @escaping @Sendable (Int, InputValue) -> Void
1465
0
    ) where InputValue: Sendable {
1466
0
        eventLoop.assertInEventLoop()
1467
0
1468
0
        if futures.count == 0 {
1469
0
            promise.succeed(())
1470
0
            return
1471
0
        }
1472
0
1473
0
        let remainingCount = NIOLoopBoundBox(_value: futures.count, uncheckedEventLoop: eventLoop)
1474
0
1475
0
        // Sends the result to `onValue` in case of success and succeeds/fails the input promise, if appropriate.
1476
0
        @Sendable
1477
0
        func processResult(_ index: Int, _ result: Result<InputValue, Error>) {
1478
0
            switch result {
1479
0
            case .success(let result):
1480
0
                onValue(index, result)
1481
0
                remainingCount.value -= 1
1482
0
1483
0
                if remainingCount.value == 0 {
1484
0
                    promise.succeed(())
1485
0
                }
1486
0
            case .failure(let error):
1487
0
                promise.fail(error)
1488
0
            }
1489
0
        }
1490
0
        // loop through the futures to chain callbacks to execute on the initiating event loop and grab their index
1491
0
        // in the "futures" to pass their result to the caller
1492
0
        for (index, future) in futures.enumerated() {
1493
0
            if future.eventLoop.inEventLoop,
1494
0
                let result = future._value
1495
0
            {
1496
0
                // Fast-track already-fulfilled results without the overhead of calling `whenComplete`. This can yield a
1497
0
                // ~20% performance improvement in the case of large arrays where all elements are already fulfilled.
1498
0
                processResult(index, result)
1499
0
                if case .failure = result {
1500
0
                    return  // Once the promise is failed, future results do not need to be processed.
1501
0
                }
1502
0
            } else {
1503
0
                future.hop(to: eventLoop)
1504
0
                    .whenComplete { result in processResult(index, result) }
1505
0
            }
1506
0
        }
1507
0
    }
1508
1509
    /// Loops through the futures array and attaches callbacks to execute `onValue` on the provided `EventLoop` when
1510
    /// they succeed. The `onValue` will receive the index of the future that fulfilled the provided `Result`.
1511
    ///
1512
    /// Once all the futures have succeed, the provided promise will succeed.
1513
    /// Once any future fails, the provided promise will fail.
1514
    @inlinable
1515
    internal static func _reduceSuccesses0(
1516
        _ promise: EventLoopPromise<Void>,
1517
        _ futures: [EventLoopFuture<Value>],
1518
        _ eventLoop: EventLoop
1519
0
    ) {
1520
0
        eventLoop.assertInEventLoop()
1521
0
1522
0
        if futures.count == 0 {
1523
0
            promise.succeed(())
1524
0
            return
1525
0
        }
1526
0
1527
0
        let remainingCount = NIOLoopBoundBox(_value: futures.count, uncheckedEventLoop: eventLoop)
1528
0
1529
0
        // Sends the result to `onValue` in case of success and succeeds/fails the input promise, if appropriate.
1530
0
        @Sendable
1531
0
        func processResult(_ index: Int, _ result: Result<Void, Error>) {
1532
0
            switch result {
1533
0
            case .success:
1534
0
                remainingCount.value -= 1
1535
0
1536
0
                if remainingCount.value == 0 {
1537
0
                    promise.succeed(())
1538
0
                }
1539
0
            case .failure(let error):
1540
0
                promise.fail(error)
1541
0
            }
1542
0
        }
1543
0
        // loop through the futures to chain callbacks to execute on the initiating event loop and grab their index
1544
0
        // in the "futures" to pass their result to the caller
1545
0
        for (index, future) in futures.enumerated() {
1546
0
            if future.eventLoop.inEventLoop,
1547
0
                let result = future._value
1548
0
            {
1549
0
                // Fast-track already-fulfilled results without the overhead of calling `whenComplete`. This can yield a
1550
0
                // ~20% performance improvement in the case of large arrays where all elements are already fulfilled.
1551
0
                switch result {
1552
0
                case .success:
1553
0
                    processResult(index, .success(()))
1554
0
                case .failure(let error):
1555
0
                    processResult(index, .failure(error))
1556
0
                    return
1557
0
                }
1558
0
            } else {
1559
0
                // We have to map to `Void` here to avoid sharing the potentially non-Sendable
1560
0
                // value across event loops.
1561
0
                future.whenComplete { result in
1562
0
                    let voidResult = result.map { _ in }
1563
0
                    if eventLoop.inEventLoop {
1564
0
                        processResult(index, voidResult)
1565
0
                    } else {
1566
0
                        eventLoop.execute {
1567
0
                            processResult(index, voidResult)
1568
0
                        }
1569
0
                    }
1570
0
                }
1571
0
            }
1572
0
        }
1573
0
    }
1574
}
1575
1576
// MARK: "fail slow" reduce
1577
1578
extension EventLoopFuture {
1579
    /// Returns a new `EventLoopFuture` that succeeds when all of the provided `EventLoopFuture`s complete.
1580
    ///
1581
    /// The returned `EventLoopFuture` always succeeds, acting as a completion notification.
1582
    /// Values fulfilled by each future are discarded.
1583
    ///
1584
    /// If the results are needed, use `whenAllComplete` instead.
1585
    /// - Parameters:
1586
    ///   - futures: An array of homogenous `EventLoopFuture`s to wait for.
1587
    ///   - eventLoop: The `EventLoop` on which the new `EventLoopFuture` callbacks will execute on.
1588
    /// - Returns: A new `EventLoopFuture` that succeeds after all futures complete.
1589
    @inlinable
1590
    public static func andAllComplete(
1591
        _ futures: [EventLoopFuture<Value>],
1592
        on eventLoop: EventLoop
1593
0
    ) -> EventLoopFuture<Void> {
1594
0
        let promise = eventLoop.makePromise(of: Void.self)
1595
0
        EventLoopFuture.andAllComplete(futures, promise: promise)
1596
0
        return promise.futureResult
1597
0
    }
1598
1599
    /// Completes a `promise` when all of the provided `EventLoopFuture`s have completed.
1600
    ///
1601
    /// The promise will always be succeeded, regardless of the outcome of the individual futures.
1602
    ///
1603
    /// If the results are required, use `whenAllComplete` instead.
1604
    ///
1605
    /// - Parameters:
1606
    ///   - futures: An array of homogenous `EventLoopFuture`s to wait for.
1607
    ///   - promise: The `EventLoopPromise` to succeed when all futures have completed.
1608
    @inlinable
1609
    public static func andAllComplete(
1610
        _ futures: [EventLoopFuture<Value>],
1611
        promise: EventLoopPromise<Void>
1612
0
    ) {
1613
0
        let eventLoop = promise.futureResult.eventLoop
1614
0
1615
0
        if eventLoop.inEventLoop {
1616
0
            self._reduceCompletions0(promise, futures, eventLoop)
1617
0
        } else {
1618
0
            eventLoop.execute {
1619
0
                self._reduceCompletions0(promise, futures, eventLoop)
1620
0
            }
1621
0
        }
1622
0
    }
1623
1624
    /// Returns a new `EventLoopFuture` that succeeds when all of the provided `EventLoopFuture`s complete.
1625
    /// The new `EventLoopFuture` will contain an array of results, maintaining ordering for each of the `EventLoopFuture`s.
1626
    ///
1627
    /// The returned `EventLoopFuture` always succeeds, regardless of any failures from the waiting futures.
1628
    ///
1629
    /// - Note: The `Value` must be `Sendable` since the isolation domains of the futures might differ i.e.
1630
    /// they might be bound to different event loops.
1631
    ///
1632
    /// If it is desired to flatten them into a single `EventLoopFuture` that fails on the first `EventLoopFuture` failure,
1633
    /// use one of the `reduce` methods instead.
1634
    /// - Parameters:
1635
    ///   - futures: An array of homogenous `EventLoopFuture`s to gather results from.
1636
    ///   - eventLoop: The `EventLoop` on which the new `EventLoopFuture` callbacks will fire.
1637
    /// - Returns: A new `EventLoopFuture` with all the results of the provided futures.
1638
    @preconcurrency
1639
    @inlinable
1640
    public static func whenAllComplete(
1641
        _ futures: [EventLoopFuture<Value>],
1642
        on eventLoop: EventLoop
1643
0
    ) -> EventLoopFuture<[Result<Value, Error>]> where Value: Sendable {
1644
0
        let promise = eventLoop.makePromise(of: [Result<Value, Error>].self)
1645
0
        EventLoopFuture.whenAllComplete(futures, promise: promise)
1646
0
        return promise.futureResult
1647
0
    }
1648
1649
    /// Completes a `promise` with the results of all provided `EventLoopFuture`s.
1650
    ///
1651
    /// The promise will always be succeeded, regardless of the outcome of the futures.
1652
    ///
1653
    /// - Note: The `Value` must be `Sendable` since the isolation domains of the futures might differ i.e.
1654
    /// they might be bound to different event loops.
1655
    ///
1656
    /// - Parameters:
1657
    ///   - futures: An array of homogenous `EventLoopFuture`s to gather results from.
1658
    ///   - promise: The `EventLoopPromise` to complete with the result of the futures.
1659
    @preconcurrency
1660
    @inlinable
1661
    public static func whenAllComplete(
1662
        _ futures: [EventLoopFuture<Value>],
1663
        promise: EventLoopPromise<[Result<Value, Error>]>
1664
0
    ) where Value: Sendable {
1665
0
        let eventLoop = promise.futureResult.eventLoop
1666
0
        let reduced = eventLoop.makePromise(of: Void.self)
1667
0
1668
0
        let results: UnsafeMutableTransferBox<[Result<Value, Error>]> = .init(
1669
0
            .init(repeating: .failure(OperationPlaceholderError()), count: futures.count)
1670
0
        )
1671
0
        let callback = { @Sendable (index: Int, result: Result<Value, Error>) in
1672
0
            results.wrappedValue[index] = result
1673
0
        }
1674
0
1675
0
        if eventLoop.inEventLoop {
1676
0
            self._reduceCompletions0(reduced, futures, eventLoop, onResult: callback)
1677
0
        } else {
1678
0
            eventLoop.execute {
1679
0
                self._reduceCompletions0(reduced, futures, eventLoop, onResult: callback)
1680
0
            }
1681
0
        }
1682
0
1683
0
        reduced.futureResult.whenComplete { result in
1684
0
            switch result {
1685
0
            case .success:
1686
0
                // verify that all operations have been completed
1687
0
                assert(
1688
0
                    !results.wrappedValue.contains(where: {
1689
0
                        guard case let .failure(error) = $0 else { return false }
1690
0
                        return error is OperationPlaceholderError
1691
0
                    })
1692
0
                )
1693
0
                promise.succeed(results.wrappedValue)
1694
0
1695
0
            case .failure(let error):
1696
0
                promise.fail(error)
1697
0
            }
1698
0
        }
1699
0
    }
1700
1701
    /// Loops through the futures array and attaches callbacks to execute `onResult` on the provided `EventLoop` when
1702
    /// they complete. The `onResult` will receive the index of the future that fulfilled the provided `Result`.
1703
    ///
1704
    /// Once all the futures have completed, the provided promise will succeed.
1705
    @inlinable
1706
    internal static func _reduceCompletions0<InputValue: Sendable>(
1707
        _ promise: EventLoopPromise<Void>,
1708
        _ futures: [EventLoopFuture<InputValue>],
1709
        _ eventLoop: EventLoop,
1710
        onResult: @escaping @Sendable (Int, Result<InputValue, Error>) -> Void
1711
0
    ) {
1712
0
        eventLoop.assertInEventLoop()
1713
0
1714
0
        if futures.count == 0 {
1715
0
            promise.succeed(())
1716
0
            return
1717
0
        }
1718
0
1719
0
        let remainingCount = NIOLoopBoundBox(_value: futures.count, uncheckedEventLoop: eventLoop)
1720
0
1721
0
        // Sends the result to `onResult` in case of success and succeeds the input promise, if appropriate.
1722
0
        @Sendable
1723
0
        func processResult(_ index: Int, _ result: Result<InputValue, Error>) {
1724
0
            onResult(index, result)
1725
0
            remainingCount.value -= 1
1726
0
1727
0
            if remainingCount.value == 0 {
1728
0
                promise.succeed(())
1729
0
            }
1730
0
        }
1731
0
        // loop through the futures to chain callbacks to execute on the initiating event loop and grab their index
1732
0
        // in the "futures" to pass their result to the caller
1733
0
        for (index, future) in futures.enumerated() {
1734
0
            if future.eventLoop.inEventLoop,
1735
0
                let result = future._value
1736
0
            {
1737
0
                // Fast-track already-fulfilled results without the overhead of calling `whenComplete`. This can yield a
1738
0
                // ~30% performance improvement in the case of large arrays where all elements are already fulfilled.
1739
0
                processResult(index, result)
1740
0
            } else {
1741
0
                future.hop(to: eventLoop)
1742
0
                    .whenComplete { result in processResult(index, result) }
1743
0
            }
1744
0
        }
1745
0
    }
1746
1747
    /// Loops through the futures array and attaches callbacks to execute `onResult` on the provided `EventLoop` when
1748
    /// they complete. The `onResult` will receive the index of the future that fulfilled the provided `Result`.
1749
    ///
1750
    /// Once all the futures have completed, the provided promise will succeed.
1751
    @inlinable
1752
    internal static func _reduceCompletions0(
1753
        _ promise: EventLoopPromise<Void>,
1754
        _ futures: [EventLoopFuture<Value>],
1755
        _ eventLoop: EventLoop
1756
0
    ) {
1757
0
        eventLoop.assertInEventLoop()
1758
0
1759
0
        if futures.count == 0 {
1760
0
            promise.succeed(())
1761
0
            return
1762
0
        }
1763
0
1764
0
        let remainingCount = NIOLoopBoundBox(_value: futures.count, uncheckedEventLoop: eventLoop)
1765
0
1766
0
        // Sends the result to `onResult` in case of success and succeeds the input promise, if appropriate.
1767
0
        @Sendable
1768
0
        func processResult(_ index: Int, _ result: Result<Void, Error>) {
1769
0
            remainingCount.value -= 1
1770
0
1771
0
            if remainingCount.value == 0 {
1772
0
                promise.succeed(())
1773
0
            }
1774
0
        }
1775
0
        // loop through the futures to chain callbacks to execute on the initiating event loop and grab their index
1776
0
        // in the "futures" to pass their result to the caller
1777
0
        for (index, future) in futures.enumerated() {
1778
0
            if future.eventLoop.inEventLoop,
1779
0
                let result = future._value
1780
0
            {
1781
0
                // Fast-track already-fulfilled results without the overhead of calling `whenComplete`. This can yield a
1782
0
                // ~30% performance improvement in the case of large arrays where all elements are already fulfilled.
1783
0
                switch result {
1784
0
                case .success:
1785
0
                    processResult(index, .success(()))
1786
0
                case .failure(let error):
1787
0
                    processResult(index, .failure(error))
1788
0
                }
1789
0
            } else {
1790
0
                // We have to map to `Void` here to avoid sharing the potentially non-Sendable
1791
0
                // value across event loops.
1792
0
                future.whenComplete { result in
1793
0
                    let voidResult = result.map { _ in }
1794
0
                    if eventLoop.inEventLoop {
1795
0
                        processResult(index, voidResult)
1796
0
                    } else {
1797
0
                        eventLoop.execute {
1798
0
                            processResult(index, voidResult)
1799
0
                        }
1800
0
                    }
1801
0
                }
1802
0
            }
1803
0
        }
1804
0
    }
1805
}
1806
1807
// MARK: hop
1808
1809
extension EventLoopFuture {
1810
    /// Returns an `EventLoopFuture` that fires when this future completes, but executes its callbacks on the
1811
    /// target event loop instead of the original one.
1812
    ///
1813
    /// It is common to want to "hop" event loops when you arrange some work: for example, you're closing one channel
1814
    /// from another, and want to hop back when the close completes. This method lets you spell that requirement
1815
    /// succinctly. It also contains an optimisation for the case when the loop you're hopping *from* is the same as
1816
    /// the one you're hopping *to*, allowing you to avoid doing allocations in that case.
1817
    ///
1818
    /// - Note: The `Value` must be `Sendable` since it is shared with the isolation domain of the target event loop.
1819
    ///
1820
    /// - Parameters:
1821
    ///   - target: The `EventLoop` that the returned `EventLoopFuture` will run on.
1822
    /// - Returns: An `EventLoopFuture` whose callbacks run on `target` instead of the original loop.
1823
    @preconcurrency
1824
    @inlinable
1825
0
    public func hop(to target: EventLoop) -> EventLoopFuture<Value> where Value: Sendable {
1826
0
        if target === self.eventLoop {
1827
0
            // We're already on that event loop, nothing to do here. Save an allocation.
1828
0
            return self
1829
0
        }
1830
0
        let hoppingPromise = target.makePromise(of: Value.self)
1831
0
        self.cascade(to: hoppingPromise)
1832
0
        return hoppingPromise.futureResult
1833
0
    }
1834
}
1835
1836
// MARK: always
1837
1838
extension EventLoopFuture {
1839
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
1840
    /// `EventLoopFuture` has any result.
1841
    ///
1842
    /// - Parameters:
1843
    ///   - callback: the callback that is called when the `EventLoopFuture` is fulfilled.
1844
    /// - Returns: the current `EventLoopFuture`
1845
    @inlinable
1846
    @preconcurrency
1847
0
    public func always(_ callback: @escaping @Sendable (Result<Value, Error>) -> Void) -> EventLoopFuture<Value> {
1848
0
        self.whenComplete { result in callback(result) }
1849
0
        return self
1850
0
    }
1851
}
1852
1853
// MARK: unwrap
1854
1855
extension EventLoopFuture {
1856
    /// Unwrap an `EventLoopFuture` where its type parameter is an `Optional`.
1857
    ///
1858
    /// Unwrap a future returning a new `EventLoopFuture`. When the resolved future's value is `Optional.some(...)`
1859
    /// the new future is created with the identical value. Otherwise the `Error` passed in the `orError` parameter
1860
    /// is thrown. For example:
1861
    /// ```
1862
    /// do {
1863
    ///     try promise.futureResult.unwrap(orError: ErrorToThrow).wait()
1864
    /// } catch ErrorToThrow {
1865
    ///     ...
1866
    /// }
1867
    /// ```
1868
    ///
1869
    /// - Parameters:
1870
    ///   - orError: the `Error` that is thrown when then resolved future's value is `Optional.none`.
1871
    /// - Returns: an new `EventLoopFuture` with new type parameter `NewValue` and the same value as the resolved
1872
    ///     future.
1873
    /// - Throws: the `Error` passed in the `orError` parameter when the resolved future's value is `Optional.none`.
1874
    @inlinable
1875
0
    public func unwrap<NewValue>(orError: Error) -> EventLoopFuture<NewValue> where Value == NewValue? {
1876
0
        self.flatMapThrowing { (value) throws -> NewValue in
1877
0
            guard let value = value else {
1878
0
                throw orError
1879
0
            }
1880
0
            return value
1881
0
        }
1882
0
    }
1883
1884
    /// Unwrap an `EventLoopFuture` where its type parameter is an `Optional`.
1885
    ///
1886
    /// Unwraps a future returning a new `EventLoopFuture` with either: the value passed in the `orReplace`
1887
    /// parameter when the future resolved with value Optional.none, or the same value otherwise. For example:
1888
    /// ```
1889
    /// promise.futureResult.unwrap(orReplace: 42).wait()
1890
    /// ```
1891
    ///
1892
    /// - Parameters:
1893
    ///   - replacement: the value of the returned `EventLoopFuture` when then resolved future's value is `Optional.some()`.
1894
    /// - Returns: an new `EventLoopFuture` with new type parameter `NewValue` and the value passed in the `replacement` parameter.
1895
    @preconcurrency
1896
    @inlinable
1897
    public func unwrap<NewValue: Sendable>(
1898
        orReplace replacement: NewValue
1899
0
    ) -> EventLoopFuture<NewValue> where Value == NewValue? {
1900
0
        self.map { (value) -> NewValue in
1901
0
            guard let value = value else {
1902
0
                return replacement
1903
0
            }
1904
0
            return value
1905
0
        }
1906
0
    }
1907
1908
    /// Unwrap an `EventLoopFuture` where its type parameter is an `Optional`.
1909
    ///
1910
    /// Unwraps a future returning a new `EventLoopFuture` with either: the value returned by the closure passed in
1911
    /// the `orElse` parameter when the future resolved with value Optional.none, or the same value otherwise. For example:
1912
    /// ```
1913
    /// var x = 2
1914
    /// promise.futureResult.unwrap(orElse: { x * 2 }).wait()
1915
    /// ```
1916
    ///
1917
    /// - Parameters:
1918
    ///   - callback: a closure that returns the value of the returned `EventLoopFuture` when then resolved future's value
1919
    ///         is `Optional.some()`.
1920
    /// - Returns: an new `EventLoopFuture` with new type parameter `NewValue` and with the value returned by the closure
1921
    ///     passed in the `callback` parameter.
1922
    @inlinable
1923
    @preconcurrency
1924
    public func unwrap<NewValue>(
1925
        orElse callback: @escaping @Sendable () -> NewValue
1926
0
    ) -> EventLoopFuture<NewValue> where Value == NewValue? {
1927
0
        self._unwrap(orElse: callback)
1928
0
    }
1929
    @usableFromInline typealias UnwrapCallback<NewValue> = @Sendable () -> NewValue
1930
1931
    @inlinable
1932
    func _unwrap<NewValue>(
1933
        orElse callback: @escaping UnwrapCallback<NewValue>
1934
0
    ) -> EventLoopFuture<NewValue> where Value == NewValue? {
1935
0
        self.map { (value) -> NewValue in
1936
0
            guard let value = value else {
1937
0
                return callback()
1938
0
            }
1939
0
            return value
1940
0
        }
1941
0
    }
1942
}
1943
1944
// MARK: may block
1945
1946
#if canImport(Dispatch)
1947
extension EventLoopFuture {
1948
    /// Chain an `EventLoopFuture<NewValue>` providing the result of a IO / task that may block. For example:
1949
    ///
1950
    ///     promise.futureResult.flatMapBlocking(onto: DispatchQueue.global()) { value in Int
1951
    ///         blockingTask(value)
1952
    ///     }
1953
    ///
1954
    /// - Note: The `Value` and `NewValue` must be `Sendable` since it is shared between the isolation region queue and the event loop.
1955
    ///
1956
    /// - Parameters:
1957
    ///   - queue: the `DispatchQueue` on which the blocking IO / task specified by `callbackMayBlock` is scheduled.
1958
    ///   - callbackMayBlock: Function that will receive the value of this `EventLoopFuture` and return
1959
    ///         a new `EventLoopFuture`.
1960
    @inlinable
1961
    @preconcurrency
1962
    public func flatMapBlocking<NewValue: Sendable>(
1963
        onto queue: DispatchQueue,
1964
        _ callbackMayBlock: @escaping @Sendable (Value) throws -> NewValue
1965
0
    ) -> EventLoopFuture<NewValue> where Value: Sendable {
1966
0
        self.flatMap { result in
1967
0
            queue.asyncWithFuture(eventLoop: self.eventLoop) { try callbackMayBlock(result) }
1968
0
        }
1969
0
    }
1970
1971
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
1972
    /// `EventLoopFuture` has a success result. The observer callback is permitted to block.
1973
    ///
1974
    /// An observer callback cannot return a value, meaning that this function cannot be chained
1975
    /// from. If you are attempting to create a computation pipeline, consider `map` or `flatMap`.
1976
    /// If you find yourself passing the results from this `EventLoopFuture` to a new `EventLoopPromise`
1977
    /// in the body of this function, consider using `cascade` instead.
1978
    ///
1979
    /// - Note: The `NewValue` must be `Sendable` since it is shared between the isolation region queue and the event loop.
1980
    ///
1981
    /// - Parameters:
1982
    ///   - queue: the `DispatchQueue` on which the blocking IO / task specified by `callbackMayBlock` is scheduled.
1983
    ///   - callbackMayBlock: The callback that is called with the successful result of the `EventLoopFuture`.
1984
    @preconcurrency
1985
    @inlinable
1986
    public func whenSuccessBlocking(
1987
        onto queue: DispatchQueue,
1988
        _ callbackMayBlock: @escaping @Sendable (Value) -> Void
1989
0
    ) where Value: Sendable {
1990
0
        self.whenSuccess { value in
1991
0
            queue.async { callbackMayBlock(value) }
1992
0
        }
1993
0
    }
1994
1995
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
1996
    /// `EventLoopFuture` has a failure result. The observer callback is permitted to block.
1997
    ///
1998
    /// An observer callback cannot return a value, meaning that this function cannot be chained
1999
    /// from. If you are attempting to create a computation pipeline, consider `recover` or `flatMapError`.
2000
    /// If you find yourself passing the results from this `EventLoopFuture` to a new `EventLoopPromise`
2001
    /// in the body of this function, consider using `cascade` instead.
2002
    ///
2003
    /// - Parameters:
2004
    ///   - queue: the `DispatchQueue` on which the blocking IO / task specified by `callbackMayBlock` is scheduled.
2005
    ///   - callbackMayBlock: The callback that is called with the failed result of the `EventLoopFuture`.
2006
    @inlinable
2007
    @preconcurrency
2008
    public func whenFailureBlocking(
2009
        onto queue: DispatchQueue,
2010
        _ callbackMayBlock: @escaping @Sendable (Error) -> Void
2011
0
    ) {
2012
0
        self._whenFailureBlocking(onto: queue, callbackMayBlock)
2013
0
    }
2014
    @usableFromInline typealias WhenFailureBlockingCallback = @Sendable (Error) -> Void
2015
2016
    @inlinable
2017
0
    func _whenFailureBlocking(onto queue: DispatchQueue, _ callbackMayBlock: @escaping WhenFailureBlockingCallback) {
2018
0
        self.whenFailure { err in
2019
0
            queue.async { callbackMayBlock(err) }
2020
0
        }
2021
0
    }
2022
2023
    /// Adds an observer callback to this `EventLoopFuture` that is called when the
2024
    /// `EventLoopFuture` has any result. The observer callback is permitted to block.
2025
    ///
2026
    /// - Note: The `NewValue` must be `Sendable` since it is shared between the isolation region queue and the event loop.
2027
    ///
2028
    /// - Parameters:
2029
    ///   - queue: the `DispatchQueue` on which the blocking IO / task specified by `callbackMayBlock` is scheduled.
2030
    ///   - callbackMayBlock: The callback that is called when the `EventLoopFuture` is fulfilled.
2031
    @inlinable
2032
    @preconcurrency
2033
    public func whenCompleteBlocking(
2034
        onto queue: DispatchQueue,
2035
        _ callbackMayBlock: @escaping @Sendable (Result<Value, Error>) -> Void
2036
0
    ) where Value: Sendable {
2037
0
        self.whenComplete { value in
2038
0
            queue.async { callbackMayBlock(value) }
2039
0
        }
2040
0
    }
2041
}
2042
#endif
2043
2044
// MARK: assertion
2045
2046
extension EventLoopFuture {
2047
    /// Attaches a callback to the `EventLoopFuture` that asserts the original future's success.
2048
    ///
2049
    /// If the original future fails, it triggers an assertion failure, causing a runtime error during development.
2050
    /// The assertion failure will include the file and line of the calling site.
2051
    ///
2052
    /// - Parameters:
2053
    ///   - file: The file this function was called in, for debugging purposes.
2054
    ///   - line: The line this function was called on, for debugging purposes.
2055
    @inlinable
2056
0
    public func assertSuccess(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
2057
0
        self.always { result in
2058
0
            switch result {
2059
0
            case .success:
2060
0
                ()
2061
0
            case .failure(let error):
2062
0
                assertionFailure("Expected success, but got failure: \(error)", file: file, line: line)
2063
0
            }
2064
0
        }
2065
0
    }
2066
    /// Attaches a callback to the `EventLoopFuture` that asserts the original future's failure.
2067
    ///
2068
    /// If the original future succeeds, it triggers an assertion failure, causing a runtime error during development.
2069
    /// The assertion failure will include the file and line of the calling site.
2070
    ///
2071
    /// - Parameters:
2072
    ///   - file: The file this function was called in, for debugging purposes.
2073
    ///   - line: The line this function was called on, for debugging purposes.
2074
    @inlinable
2075
0
    public func assertFailure(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
2076
0
        self.always { result in
2077
0
            switch result {
2078
0
            case .success(let value):
2079
0
                assertionFailure("Expected failure, but got success: \(value)", file: file, line: line)
2080
0
            case .failure:
2081
0
                ()
2082
0
            }
2083
0
        }
2084
0
    }
2085
2086
    /// Attaches a callback to the `EventLoopFuture` that preconditions the original future's success.
2087
    ///
2088
    /// If the original future fails, it triggers a precondition failure, causing a runtime error during development.
2089
    /// The precondition failure will include the file and line of the calling site.
2090
    ///
2091
    /// - Parameters:
2092
    ///   - file: The file this function was called in, for debugging purposes.
2093
    ///   - line: The line this function was called on, for debugging purposes.
2094
    @inlinable
2095
0
    public func preconditionSuccess(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
2096
0
        self.always { result in
2097
0
            switch result {
2098
0
            case .success:
2099
0
                ()
2100
0
            case .failure(let error):
2101
0
                Swift.preconditionFailure("Expected success, but got failure: \(error)", file: file, line: line)
2102
0
            }
2103
0
        }
2104
0
    }
2105
2106
    /// Attaches a callback to the `EventLoopFuture` that preconditions the original future's failure.
2107
    ///
2108
    /// If the original future succeeds, it triggers a precondition failure, causing a runtime error during development.
2109
    /// The precondition failure will include the file and line of the calling site.
2110
    ///
2111
    /// - Parameters:
2112
    ///   - file: The file this function was called in, for debugging purposes.
2113
    ///   - line: The line this function was called on, for debugging purposes.
2114
    @inlinable
2115
0
    public func preconditionFailure(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
2116
0
        self.always { result in
2117
0
            switch result {
2118
0
            case .success(let value):
2119
0
                Swift.preconditionFailure("Expected failure, but got success: \(value)", file: file, line: line)
2120
0
            case .failure:
2121
0
                ()
2122
0
            }
2123
0
        }
2124
0
    }
2125
}
2126
2127
/// An opaque identifier for a specific `EventLoopFuture`.
2128
///
2129
/// This is used only when attempting to provide high-fidelity diagnostics of leaked
2130
/// `EventLoopFuture`s. It is entirely opaque and can only be stored in a simple
2131
/// tracking data structure.
2132
public struct _NIOEventLoopFutureIdentifier: Hashable, Sendable {
2133
    private var opaqueID: UInt
2134
2135
    @usableFromInline
2136
60.2k
    internal init<T>(_ future: EventLoopFuture<T>) {
2137
60.2k
        self.opaqueID = _NIOEventLoopFutureIdentifier.obfuscatePointerValue(future: future)
2138
60.2k
    }
2139
2140
60.2k
    private static func obfuscatePointerValue<T>(future: EventLoopFuture<T>) -> UInt {
2141
60.2k
        // Note:
2142
60.2k
        // 1. 0xbf15ca5d is randomly picked such that it fits into both 32 and 64 bit address spaces
2143
60.2k
        // 2. XOR with 0xbf15ca5d so that Memory Graph Debugger and other memory debugging tools
2144
60.2k
        // won't see it as a reference.
2145
60.2k
        UInt(bitPattern: ObjectIdentifier(future)) ^ 0xbf15_ca5d
2146
60.2k
    }
2147
}
2148
2149
// The future is unchecked Sendable following the below isolation rules this is safe
2150
//
2151
// 1. Receiving the value of the future is always done on the EventLoop of the future, hence
2152
// the value is never transferred out of the event loops isolation domain. It only gets transferred
2153
// by certain methods such as `hop()` and those methods are annotated with requiring the Value to be
2154
// Sendable
2155
// 2. The promise is `Sendable` but fulfilling the promise with a value requires the user to
2156
// transfer the value to the promise. This ensures that the value is now isolated to the event loops
2157
// isolation domain. Note: Sendable values can always be transferred
2158
2159
extension EventLoopPromise: Sendable {}
2160
2161
extension EventLoopFuture: @unchecked Sendable {}
2162
2163
extension EventLoopPromise where Value == Void {
2164
    // Deliver a successful result to the associated `EventLoopFuture<Void>` object.
2165
    @inlinable
2166
0
    public func succeed() {
2167
0
        succeed(Void())
2168
0
    }
2169
}
2170
2171
extension Optional {
2172
    /// Sets or cascades the future result of self to the provided promise, if present.
2173
    ///
2174
    /// If `promise` is `nil` then this function is a no-op. Otherwise, if `self` is `nil` then
2175
    /// `self` is set to `promise`. If `self` isn't `nil` then its `futureResult` will be cascaded
2176
    /// to `promise`.
2177
    ///
2178
    /// - Parameter promise: The promise to set or cascade to.
2179
    @preconcurrency
2180
    public mutating func setOrCascade<Value: Sendable>(to promise: EventLoopPromise<Value>?)
2181
0
    where Wrapped == EventLoopPromise<Value> {
2182
0
        guard let promise = promise else { return }
2183
0
2184
0
        switch self {
2185
0
        case .none:
2186
0
            self = .some(promise)
2187
0
        case .some(let existing):
2188
0
            existing.futureResult.cascade(to: promise)
2189
0
        }
2190
0
    }
2191
}