Releases: chinedufn/swift-bridge
Release list
0.1.59
-
Add support for calling async functions when using Swift 6.0+. Now Swift 5.9+ and 6.0+ are supported. #362 (thanks @Choochmeque)
-
Support
Option<String>in shared struct fields. #354 (thanks @Choochmeque)// Rust #[swift_bridge::bridge] mod ffi { #[swift_bridge(swift_repr = "struct")] struct UserProfile { name: String, bio: Option<String>, // Now supported } extern "Rust" { fn create_profile(name: String, bio: Option<String>) -> UserProfile; } }
// Swift // Create with Some value let profileWithBio = UserProfile( name: "Alice".intoRustString(), bio: "Hello world".intoRustString() ) // Create with None value let profileWithoutBio = UserProfile( name: "Bob".intoRustString(), bio: nil ) // Access optional field if let bio = profileWithBio.bio { print("Bio: \(bio.toString())") }
-
Support Rust calls Swift async throwing function. #348 (thanks @Choochmeque)
// Rust #[swift_bridge::bridge] mod ffi { enum SwiftError { SomeError, } extern "Swift" { async fn swift_throwing_function_void(succeed: Bool) -> Result<(), SwiftError>; } }
// Swift func swift_throwing_function_void(succeed: Bool) throws(SwiftError) { if !succeed { throw SwiftError.SomeError } }
0.1.58
-
Support calling async Swift functions from Rust #346 (thanks @Choochmeque)
// Rust #[swift_bridge::bridge] mod ffi { enum FetchError { NetworkError, NotFound, } extern "Swift" { async fn fetch_count() -> u32; async fn fetch_data(succeed: bool) -> Result<u32, FetchError>; } } async fn example() { let count = ffi::fetch_count().await; match ffi::fetch_data(true).await { Ok(data) => println!("Got: {}", data), Err(e) => println!("Error: {:?}", e), } }
// Swift func fetch_count() async -> UInt32 { return 999 } func fetch_data(succeed: Bool) async throws(FetchError) -> UInt32 { if !succeed { throw FetchError.NetworkError } return 123 }
-
Support calling Swift throwing functions from Rust #347 (thanks @Choochmeque)
// Rust #[swift_bridge::bridge] mod ffi { enum SwiftError { SomeError, } extern "Swift" { fn swift_throwing_function_u32(succeed: Bool) -> Result<u32, SwiftError>; fn swift_throwing_function_void(succeed: Bool) -> Result<(), SwiftError>; } }
// Swift func swift_throwing_function_u32(succeed: Bool) throws(SwiftError) -> UInt32 { if succeed { return 42 } else { throw SwiftError.SomeError } } func swift_throwing_function_void(succeed: Bool) throws(SwiftError) { if !succeed { throw SwiftError.SomeError } }
-
Support Swift
Sendableprotocol #317#[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_bridge(Sendable)] type MyRustType; } extern "Swift" { #[swift_bridge(Sendable)] type MySwiftType; } }
-
Support Swift function argument labels #349 (thanks @Choochmeque)
// Rust extern "Swift" { fn swift_func_with_unlabeled_params( #[swift_bridge(label = "_")] a: i32, #[swift_bridge(label = "_")] b: i32, ) -> i32; fn swift_func_with_custom_labels( #[swift_bridge(label = "first")] a: i32, #[swift_bridge(label = "second")] b: i32, ) -> i32; }
// Swift func swift_func_with_unlabeled_params(_ a: Int32, _ b: Int32) -> Int32 { return a + b } func swift_func_with_custom_labels(first a: Int32, second b: Int32) -> Int32 { return a + b }
-
Support Rust returning
-> Result<*, String>#296 (thanks @brittlewis12)#[swift_bridge::bridge] mod ffi { extern "Rust" { fn do_fallible_work() -> Result<(), String>; } }
-
Support the Swift
Equatableprotocol on RustCopytypes [#328] (thanks @pearfalse)#[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_bridge(Copy(12), Equatable)] type SomeOpaqueBytes; } }
-
Implement Swift
SendableforRustString#330let rustString = RustString("hello world") Thread.detachNewThread { XCTAssertEqual(rustString.len(), 11) }
-
Support Swift's
Hashableprotocol on RustCopytypes #339 (thanks @aDifferentJT)extern "Rust" { #[swift_bridge(Copy(8), Equatable, Hashable)] type T; }
0.1.57
-
Support Failable initializers. #276 (thanks @NiwakaDev)
// Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_bridge(Equatable)] type FailableInitType; #[swift_bridge(init)] fn new() -> Option<FailableInitType>; } }
// Swift let failableInitType = FailableInitType() if failableInitType == nil { // ... } else { // ... }
-
Support Throwing initializers #287 (thanks @NiwakaDev)
// Rust #[swift_bridge::bridge] mod ffi { enum ResultTransparentEnum { NamedField { data: i32 }, UnnamedFields(u8, String), NoFields, } extern "Rust" { type ThrowingInitializer; #[swift_bridge(init)] fn new(succeed: bool) -> Result<ThrowingInitializer, ResultTransparentEnum>; fn val(&self) -> i32; } }
// Swift do { let throwingInitializer = try ThrowingInitializer(false) } catch let error as ResultTransparentEnum { //... } catch { //... }
0.1.56
-
Add
swift-bridge parse-bridgesCLI command. #274 (thanks @integer-overflown)swift-bridge-cli parse-bridges --crate-name my-crate -f src/lib.rs -o generated
swift-bridge-cli parse-bridges --crate-name my-superb-crate \ -f src/lib.rs \ -f src/some_other_file.rs \ -o generated
-
Respect bridge modules' visibility. #284 (thanks @jnbooth)
// Notice that this is `pub mod`. // Before this commit `swift-bridge` would ignore the `pub` and instead // emit a `mod ffi`. // This made it impossible to `use enums::ffi_foo::MyEnum` from another module. #[swift_bridge::bridge] pub mod ffi_foo { enum MyEnum { VariantA, VariantB, VariantC, } } #[swift_bridge::bridge] pub(crate) mod ffi_bar { enum AnotherEnum { Variant1, Variant2, } }
-
Add a temporary work around for a dead code linting regression in Rust
1.79. #278 (thanks @sax)rustc's dead code linting pass regressed in1.79, causingswift-bridgeto sometimes generate code that emitted dead code warnings, even though the code was not dead.- tracked: rust-lang/rust#126706
// Some bridge modules that used `Result` were given an // "error: field `0` is never read" warning. #[swift_bridge::bridge] mod ffi { #[swift_bridge(swift_repr = "struct")] struct TransparentErrorStruct(pub String); extern "Rust" { fn rust_func_returns_result_transparent_struct( succeed: bool ) -> Result<(), TransparentErrorStruct>; } }
0.1.55
- Fix memory leak when passing
Option<SwiftType>from Swift to Rust. #273- It is very unlikely that users were impacted by this leak
Option<SwiftType>support was introduced about 10 hours ago - Full explanation of the leak can be found in 87dbea3
#[swift_bridge::bridge] mod ffi { extern "Swift" { type SomeSwiftType; } extern "Rust" { // Calling with would leak memory in "0.1.54". // This no longer leaks as of "0.1.55". fn option_arg(arg: Option<SomeSwiftType>); } }
- It is very unlikely that users were impacted by this leak
0.1.54
- Add support for bridging
Option<SwiftType>in Rust function arguments and returns. #272 (thanks @Bright-Shard)#[swift_bridge::bridge] mod ffi { extern "Swift" { type SomeSwiftType; } extern "Rust" { fn option_arg(arg: Option<SomeSwiftType>); fn returns_option() -> Option<SomeSwiftType>; } }
0.1.53
-
Add support for bridging
Option<&OpaqueRustType>inextern "Rust"modules. #257 (thanks @PrismaPhonic)#[swift_bridge::bridge] mod ffi { extern "Rust" { type MyRustType; fn my_func(arg: Option<&MyRustType>) -> Option<&MyRustType>; } }
-
Add support for bridging
Option<String>inextern "Swift"args/returns andOption<&str>inextern "Swift"args. #264#[swift_bridge::bridge] mod ffi { extern "Swift" { fn opt_string_function(arg: Option<String>) -> Option<String>; fn opt_str_function(arg: Option<&str>); } }
-
Improve error message when reporting an unsupported attribute #244 (thanks @bes)
0.1.52
-
Improve support for order independent declarations. #230 (thanks @NiwakaDev)
-
Support
Vec<PRIMITIVE>in Swift function argument and return types. #229 (thanks @timwedde)// Rust fn main() { let bytes = ffi::receive_bytes(); println!("bytes: {:?}", bytes); let vec: Vec<u8> = vec![6, 1, 2, 3, 4, 5]; ffi::send_bytes(vec); } #[swift_bridge::bridge] mod ffi { extern "Swift" { fn receive_bytes() -> Vec<u8>; fn send_bytes(vec: Vec<u8>); } }
// Swift func send_bytes(vec: RustVec<UInt8>) { print("Received \(vec.len()) bytes from Rust") for val in vec { print(val) } } func receive_bytes() -> RustVec<UInt8> { let vec = RustVec<UInt8>() for i in 0 ... 4 { vec.push(value: UInt8(i)) } return vec }
-
Support using
already_declaredenums and structs as Swift arguments. #226 (thanks @conectado)// For example, the following is now possible: #[swift_bridge::bridge] mod ffi_i { enum Animal { Alligator, Cat, } } use ffi_i::Foo; #[swift_bridge::bridge] mod ffi { #[swift_bridge(already_declared)] enum Animal {} extern "Swift" { fn hug(a: Animal); } }
-
Support Rust async fn return
Result<(), enum>. #189 (thanks @NiwakaDev)// Rust #[swift_bridge::bridge] mod ffi { enum SomeEnum { //... } extern "Rust" { async fn some_function() -> Result<(), SomeEnum>; } }
// Swift do { let value = try await some_function() //... } catch let error as SomeEnum { //... } catch { //... }
-
Support Rust async fn return
Result<enum, enum>. #182 (thanks @NiwakaDev)// Rust #[swift_bridge::bridge] mod ffi { enum NetworkError { NoData, Authentication, } extern "Rust" { type Data; } extern "Rust" { async fn fetch_from_server() -> Result<Data, NetworkError>; } }
// Swift do { let data = try await fetch_from_server() //... } catch let error as NetworkError { //... } catch { //... }
-
Fix and test async Rust fn return
Result<(), OpaqueType>. #221 (thanks @jfaust) -
Fix and test async Rust fn return
Result<Vec<T>, *>. #218 (thanks @jfaust) -
Support passing primitive tuples from
Rust -> Swift. #195 (thanks @NiwakaDev)// Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { fn reflect_tuple_primitives(tuple: (i16, u32)) -> (i16, u32); } } fn reflect_tuple_primitives(tuple: (i16, u32)) -> (i16, u32) { tuple }
// Swift let tuple = reflect_tuple_primitives((-1, 10))
-
Support passing primitive tuples from
Swift -> Rust. #205 + #211 (thanks @NiwakaDev)// Rust #[swift_bridge::bridge] mod ffi { extern "Swift" { fn swift_reflect_tuple_primitives(arg: (i32, u32)) -> (i32, u32); } }
// Swift let tuple = swift_reflect_tuple_primitives((-123, 123));
-
Support returning
Result<Tuple, *>from Rust to Swift. #213 (thanks @NiwakaDev)// Rust #[swift_bridge::bridge] mod ffi { extern "Rust" { fn rust_func_return_result_tuple_transparent_enum( succeed: bool, ) -> Result<(i32, ResultTestOpaqueRustType, String), ResultTransparentEnum>; } }
// Swift do { //... let tuple: (Int32, ResultTestOpaqueRustType, RustString) = try rust_func_return_result_tuple_transparent_enum(true) //... } catch { //... }
-
Support
#[derive(Debug)]on transparent enums. #194 (thanks @naturecodevoid)// Rust #[swift_bridge::bridge] mod ffi { #[derive(Debug)] enum DeriveDebugEnum { Variant, } }
// Swift let debugString = String(reflecting: DeriveDebugEnum.Variant) XCTAssertEqual(debugString, "Variant")
-
Only support the
#[swift_bridge(associated_to)]attribute on instance methods. #206 (thanks @NiwakaDev) -
Support Option in Swift fns. #203
mod ffi { extern "Swift" { fn my_func(arg: Option<u8>) -> Option<bool>; } }
-
Add
Vec<f32>andVec<f64>support. #200 (thanks @rkreutz)#[swift_bridge::bridge] mod ffi { #[swift_bridge(swift_repr = "struct")] struct SomeStruct { field: Vec<f32>, } extern "Rust" { fn do_something(val: SomeStruct) -> Vec<f32>; } } fn do_something(val: SomeStruct) -> Vec<f32> { // ... }
-
Add
#[derive(Copy, Clone)]support to transparent structs. #198 (thanks @rkreutz)#[swift_bridge::bridge] mod ffi { #[swift_bridge(swift_repr = "struct")] #[derive(Copy, Clone)] struct Foo { field: u8, } }
-
Slightly simplify generated code for returning
Result<(), OpaqueType>. #184 (thanks @NiwakaDev) -
Support RustString in extern Swift functions. [#225] (thanks @NiwakaDev)
// Swift func reflect_swift_string(arg: RustString) -> RustString { arg }
// Rust #[swift_bridge::bridge] mod ffi { extern "Swift" { fn reflect_swift_string(arg: String) -> String; } } let foo = "foo"; let string = ffi::reflect_swift_string(foo.to_string()); assert_eq!(string.len(), 3); assert_eq!(&string, foo);
0.1.51
-
Support returning
Result<(), OpaqueRustType>from Rust functions. #180 (thanks @jfaust)// For example, the following is now possible: #[swift_bridge::bridge] mod ffi { struct UnitStruct; extern "Rust" { type OpaqueType; fn null_result() -> Result<(), OpaqueType>; fn unit_result() -> Result<UnitStruct, OpaqueType>; } } fn null_result() -> Result<(), OpaqueType> { Ok(()) } fn unit_result() -> Result<UnitStruct, OpaqueType> { Ok(UnitStruct) }
-
Support shared enums with named data. #175 (thanks @NiwakaDev)
// For example, the following is now possible: #[swift_bridge::bridge] mod ffi { enum EnumWithNamedData { Variant1 { hello: String, data_u8: u8 }, Variant2 { data_i32: i32 }, Variant3 { foo: Foo }, } extern "Rust" { #[swift_bridge(Equatable)] type Foo; #[swift_bridge(init)] fn new() -> Foo; fn reflect_enum_with_named_data(arg: EnumWithNamedData) -> EnumWithNamedData; } }
// Swift let enumWithNamedData3 = EnumWithNamedData.Variant3(foo: Foo()) switch reflect_enum_with_named_data(enumWithNamedData3) { case .Variant3(let foo): XCTAssertEqual(foo, Foo()) break default: XCTFail() }
-
Support opaque types inside of data-carrying enums. #181 (thanks @NiwakaDev)
// For example, the following is now possible: #[swift_bridge::bridge] mod ffi { enum OpaqueRustEnum { Unnamed(MyType) Named { field: MyType }, } extern "Rust" { #[swift_bridge(Equatable)] type MyType; #[swift_bridge(init)] fn new() -> MyType; fn reflect_enum(arg: OpaqueRustEnum) -> OpaqueRustEnum; } }
// Swift let opaqueRustEnum = OpaqueRustEnum.Named(field: MyType()) switch reflect_enum(opaqueRustEnum) { case .Named(let named): XCTAssertEqual(named, MyType()) break default: XCTFail() }
-
Reduce the FFI representation of ZSTs (zero-sized types) from one byte to zero bytes. #178
- Previously ZSTs were bridged as a
u8in order to preserve FFI safety. - Now we simply inline the ZST on both sides of the FFI boundary, enabling zero memory overhead sharing of ZSTs.
// For example, the following bridge module: #[swift_bridge::bridge] mod ffi { struct UnitStruct1; struct UnitStruct2{} struct UnitStruct3(); extern "Rust" { fn some_function( arg1: UnitStruct1, arg2: UnitStruct2, arg3: UnitStruct3, ) -> UnitStruct1; } }
// generates the following exported Rust function: #[link_name = "__swift_bridge__$some_function"] pub extern "C" fn __swift_bridge__some_function() { {super::some_function(UnitStruct1, UnitStruct2{}, UnitStruct3()); ()} }
// and generates the following Swift: func some_function(arg1: UnitStruct1, arg2: UnitStruct2, arg3: UnitStruct3) -> UnitStruct1 { { let _ = __swift_bridge__$some_function(); UnitStruct1() }() }
- Previously ZSTs were bridged as a
0.1.50
-
Support data-carrying tuple enum variants. #172 (thanks @NiwakaDev)
// For example, the following is now possible: #[swift_bridge::bridge] mod ffi { enum EnumWithUnnamedData { Variant1(String, u32), Variant2(i32, u8), Variant3, } }
// Swift let myEnum: EnumWithUnnamedData = .Variant2(10, 20)
-
Emit compile time errors when returning the wrong opaque Rust type. #169 (thanks @MikuroXina)
// For example, the following will no longer compile: #[swift_bridge::bridge] mod ffi { extern "Rust" { // Before this release calling `get_reference()` from Swift would cause // undefined behavior. // As of this release this will no longer compile. fn get_reference() -> SomeType; } } // Note that the bridge module incorrectly declares `-> SomeType` // instead of `-> &'static SomeType`. fn get_reference() -> &'static SomeType { &SomeType }