Functions
swift-bridge
allows you to export Rust functions for Swift to use and import Swift
functions for Rust to use.
#![allow(unused)] fn main() { #[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_name = "printGreeting"] fn print_greeting(name: &str); } extern "Swift" { fn add(lhs: usize, rhs: usize) -> usize; } } fn print_greeting(name: &str) { let sum = ffi::add(1, 2); println!("Hello {name}. 1 + 2 = {sum}!") } }
// Swift
printGreeting("Tolu")
func add(lhs: UInt, rhs: UInt) -> UInt {
lhs + rhs
}
Async Rust Functions
swift-bridge
supports async/await between Swift and Rust.
Calling an async Rust function from Swift is supported. Calling an async Swift function from Rust is not yet supported.
#![allow(unused)] fn main() { #[swift_bridge::bridge] mod ffi { extern "Rust" { type User; type ApiError; async fn user_count() -> u32; async fn load_user(url: &str) -> Result<User, ApiError>; } } }
// Swift
let totalUsers = await user_count()
do {
let user = try await load_user("https://example.com/users/5")
} catch let error as ApiError {
// ... error handling ...
}
Function Attributes
#[swift_bridge(init)]
Used to generate a Swift initializer for Opaque Types.
#![allow(unused)] fn main() { // Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { type RegularInitializer; #[swift_bridge(init)] fn new() -> RegularInitializer; } extern "Rust" { type FailableInitializer; #[swift_bridge(init)] fn new() -> Option<FailableInitializer>; } enum SomeError { case1, case2 } extern "Rust" { type ThrowingInitializer; #[swift_bridge(init)] fn new() -> Result<FailableInitializer, SomeError>; } } }
// Swift
let regularInitializer = RegularInitializer()
if let failableInitializer = FailableInitializer() {
// ...
}
do {
let throwingInitializer = try ThrowingInitializer()
} catch let error {
// ...
}
#[swift_bridge(Identifiable)]
Used to generate a Swift Identifiable
protocol implementation.
#![allow(unused)] fn main() { // Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { type SomeType; #[swift_bridge(Identifiable, swift_name = "someFunction")] fn some_function(&self) -> i16; } } }
// Generated Swift
// (rough example, the real generated code looks a little different)
class SomeType {
// ...
}
extension SomeType: Identifiable {
var id: UInt16 {
return self.someFunction()
}
}
#[swift_bridge(args_into = (arg_name, another_arg_name))]
Used to name the arguments that should have .into()
called on them when
passing them to their handler function.
One use case is for exposing a third-party type as a shared struct.
#![allow(unused)] fn main() { mod pretend_this_is_some_third_party_crate { // We want to expose this third-party struct as a shared struct. pub struct UniqueId { id: u64 } } use pretend_this_is_some_third_party_crate::UniqueId; fn a_function (_some_arg: UniqueId, _an_arg: UniqueId, _cool_arg: u8) { // ... } mod ffi { struct FfiUniqueId(u64); extern "Rust" { // super::a_function does not take a `u64` or an `FfiUniqueId`, // but this still works since they both `impl Into<UniqueId>`. #[swift_bridge(args_into = (some_arg, an_arg))] fn a_function(some_arg: u64, an_arg: FfiUniqueId, cool_arg: u8); } } impl From<u64> for UniqueId { fn from(id: u64) -> UniqueId { UniqueId { id } } } impl Into<UniqueId> for ffi::FfiUniqueId { fn into(self) -> UniqueId { UniqueId(self.0) } } }
#[swift_bridge(associated_to = SomeType)]
Indicates that we are exposing an associated function for a type.
#![allow(unused)] fn main() { // Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { type Message; // Exposes Message::parse to Swift as Message.parse #[swift_bridge(associated_to = Message)] fn parse(text: &str) -> Option<Message>; } } struct LongMessage(String); impl LongMessage { fn parse(text: impl ToString) -> Option<Self> { let text = text.to_string(); if text.len() > 10_000 { Some(LongMessage(text)) } else { None } } } }
// Swift
func maybeSendLongMessage(text: String) {
let maybeMessage = Message.parse(text)
if let message = maybeMessage {
// ... send the message
}
}
#[swift_bridge(get(field_name))]
Allows you to return the value of an opaque Rust struct's field.
You can prefix the field name with &
or &mut
in order to return a reference
or mutable reference to the field.
#![allow(unused)] fn main() { #[swift_bridge::bridge] mod ffi { extern "Rust" { type SomeType; // Returns self.my_u8 #[swift_bridge(get(my_u8))] fn my_u8(&self) -> u8; // Returns &self.my_string #[swift_bridge(get(&my_string))] fn my_string_reference(&self) -> &str; } } pub struct SomeType { my_u8: u8, my_string: String, } }
#[swift_bridge(get_with(field_name = path::to::function))]
Allows you to pass an opaque Rust struct's field into a function and then return the value that that function returned.
You can prefix the field name with &
or &mut
in order to pass the field
to the function by reference or mutable reference respectively.
#![allow(unused)] fn main() { use Clone; #[swift_bridge::bridge] mod ffi { extern "Rust" { type SomeType; // Returns ui_to_i16(self.my_u8) #[swift_bridge(get_with(my_u8 = u8_to_i16))] fn my_u8_converted(&self) -> u16; // Returns Clone::clone(&self.my_string) #[swift_bridge(get_with(&my_string = Clone::clone))] fn my_string_cloned(&self) -> String; // Returns string_to_u32(&self.my_string) #[swift_bridge(get_with(&my_string = string_to_u32))] fn my_string_parsed(&self) -> u32; } } pub struct SomeType { my_u8: u8, my_string: String, } fn u8_to_i16 (num: u8) -> i16 { num as i16 } fn string_to_u32(string: &str) -> u32 { string.parse().unwrap() } }
#[swift_bridge(label = "argName")]
Used to set the Swift argument label.
#![allow(unused)] fn main() { // Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { fn add( #[swift_bridge(label = "leftHand")] left_hand: i32, right_hand: i32, ) -> i32; } } fn add(left_hand: i32, right_hand: i32) -> i32 { left_hand + right_hand } }
// Swift
let sum = add(leftHand: 10, 20)
#[swift_bridge(return_into)]
Allows a swift-bridge definition of fn foo() -> T
to work for any fn foo() -> impl Into<T>
.
#![allow(unused)] fn main() { use some_other_crate::Uuid; #[swift_bridge::bridge] mod ffi { struct FfiUuid { uuid: [u8; 16] } extern "Rust" { #[swift_bridge(return_into)] fn make_uuid() -> FfiUuid; } } impl From<Uuid> for ffi::FFiUuid { fn from(uuid: Uuid) -> ffi::FfiUuid { unsafe { std::mem::transmute(uuid) } } } use self::some_other_crate::make_uuid; mod some_other_crate { pub struct Uuid { uuid: [u8; 16] } // Here we can return a Uuid, even though swift-bridge is expecting an FfiUuid. pub fn make_uuid() -> Uuid { Uuid::new_v4() } } }
#[swift_bridge(return_with = path::to::some_function)]
Allows a swift-bridge definition of fn foo() -> T
to work for a fn foo() -> U
by
passing T
to a fn(T) -> U
.
#![allow(unused)] fn main() { #[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_bridge(return_with = some_module::convert_str_to_u32)] fn get_str_value_return_with() -> u32; } } fn get_str_value_return_with() -> &'static str { "123" } mod some_module { pub fn convert_str_to_u32(val: &str) -> u32 { val.parse().unwrap() } } }
#[swift_bridge(rust_name = "function_name")]
Use the given rust_name
to find the function's implementation.
#![allow(unused)] fn main() { #[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_bridge(rust_name = "another_function")] fn some_function(); } } fn another_function() { } }
#[swift_bridge(swift_name = "functionName")]
Sets the function name that is used on the Swift side.
#![allow(unused)] fn main() { #[swift_bridge::bridge] mod ffi { extern "Rust" { // Exports `some_function` as `someFunction`. #[swift_bridge(swift_name = "someFunction")] fn some_function(); } extern "Swift" { // Imports `anotherFunction` as `another_function`. #[swift_bridge(swift_name = "anotherFunction")] fn another_function(); } } }