Skip to content

Commit 2724644

Browse files
authored
Support RustString in extern Swift functions (#225)
Related to #201. This commit adds support `RustString` in extern Swift functions. Here's an example of using this. ```Swift //Swift func reflect_swift_string(arg: RustString) -> RustString { arg } ``` ```Rust //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); ```
1 parent 36565f2 commit 2724644

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed

SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner/String.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ import Foundation
1010
func create_swift_string() -> String {
1111
"hello"
1212
}
13+
14+
func reflect_rust_string(arg: RustString) -> RustString {
15+
arg
16+
}

SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/StringTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class StringTests: XCTestCase {
4040

4141
func testRustStringToString() throws {
4242
let string = "hi"
43-
43+
4444
XCTAssertEqual(
4545
create_string(string).toString(),
4646
"hi"

crates/swift-bridge-ir/src/bridged_type/bridgeable_string.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ impl BridgeableType for BridgedString {
4949

5050
fn to_swift_type(&self, type_pos: TypePosition, _types: &TypeDeclarations) -> String {
5151
match type_pos {
52-
TypePosition::FnArg(_func_host_lang, _) => "GenericIntoRustString".to_string(),
52+
TypePosition::FnArg(func_host_lang, _) => {
53+
if func_host_lang.is_rust() {
54+
"GenericIntoRustString".to_string()
55+
} else {
56+
"UnsafeMutableRawPointer".to_string()
57+
}
58+
}
5359
TypePosition::FnReturn(func_host_lang) => {
5460
if func_host_lang.is_rust() {
5561
"RustString".to_string()

crates/swift-bridge-ir/src/codegen/codegen_tests/string_codegen_tests.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,50 @@ func __swift_bridge__some_function () -> UnsafeMutableRawPointer {
262262
.test();
263263
}
264264
}
265+
266+
/// Test code generation for Swift function that takes and returns an owned String argument.
267+
mod extern_swift_func_takes_and_returns_string {
268+
use super::*;
269+
270+
fn bridge_module_tokens() -> TokenStream {
271+
quote! {
272+
mod foo {
273+
extern "Swift" {
274+
fn some_function (value: String) -> String;
275+
}
276+
}
277+
}
278+
}
279+
280+
fn expected_rust_tokens() -> ExpectedRustTokens {
281+
ExpectedRustTokens::Contains(quote! {
282+
pub fn some_function (value: String) -> String {
283+
unsafe {
284+
Box :: from_raw (unsafe { __swift_bridge__some_function (swift_bridge :: string :: RustString (value) . box_into_raw ()) }) . 0
285+
}
286+
}
287+
})
288+
}
289+
290+
const EXPECTED_SWIFT_CODE: ExpectedSwiftCode = ExpectedSwiftCode::ContainsAfterTrim(
291+
r#"
292+
@_cdecl("__swift_bridge__$some_function")
293+
func __swift_bridge__some_function (_ value: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
294+
{ let rustString = some_function(value: RustString(ptr: value)).intoRustString(); rustString.isOwned = false; return rustString.ptr }()
295+
}
296+
"#,
297+
);
298+
299+
const EXPECTED_C_HEADER: ExpectedCHeader = ExpectedCHeader::ExactAfterTrim(r#""#);
300+
301+
#[test]
302+
fn extern_rust_fn_takes_and_returns_string() {
303+
CodegenTest {
304+
bridge_module: bridge_module_tokens().into(),
305+
expected_rust_tokens: expected_rust_tokens(),
306+
expected_swift_code: EXPECTED_SWIFT_CODE,
307+
expected_c_header: EXPECTED_C_HEADER,
308+
}
309+
.test();
310+
}
311+
}

crates/swift-integration-tests/src/string.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@ mod ffi {
88

99
extern "Swift" {
1010
fn create_swift_string() -> String;
11+
fn reflect_rust_string(arg: String) -> String;
1112
}
1213
}
1314

1415
fn run_string_tests() {
1516
let string = ffi::create_swift_string();
1617
assert_eq!(string.len(), 5);
1718
assert_eq!(&string, "hello");
19+
20+
let foo = "foo";
21+
let string = ffi::reflect_rust_string(foo.to_string());
22+
assert_eq!(string.len(), 3);
23+
assert_eq!(&string, foo);
1824
}
1925

2026
fn create_string(str: &str) -> String {

0 commit comments

Comments
 (0)