Wrap the raw pointers exposed across the bridge as named types that approximate
Swift's OpaquePointer?. Parameterize NativeHandleOwner with the native handle
type.
- All public Swift-defined structs except CdsiLookupResponse,
which wraps LookupResponseEntryList, which can *probably* be made
Sendable but I didn't spend time on it.
- All public Swift-defined enums except those being used purely as
namespaces.
- All zkgroup types, since they are immutable and can be serialized
and deserialized to send them anyway
- ServiceId and its subclasses, an immutable class hierarchy
- ProtocolAddress, PinHash, SenderCertificate and ServerCertificate,
and all public and private Key types, immutable wrappers around
immutable Rust objects
More of our wrapper types could be made Sendable as well if there's a
need to. See CODING_GUIDELINES for more info.
...and pass that struct by reference.
This has some benefits and some drawbacks:
+ Type inference is (usually) more reliable; invokeAsyncFunction no
longer needs a "returning:" parameter for disambiguation.
+ We can add more fields to the promise structs as needed.
+ We can use the same argument for input and output.
- Before, every promise that produced an OpaquePointer could share one
protocol implementation on the Swift side. Now, they're separate.
- The manual type erasure code in the implementation of Completer has
gotten worse.
- Using the same argument for input and output may be confusing.
On the Rust side, this expects a typical C callback function with a
"context" parameter. On the Swift side, we pass a manually-refcounted
object as that "context" which can be used to complete a
CheckedContinuation, bridging into the language 'async' functionality.
The main obstacle to this approach is that Swift does not allow C
function pointers to be used in generic ways, due to its run-time
generics model. AsyncUtils.swift describes the workarounds needed to
deal with this.