You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: README.md
+49-16
Original file line number
Diff line number
Diff line change
@@ -4,18 +4,28 @@ Call Swift functions from Rust with ease!
4
4
5
5
## Setup
6
6
7
-
After adding `swift-rs` to your project's `Cargo.toml`, some setup work must be done.
7
+
Add `swift-rs` to your project's `dependencies` and `build-dependencies`:
8
+
9
+
```toml
10
+
[dependencies]
11
+
swift-rs = "0.3.0"
12
+
13
+
[build-dependencies]
14
+
swift-rs = { version = "0.3.0", features = "build" }
15
+
```
16
+
17
+
Next, some setup work must be done:
8
18
9
19
1. Ensure your swift code is organized into a Swift Package. This can be done in XCode by selecting File -> New -> Project -> Multiplatform -> Swift Package and importing your existing code.
10
-
2. Add SwiftRs as a dependency to your Swift package. A quick internet search can show you how to do this.
20
+
2. Add `SwiftRs` as a dependency to your Swift package. A quick internet search can show you how to do this.
11
21
3. Create a `build.rs` file in your project's source folder, if you don't have one already.
12
22
4. Link the swift runtime to your binary
13
23
14
24
```rust
15
-
useswift_rs::build_utils;
25
+
useswift_rs::build;
16
26
17
27
fnbuild() {
18
-
build_utils::link_swift();
28
+
build_utils::build();
19
29
20
30
// Other build steps
21
31
}
@@ -24,11 +34,11 @@ fn build() {
24
34
4. Link your swift package to your binary. `link_swift_package` takes 2 arguments: The name of your package as specified in its `Package.swift`, and the location of your package's root folder relative to your rust project's root folder.
@@ -40,9 +50,9 @@ With those steps completed, you should be ready to start using Swift code from R
40
50
41
51
To allow calling a Swift function from Rust, it must follow some rules:
42
52
43
-
1. It must be global and public
53
+
1. It must be global
44
54
2. It must be annotated with `@_cdecl`, so that it is callable from C
45
-
3. It must only use types that can be represented in Objective-C, so only classes that derive NSObject, as well as primitives such as Int and Bool. This excludes strings, arrays, generics (though all of these can be sent with workarounds) and structs (which are strictly forbidden).
55
+
3. It must only use types that can be represented in Objective-C, so only classes that derive `NSObject`, as well as primitives such as Int and Bool. This excludes strings, arrays, generics (though all of these can be sent with workarounds) and structs (which are strictly forbidden).
46
56
47
57
For this example we will use a function that simply squares a number:
48
58
@@ -103,7 +113,7 @@ struct SquareNumberResult {
103
113
}
104
114
```
105
115
106
-
We are not allowed to do this, though, since structs cannot be represented in Objective-C. Instead, we must use a class that extends NSObject:
116
+
We are not allowed to do this, though, since structs cannot be represented in Objective-C. Instead, we must use a class that extends `NSObject`:
107
117
108
118
```swift
109
119
classSquareNumberResult: NSObject {
@@ -159,11 +169,35 @@ fn main() {
159
169
letresult=unsafe { square_number(input) };
160
170
161
171
letresult_input=result.input; // 4
162
-
letresult_input=result.output; // 16
172
+
letresult_output=result.output; // 16
173
+
}
174
+
```
175
+
176
+
Creating objects in Rust and then passing them to Swift is not supported.
177
+
178
+
## Optionals
179
+
180
+
`swift-rs` also supports Swift's `nil` type, but only for functions that return optional `NSObject`s. Functions returning optional primitives cannot be represented in Objective C, and thus are not supported.
181
+
182
+
Let's say we have a function returning an optional `SRString`:
Thanks to Rust's [null pointer optimisation](https://doc.rust-lang.org/std/option/index.html#representation), the optional nature of `SRString?` can be represented by wrapping `SRString` in Rust's `Option<T>` type!
Currently, creating objects in Rust and then passing them to Swift is not supported.
200
+
Null pointers are actually the reason why a function that returns an optional primitives cannot be represented in C. If this were to be supported, how could a `nil` be differentiated from a number? It can't!
167
201
168
202
## Complex types
169
203
@@ -230,7 +264,7 @@ fn main() {
230
264
// or though the Deref trait
231
265
let value_str: &str =&*value_srstring;
232
266
233
-
//STString also implements Display
267
+
//SRString also implements Display
234
268
println!("{}", value_ststring); // Will print "lorem ipsum" to the console
235
269
}
236
270
```
@@ -381,11 +415,10 @@ Mutating values across Swift and Rust is not currently an aim for this library,
381
415
382
416
## Why?
383
417
384
-
I was helping my friend [Jamie Pine](https://twitter.com/jamiepine) with a desktop app made with [Tauri](https://twitter.com/TauriApps), an Electron alternative that uses Rust as its backend. One of the features Jamie wanted was to get the preview icon for files on his filesystem, which can be done with the [icon(forFile:)](https://developer.apple.com/documentation/appkit/nsworkspace/1528158-icon) function on the app's `NSWorkspace`. This requires accessing the static `shared` property of `NSWorkspace`, something that after some research wasn't possible using the [Rust Objective-C bindings](https://docs.rs/objc/0.2.7/objc/) (since from what I can tell it only supports sending and receiving messages, not accessing static properties), and I could figure out if [swift-bindgen](https://github.com/nvzqz/swift-bindgen) could do the job. So I created this library and the rest is history!
418
+
I was helping my friend [Jamie Pine](https://twitter.com/jamiepine) with a desktop app made with [Tauri](https://twitter.com/TauriApps), an Electron alternative that uses Rust as its backend. One of the features Jamie wanted was to get the preview icon for files on his filesystem, which can be done with the [icon(forFile:)](https://developer.apple.com/documentation/appkit/nsworkspace/1528158-icon) function on the app's `NSWorkspace`. This requires accessing the static `shared` property of `NSWorkspace`, something that after some research wasn't possible using the [Rust Objective-C bindings](https://docs.rs/objc/0.2.7/objc/) (since from what I can tell it only supports sending and receiving messages, not accessing static properties), and I couldn't figure out if [swift-bindgen](https://github.com/nvzqz/swift-bindgen) could do the job. So I created this library and the rest is history!
385
419
386
-
The examples folder is actually the same Swift code that Jamie uses in his project. While there's probably other, less unsafe ways to interop with Swift, its been both my and Jamie's experience that leveraging Swift for it's native API access and Rust for building applications is quite nice compared to wrangling Swift with calls from Rust similar to how the `objc` crate has you do. This library probably has a littany of problems around memory management and leaks since I'm not that well versed in the Swift runtime, but it gets the job done!
420
+
The examples folder issimilar to the same Swift code that Jamie uses in his project. While there's probably other, less unsafe ways to interop with Swift, its been both my and Jamie's experience that leveraging Swift for it's native API access and Rust for building applications is quite nice compared to wrangling Swift with calls from Rust similar to how the `objc` crate has you do. This library probably has a littany of problems around memory management and leaks since I'm not that well versed in the Swift runtime, but it gets the job done!
387
421
388
422
## Todo
389
423
390
-
- Swift class deallocation from rust (implementing Drop and using deallocate\_{type} methods)
0 commit comments