Call Rust from Swift and vice versa.
swift-bridge
makes it possible to pass complex types between Rust and Swift without needing to write any FFI glue code yourself.
You write the type signatures of your FFI boundary in Rust, and then swift-bridge
uses that to auto-generate the FFI layer.
The generated FFI layer is both type-safe and memory-safe, allowing you to confidently communicate between languages.
swift-bridge
takes inspiration from the bridge module idea pioneered by cxx.
swift-bridge
works, but it's still early so it's possible to run into edge cases where the generated code is subtly not-memory-safe.
All of these cases are addressable, and once they're all tackled using code generated from swift-bridge
should be entirely memory safe
on both the Swift and Rust side.
So, swift-bridge
is not yet production ready.
Right now I'm looking for feedback from bleeding-edge users in order to continue to improve the APIs and the generated code.
I can especially use feedback from people with Swift experience, since I don't have much.
I'm using swift-bridge
to ship an application that has extreme reliability requirements, so you can rest assured that the core maintaners have a vested interest in addressing your feedback.
The 0.1.x
versions will not follow semver.
We'll maintain semver from 0.2
and onwards.
```toml
[build-dependencies] swift-bridge-build = "0.1"
[dependencies] swift-bridge = "0.1" ```
Here's a quick peek at how defining FFI bindings looks.
A more thorough walk through of swift-bridge
can be found in the book.
```rust // lib.rs
pub struct ARustStack(Vec
pub struct SomeType {
map: HashMap
pub struct AnotherType(u8, Box
mod ffi { // Shared struct definitions can have their fields directly // accessed by both Swift and Rust. #[swiftbridge(swiftrepr = "struct")] struct SwiftStackConfig { max_size: u8 }
extern "Rust" {
// Exposes super::ARustStack to Swift.
type ARustStack;
// Allows Swift to call the `push` method on `ARustStack`.
// Swift will only be able to call this when it has
// an owned `ARustStack` or a mutablly referenced
// `&mut ARustStack`.
fn push (&mut self, val: String);
// Allows Swift to call the `pop` method on `ARustStack`.
fn pop (&mut self) -> Option<String>;
}
extern "Rust" {
// Exposes super::do_stuff to Swift
fn do_stuff(a: &SomeType, b: &mut AnotherType) -> Option<SwiftStack>;
}
extern "Rust" {
// Exposes super::SomeType to Swift
type SomeType;
// Exposes super::AnotherType to Swift
type AnotherType;
// The "init" annotation.
// Indicates that this should show up on the Swift side as
// a class initializer for SomeType.
#[swift_bridge(init)]
fn new() -> SomeType;
#[swift_bridge(init)]
fn new_with_u8(val: u8) -> AnotherType;
fn call(self: &AnotherType) -> bool;
}
// Exposes a Swift `class SwiftStack` to Rust.
extern "Swift" {
type SwiftStack;
#[swift_bridge(init)]
fn new(config: SwiftStackConfig) -> SwiftStack;
fn push(&mut self, val: String) -> Bool;
}
}
impl ARustStack { fn push(&mut self, val: String) { self.0.push(val); }
fn pop(&mut self) -> Option<String> {
self.0.pop()
}
}
impl SomeType { fn new() -> Self { SomeType::default() } }
impl AnotherType { fn newwithu8(val: u8) -> Self { AnotherType(val, Box::new(|| true)) }
fn call(&self) -> bool {
(self.0)()
}
}
fn dostuff(a: &SomeType, b: &mut AnotherType) -> Option
Some(swift_stack)
} ```
```swift // Swift
class SwiftStack { var stack: [String] = [] var maxSize: UInt8
init(config: SwiftStackConfig) {
self.maxSize = config.max_size
}
func push(val: String) {
self.stack.push(val)
}
}
func doThings() { // Calls SomeType::new() let someType = SomeType() // Calls AnotherType::newwithu8 let anotherType = AnotherType(val: 50)
let stack: SwiftStack? = do_stuff(someType, anotherType)
} ```
TODO... make GitHub issues for these..
fn foo () -> SomeType
even though the real definition is fn foo () -> &SomeType {}
swift_bridge
comes with support for a number of Rust and Swift standard library types.
| name in Rust | name in Swift | notes |
| --- | --- | --- |
| u8, i8, u16, i16... etc | UInt8, Int8, UInt16, Int16 ... etc | |
| bool | Bool | |
| String, &String, &mut String | RustString | |
| &str | RustStr | |
| Vec
Other places such as function arguments are not yet implemented but will come.
|
| Result\
Open an issue! | | |
| | Have a Swift standard library type in mind?
Open an issue! | |
To run the test suite.
```sh
git clone git@github.com:chinedufn/swift-bridge.git cd swift-bridge
cargo test --all && ./test-integration.sh ```