# Interoperating with Swift Automatically mapping Apple's Swift-only frameworks is out of scope for the `objc2` project, see [#524](https://github.com/madsmtm/objc2/issues/524) for discussion. That said, if you need to interface with Swift from Rust, there are a few ways to go about it. ## Exposing C APIs with `@_cdecl` The simplest way is probably to sidestep `objc2` directly, and instead expose functionality as `@_cdecl("...")`. Something like the following: ```swift // foo.swift @_cdecl("foo") func foo() -> Int32 { return 42; } ``` ```rust,ignore // build.rs fn main() { // Somehow invoke `swiftc` to compile the library. // You probably want to use a helper library for this! let status = std::process::Command("swiftc") .arg("foo.swift") .arg("-emit-library") .status() .unwrap(); assert!(status.success()); // And somehow tell Cargo to link the library. println!("cargo::rustc-link-lib=foo"); } ``` ```rust,no_run // main.rs extern "C" { fn foo() -> i32; } fn main() { println!("foo returned {}", unsafe { foo() }); } ``` ## Exposing Objective-C APIs with `@objc` Building on the above approach, you could instead expose an Objective-C API using `@objc`, and then map that to Rust using `objc2`. Something like the following: ```swift // foo.swift import Foundation @objc(Foo) class Foo: NSObject { @objc var foo: Int32 = 42; @objc func doStuff() { print("foo \(foo)") } } ``` You can view the Objective-C interface for this with `swiftc file.swift -emit-objc-header`. Mapping this to Rust would then look something like: ```rust,no_run // main.rs use objc2::rc::{Allocated, Retained}; use objc2::runtime::NSObject; use objc2::{extern_class, extern_methods, AnyThread}; extern_class!( #[unsafe(super(NSObject))] #[name = "Foo"] // Matching the name in @objc(Foo) pub struct Foo; ); #[allow(non_snake_case)] impl Foo { extern_methods!( // Generated by the Swift compiler. #[unsafe(method(init))] pub fn init(this: Allocated) -> Retained; // Property accessors. #[unsafe(method(foo))] pub fn foo(&self) -> i32; #[unsafe(method(setFoo:))] pub fn setFoo(&self, value: i32); // Method. #[unsafe(method(doStuff))] pub fn doStuff(&self); ); } fn main() { let obj = Foo::init(Foo::alloc()); assert_eq!(obj.foo(), 42); obj.setFoo(10); obj.doStuff(); } ``` The plan for the future is to allow you to automatically map the Objective-C API that the Swift compiler generated using `bindgen`, see [#729](https://github.com/madsmtm/objc2/issues/729). ## Further research To my knowledge, there exist a few projects in the Rust ecosystem that help with some of this: - [`swift-rs`](https://github.com/Brendonovich/swift-rs) - [`swift-bridge`](https://github.com/chinedufn/swift-bridge) - [`swift-bindgen`](https://github.com/nvzqz/swift-bindgen) - [UniFFI](https://github.com/mozilla/uniffi-rs)