swift-bridge: Implementing Swift's Error and Sendable protocols on an opaque Rust type's generated Swift class
The Problem
In #149 we implemented support for returning -> Result<T, E> where E is an opaque Rust type.
// Rust
#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
type TypeA;
type TypeB;
fn some_function() -> Result<TypeA, TypeB>;
fn print_info(self: &TypeB);
}
}
Swift errors need to conform to Swift’s Error and Sendable protocols, but right now there is no way to
declare that an Opaque Rust type should conform to Error and Sendable.
Instead, you currently have to manually specify that a type conforms.
An Example “Solution”
NOTE: This is a quick sketch of a potential solution in order to help make the problem more clear. The concurrency implications have not been deeply considered. Before working on this we should take a step back to lay out and consider all of the Rust + Swift concurrency factors at play. The final solution might not look anything like this sketch. The “Resources” section below links to resources that we will want to study and reference while figuring out our design.
If an OpaqueRustType implements Rust’s Send and Sync traits we may want the user to be able to emit a Sendable protocol implementation.
#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
// If the type does not implement Rust's `Send + Sync` traits we get a
// compile time error
#[swift_bridge(Sendable)]
type TypeA;
}
}
// This implements `Send` and `Sync`, so
// the `Sendable` attribute above works.
struct TypeA {
field: Vec<u8>
}
On the Swift side this could generate something like:
// Swift
extension TypeA: @unchecked Sendable {}
extension TypeA: Error {}
NOTE: The above is a quick sketch of a potential solution in order to help make the problem more clear. The concurrency implications have not been deeply considered. Before working on this we should take a step back to lay out and consider all of the Rust + Swift concurrency factors at play. The final solution might not look anything like this sketch. The “Resources” section below links to resources that we will want to study and reference while figuring out our design.
Considerations
Sendable
We need to have a good understanding of Swift’s Sendable protocol’s requirements.
The Resources section below contains links with more information.
Swift reference types
The struct TypeA in Rust becomes a class TypeA in Swift.
If this class TypeA implements Sendable then it can be sent across threads,
meaning that two different threads could access the mutable methods on the instance of
class TypeA at the same time.
Is it possible for us to prevent this? Could Swift’s Actors be of use here?
Concurrency
In general we need to think through Swift’s concurrency model and make sure that we are going down a safe path.
Getting some design feedback from someone with a good amount of Swift experience would be helpful.
Resources
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 1
- Comments: 26 (11 by maintainers)
Please add https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html to Resources.