| // Copyright (C) 2026 Apple Inc. All rights reserved. | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions | |
| // are met: | |
| // 1. Redistributions of source code must retain the above copyright | |
| // notice, this list of conditions and the following disclaimer. | |
| // 2. Redistributions in binary form must reproduce the above copyright | |
| // notice, this list of conditions and the following disclaimer in the | |
| // documentation and/or other materials provided with the distribution. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
| // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
| // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
| // THE POSSIBILITY OF SUCH DAMAGE. | |
| // FIXME: (rdar://164119356) Move this file into WTF. | |
| #if compiler(>=6.4) && !SWIFT_WEBKIT_TOOLCHAIN | |
| import wtf.Core.CompletionHandler | |
| /// The machinery shared by ``CxxCompletionHandler``, ``CxxConsumingCompletionHandler``, and | |
| /// ``CxxVoidCompletionHandler``. | |
| /// | |
| /// - Important: Do not conform to this directly. Conform to one of those three instead. | |
| public protocol CxxCompletionHandlerBase: ~Copyable { | |
| /// The type of the completion handler's only parameter, or `Void` if it has none. | |
| /// | |
| /// State this explicitly, matching the C++ parameter type: | |
| /// | |
| /// ```swift | |
| /// typealias Argument = CInt | |
| /// ``` | |
| associatedtype Argument: ~Copyable | |
| /// Creates a completion handler from the C ABI a Swift closure reduces to: a function pointer, an opaque context, and | |
| /// a destructor for that context. | |
| /// | |
| /// Every specialization of `WTF::CompletionHandler` already has this constructor, so conformances never implement it | |
| /// themselves. | |
| /// | |
| /// - Parameters: | |
| /// - invoke: The function pointer. | |
| /// - destroy: The function describing how to destroy the closure. | |
| /// - context: An opaque context for the closure. | |
| /// - Important: Do not implement or call this yourself. | |
| init(invoke: WTF.SwiftClosureInvoke, destroy: WTF.SwiftClosureDestroy, context: UnsafeMutableRawPointer) | |
| } | |
| /// A protocol for concrete specializations of `WTF::CompletionHandler` that take one argument by value to conform to. | |
| /// | |
| /// Conforming a specialization to this protocol allows Swift to easily call functions that accept `WTF::CompletionHandler` parameters. | |
| /// For example, this makes it possible to call a function like: | |
| /// | |
| /// ```cpp | |
| /// using DoSomethingCompletionHandler = WTF::CompletionHandler<void(int)>; | |
| /// void doSomething(DoSomethingCompletionHandler&&); | |
| /// ``` | |
| /// | |
| /// by creating this conformance: | |
| /// | |
| /// ```swift | |
| /// extension DoSomethingCompletionHandler: @unsafe CxxCompletionHandler { | |
| /// typealias Argument = CInt | |
| /// } | |
| /// ``` | |
| /// | |
| /// Swift can then call this via the `init(_ body: @escaping (Argument) -> Void)` initializer: | |
| /// | |
| /// ```swift | |
| /// doSomething(consuming: .init { number in ... }) | |
| /// ``` | |
| /// | |
| /// or by using the convenience continuation initializer: | |
| /// | |
| /// ```swift | |
| /// await withCheckedContinuation { continuation in | |
| /// doSomething(consuming: .init(continuation)) | |
| /// } | |
| /// ``` | |
| /// | |
| /// Common specializations like `WTF::VoidCompletionHandler` and `WTF::BoolCompletionHandler` already conform. | |
| /// | |
| /// - Note: If the C++ parameter is an rvalue reference (`T&&`) rather than a value, conform to | |
| /// ``CxxConsumingCompletionHandler`` instead. | |
| /// - Important: Do not implement the protocol requirements yourself. It is unsafe if you do so. | |
| public protocol CxxCompletionHandler: CxxCompletionHandlerBase, ~Copyable where Argument: Copyable { | |
| /// Invokes the completion handler. | |
| /// | |
| /// This is implemented by the imported C++ `operator()`, which is what makes the compiler verify that `Argument` matches | |
| /// the type C++ actually passes. | |
| /// | |
| /// - Important: Do not implement this yourself. | |
| mutating func callAsFunction(_ argument: Argument) | |
| } | |
| /// A protocol for concrete specializations of `WTF::CompletionHandler` that take one argument by rvalue reference to | |
| /// conform to. | |
| /// | |
| /// This is the same as ``CxxCompletionHandler`` except that it matches a C++ signature like: | |
| /// | |
| /// ```cpp | |
| /// using DoSomethingCompletionHandler = WTF::CompletionHandler<void(MoveOnlyThing&&)>; | |
| /// ``` | |
| /// | |
| /// - Important: Do not implement the protocol requirements yourself. It is unsafe if you do so. | |
| public protocol CxxConsumingCompletionHandler: CxxCompletionHandlerBase, ~Copyable { | |
| /// Invokes the completion handler. | |
| /// | |
| /// This is implemented by the imported C++ `operator()`, which is what makes the compiler verify that `Argument` matches | |
| /// the type C++ actually passes. | |
| /// | |
| /// - Important: Do not implement this yourself. | |
| mutating func callAsFunction(consuming: consuming Argument) | |
| } | |
| /// A protocol for concrete specializations of `WTF::CompletionHandler` that take no argument to conform to. | |
| public protocol CxxVoidCompletionHandler: CxxCompletionHandlerBase, ~Copyable where Argument == Void { | |
| /// Invokes the completion handler. | |
| /// | |
| /// - Important: Do not implement this yourself. | |
| mutating func callAsFunction() | |
| } | |
| extension CxxCompletionHandlerBase where Self: ~Copyable { | |
| /// Creates a completion handler that owns `box` and dispatches to it. | |
| /// | |
| /// - Parameter box: The box holding the Swift closure to call. | |
| fileprivate init(box: SwiftClosureBoxBase) { | |
| // This is all safe because all uses of the raw pointer are encapsulated in the C++ implementation and its lifetime | |
| // is not modified elsewhere. | |
| unsafe self.init( | |
| invoke: { context, argument in | |
| // This uses `SwiftClosureBoxBase` and not `SwiftClosureBox<Argument>` because a C function pointer | |
| // cannot be formed from a closure that captures generic parameters. | |
| unsafe Unmanaged<SwiftClosureBoxBase>.fromOpaque(context).takeUnretainedValue().call(with: argument) | |
| }, | |
| destroy: { context in | |
| unsafe Unmanaged<AnyObject>.fromOpaque(context).release() | |
| }, | |
| context: unsafe Unmanaged.passRetained(box).toOpaque() | |
| ) | |
| } | |
| } | |
| extension CxxCompletionHandler where Self: ~Copyable { | |
| // These functions are safe because its implementation is safe. | |
| /// Creates a `WTF::CompletionHandler` type from a Swift closure. | |
| /// | |
| /// - Parameters: | |
| /// - isolation: The current isolation. | |
| /// - body: The Swift closure to use. | |
| @safe | |
| public init(isolation: isolated (any Actor)? = #isolation, _ body: @escaping (Argument) -> Void) { | |
| self.init(box: SwiftCopyingClosureBox(isolation: isolation, body)) | |
| } | |
| } | |
| extension CxxConsumingCompletionHandler where Self: ~Copyable { | |
| // These functions are safe because its implementation is safe. | |
| /// Creates a `WTF::CompletionHandler` type from a Swift closure. | |
| /// | |
| /// - Parameters: | |
| /// - isolation: The current isolation. | |
| /// - body: The Swift closure to use. | |
| @safe | |
| public init(isolation: isolated (any Actor)? = #isolation, _ body: @escaping (consuming Argument) -> Void) { | |
| self.init(box: SwiftTakingClosureBox(isolation: isolation, body)) | |
| } | |
| } | |
| extension CxxCompletionHandler where Self: ~Copyable, Argument: Sendable { | |
| /// A convenience initializer to create a completion handler from a `CheckedContinuation` directly to make bridging to a Swift `async` | |
| /// context trivial. | |
| /// | |
| /// This should be preferred for most cases. | |
| /// | |
| /// - Parameter continuation: A continuation vended by `withCheckedContinuation`. | |
| @safe | |
| public init(_ continuation: CheckedContinuation<Argument, some Error>) { | |
| self.init { continuation.resume(returning: $0) } | |
| } | |
| } | |
| extension CxxVoidCompletionHandler where Self: ~Copyable { | |
| // These functions are safe because its implementation is safe. | |
| /// Creates a `WTF::CompletionHandler` type from a Swift closure. | |
| /// | |
| /// - Parameters: | |
| /// - isolation: The current isolation. | |
| /// - body: The Swift closure to use. | |
| @safe | |
| public init(isolation: isolated (any Actor)? = #isolation, _ body: @escaping () -> Void) { | |
| self.init(box: SwiftVoidClosureBox(isolation: isolation, body)) | |
| } | |
| /// A convenience initializer to create a completion handler from a `CheckedContinuation` directly to make bridging to a Swift `async` | |
| /// context trivial. | |
| /// | |
| /// This should be preferred for most cases. | |
| /// | |
| /// - Parameter continuation: A continuation vended by `withCheckedContinuation`. | |
| @safe | |
| public init(_ continuation: CheckedContinuation<Void, some Error>) { | |
| self.init { continuation.resume() } | |
| } | |
| } | |
| private class SwiftClosureBoxBase { | |
| private let isolation: (any Actor)? | |
| init(isolation: (any Actor)?) { | |
| self.isolation = isolation | |
| } | |
| func call(with argument: UnsafeMutableRawPointer?) { | |
| preconditionFailure("Subclasses must override call(with:)") | |
| } | |
| final func checkIsolation() { | |
| isolation?.preconditionIsolated("A completion handler must be invoked on the isolation that created it") | |
| } | |
| } | |
| private final class SwiftVoidClosureBox: SwiftClosureBoxBase { | |
| private let body: () -> Void | |
| init(isolation: (any Actor)?, _ body: @escaping () -> Void) { | |
| self.body = body | |
| super.init(isolation: isolation) | |
| } | |
| override func call(with pointer: UnsafeMutableRawPointer?) { | |
| unsafe precondition(pointer == nil) | |
| checkIsolation() | |
| body() | |
| } | |
| } | |
| /// Copies the argument out of the pointer C++ supplied, leaving C++ to destroy its own object. | |
| private final class SwiftCopyingClosureBox<Argument>: SwiftClosureBoxBase { | |
| private let body: (Argument) -> Void | |
| init(isolation: (any Actor)?, _ body: @escaping (Argument) -> Void) { | |
| self.body = body | |
| super.init(isolation: isolation) | |
| } | |
| override func call(with pointer: UnsafeMutableRawPointer?) { | |
| guard let pointer = unsafe pointer else { | |
| preconditionFailure("A completion handler taking an argument must be passed a pointer to one") | |
| } | |
| checkIsolation() | |
| // Safety properties: | |
| // | |
| // Non-null, initialized, aligned: guarded above, and C++ passes `std::addressof` of the live | |
| // parameter object it was invoked with, so it is the address of a fully constructed object. | |
| // Really an `Argument`: the `callAsFunction` requirement is witnessed by the imported C++ | |
| // `operator()`, so a conformance whose `Argument` disagrees with the C++ parameter type does | |
| // not compile. The typealias is checked, not merely promised. | |
| // Lifetime: `invoke` is synchronous, so C++ is blocked inside the call for as long as this runs | |
| // and cannot have released the object. This method never stores `pointer`; only the copied | |
| // value may outlive the call. | |
| // Aliasing: C++ still owns that same object, so this may only read it. `.pointee` copies, and | |
| // C++ is blocked and so cannot be writing concurrently. Taking the value instead would | |
| // leave C++'s object deinitialized behind its back. | |
| // Isolation: `checkIsolation()` above. | |
| body(unsafe pointer.assumingMemoryBound(to: Argument.self).pointee) | |
| } | |
| } | |
| /// Takes the argument out of the pointer C++ supplied. | |
| private final class SwiftTakingClosureBox<Argument: ~Copyable>: SwiftClosureBoxBase { | |
| private let body: (consuming Argument) -> Void | |
| init(isolation: (any Actor)?, _ body: @escaping (consuming Argument) -> Void) { | |
| self.body = body | |
| super.init(isolation: isolation) | |
| } | |
| override func call(with pointer: UnsafeMutableRawPointer?) { | |
| guard let pointer = unsafe pointer else { | |
| preconditionFailure("A completion handler taking an argument must be passed a pointer to one") | |
| } | |
| checkIsolation() | |
| // Safety properties: | |
| // | |
| // As in `SwiftCopyingClosureBox`, with three differences that all follow from C++ having built | |
| // this object solely to hand over: | |
| // | |
| // Aliasing: C++ placement-new'd the value into an `AlignedStorage` local and does not touch it | |
| // again -- `AlignedStorage`'s destructor does not run `~ArgumentType` -- so taking it here | |
| // races with nothing. Alignment comes from `alignas(alignment_of_v<T>)` on that storage. | |
| // Consumed exactly once: `.move()` deinitializes the storage, and nothing else destroys it. C++ | |
| // will not, and `CompletionHandler::operator()` clears its function before calling, so the | |
| // handler cannot run twice. | |
| // Relocation: Swift moves a noncopyable imported C++ value byte-wise rather than running its | |
| // move constructor. `WTF::CompletionHandler` static-asserts that such an argument has a | |
| // non-trivial destructor, which is what makes Swift use the move constructor instead. | |
| body(unsafe pointer.assumingMemoryBound(to: Argument.self).move()) | |
| } | |
| } | |
| extension WTF.VoidCompletionHandler: @unsafe CxxVoidCompletionHandler {} | |
| extension WTF.BoolCompletionHandler: @unsafe CxxCompletionHandler { | |
| // swift-format-ignore: AllPublicDeclarationsHaveDocumentation | |
| public typealias Argument = Bool | |
| } | |
| #endif // compiler(>=6.4) && !SWIFT_WEBKIT_TOOLCHAIN |