Skip to content

Commit 58f4a40

Browse files
authored
Swift Option<String> and Option<&str> (#264)
This commit adds support for passing `Option<String>` to and from `extern "Swift"` functions, as well as for passing `Option<&str>` to extern "Swift" functions. For example, the following is now possible: ```rust #[swift_bridge::bridge] mod ffi { extern "Swift" { fn opt_string_function(arg: Option<String>) -> Option<String>; fn opt_str_function(arg: Option<&str>); } } ``` Note that you can not yet return `-> Option<&str>` from Swift. This is an uncommon use case, so we're waiting until someone actually needs it.
1 parent 53b118d commit 58f4a40

27 files changed

+645
-132
lines changed

SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner/Option.swift

+19
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,22 @@ func swift_reflect_option_bool(arg: Optional<Bool>) -> Optional<Bool> {
4747
arg
4848
}
4949

50+
51+
func swift_reflect_option_string(arg: Optional<RustString>) -> Optional<RustString> {
52+
arg
53+
}
54+
// TODO: Change `swift_arg_option_str` `swift_reflect_option_str` once we support Swift returning `-> &str` via RustStr
55+
// For now we return true if the arg is Some and false if arg is None
56+
//func swift_reflect_option_str(arg: Optional<RustStr>) -> Optional<RustStr> {
57+
// arg
58+
//}
59+
func swift_arg_option_str(arg: Optional<RustStr>) -> Bool {
60+
if let val = arg {
61+
assert(val.toString() == "this is an option str")
62+
return true
63+
} else {
64+
return false
65+
}
66+
67+
}
68+

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

+66-24
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ pub(crate) trait BridgeableType: Debug {
117117
/// Get the Swift representation of this type.
118118
///
119119
/// For example, `Result<String, ()>` would become `RustResult<String, ()>`
120-
fn to_swift_type(&self, type_pos: TypePosition, types: &TypeDeclarations) -> String;
120+
fn to_swift_type(
121+
&self,
122+
type_pos: TypePosition,
123+
types: &TypeDeclarations,
124+
swift_bridge_path: &Path,
125+
) -> String;
121126

122127
/// Get the C representation of this type.
123128
fn to_c_type(&self, types: &TypeDeclarations) -> String;
@@ -146,6 +151,7 @@ pub(crate) trait BridgeableType: Debug {
146151
/// Get the FFI compatible Option<Self> representation.
147152
fn to_ffi_compatible_option_swift_type(
148153
&self,
154+
type_pos: TypePosition,
149155
swift_bridge_path: &Path,
150156
types: &TypeDeclarations,
151157
) -> String;
@@ -207,6 +213,7 @@ pub(crate) trait BridgeableType: Debug {
207213
expression: &str,
208214
type_pos: TypePosition,
209215
types: &TypeDeclarations,
216+
swift_bridge_path: &Path,
210217
) -> String;
211218

212219
/// Convert an Option<Self> FFI representation to the Rust representation.
@@ -285,6 +292,8 @@ pub(crate) trait BridgeableType: Debug {
285292
/// of checking the type.
286293
fn contains_ref_string_recursive(&self) -> bool;
287294

295+
// TODO: Is this used? Do we need this?
296+
#[allow(unused)]
288297
/// Parse the type from a `FnArg`.
289298
fn from_fn_arg(
290299
fn_arg: &FnArg,
@@ -532,8 +541,13 @@ impl BridgeableType for BridgedType {
532541
self.to_rust_type_path(types)
533542
}
534543

535-
fn to_swift_type(&self, type_pos: TypePosition, types: &TypeDeclarations) -> String {
536-
self.to_swift_type(type_pos, types)
544+
fn to_swift_type(
545+
&self,
546+
type_pos: TypePosition,
547+
types: &TypeDeclarations,
548+
swift_bridge_path: &Path,
549+
) -> String {
550+
self.to_swift_type(type_pos, types, swift_bridge_path)
537551
}
538552

539553
fn to_c_type(&self, types: &TypeDeclarations) -> String {
@@ -562,6 +576,7 @@ impl BridgeableType for BridgedType {
562576

563577
fn to_ffi_compatible_option_swift_type(
564578
&self,
579+
_type_pos: TypePosition,
565580
_swift_bridge_path: &Path,
566581
_types: &TypeDeclarations,
567582
) -> String {
@@ -626,8 +641,9 @@ impl BridgeableType for BridgedType {
626641
expression: &str,
627642
type_pos: TypePosition,
628643
types: &TypeDeclarations,
644+
swift_bridge_path: &Path,
629645
) -> String {
630-
self.convert_ffi_value_to_swift_value(expression, type_pos, types)
646+
self.convert_ffi_value_to_swift_value(expression, type_pos, types, swift_bridge_path)
631647
}
632648

633649
fn convert_ffi_option_expression_to_swift_type(&self, _expression: &str) -> String {
@@ -1091,9 +1107,14 @@ impl BridgedType {
10911107
// U8 -> UInt8
10921108
// *const u32 -> UnsafePointer<UInt32>
10931109
// ... etc
1094-
pub fn to_swift_type(&self, type_pos: TypePosition, types: &TypeDeclarations) -> String {
1110+
pub fn to_swift_type(
1111+
&self,
1112+
type_pos: TypePosition,
1113+
types: &TypeDeclarations,
1114+
swift_bridge_path: &Path,
1115+
) -> String {
10951116
match self {
1096-
BridgedType::Bridgeable(b) => b.to_swift_type(type_pos, types),
1117+
BridgedType::Bridgeable(b) => b.to_swift_type(type_pos, types, swift_bridge_path),
10971118
BridgedType::StdLib(stdlib_type) => match stdlib_type {
10981119
StdLibType::U8 => "UInt8".to_string(),
10991120
StdLibType::I8 => "Int8".to_string(),
@@ -1119,7 +1140,7 @@ impl BridgedType {
11191140
format!(
11201141
"Unsafe{}Pointer<{}>",
11211142
maybe_mutable,
1122-
ty.to_swift_type(type_pos, types)
1143+
ty.to_swift_type(type_pos, types, swift_bridge_path)
11231144
)
11241145
}
11251146
Pointee::Void(_) => {
@@ -1136,7 +1157,7 @@ impl BridgedType {
11361157
} else {
11371158
format!(
11381159
"UnsafeBufferPointer<{}>",
1139-
slice.ty.to_swift_type(type_pos, types)
1160+
slice.ty.to_swift_type(type_pos, types, swift_bridge_path)
11401161
)
11411162
}
11421163
}
@@ -1167,26 +1188,37 @@ impl BridgedType {
11671188
StdLibType::Vec(ty) => match type_pos {
11681189
TypePosition::FnArg(func_host_lang, _) => {
11691190
if func_host_lang.is_rust() {
1170-
format!("RustVec<{}>", ty.ty.to_swift_type(type_pos, types))
1191+
format!(
1192+
"RustVec<{}>",
1193+
ty.ty.to_swift_type(type_pos, types, swift_bridge_path)
1194+
)
11711195
} else {
11721196
"UnsafeMutableRawPointer".to_string()
11731197
}
11741198
}
11751199
TypePosition::FnReturn(func_host_lang) => {
11761200
if func_host_lang.is_rust() {
1177-
format!("RustVec<{}>", ty.ty.to_swift_type(type_pos, types))
1201+
format!(
1202+
"RustVec<{}>",
1203+
ty.ty.to_swift_type(type_pos, types, swift_bridge_path)
1204+
)
11781205
} else {
11791206
"UnsafeMutableRawPointer".to_string()
11801207
}
11811208
}
11821209
_ => {
1183-
format!("RustVec<{}>", ty.ty.to_swift_type(type_pos, types))
1210+
format!(
1211+
"RustVec<{}>",
1212+
ty.ty.to_swift_type(type_pos, types, swift_bridge_path)
1213+
)
11841214
}
11851215
},
1186-
StdLibType::Option(opt) => opt.to_swift_type(type_pos, types),
1187-
StdLibType::Result(result) => result.to_swift_type(type_pos, types),
1216+
StdLibType::Option(opt) => opt.to_swift_type(swift_bridge_path, type_pos, types),
1217+
StdLibType::Result(result) => {
1218+
result.to_swift_type(type_pos, types, swift_bridge_path)
1219+
}
11881220
StdLibType::BoxedFnOnce(boxed_fn) => boxed_fn.to_swift_type().to_string(),
1189-
StdLibType::Tuple(tuple) => tuple.to_swift_type(type_pos, types),
1221+
StdLibType::Tuple(tuple) => tuple.to_swift_type(type_pos, types, swift_bridge_path),
11901222
},
11911223
BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Struct(shared_struct))) => {
11921224
match type_pos {
@@ -1482,11 +1514,15 @@ impl BridgedType {
14821514
expression: &str,
14831515
type_pos: TypePosition,
14841516
types: &TypeDeclarations,
1517+
swift_bridge_path: &Path,
14851518
) -> String {
14861519
match self {
1487-
BridgedType::Bridgeable(b) => {
1488-
b.convert_ffi_expression_to_swift_type(expression, type_pos, types)
1489-
}
1520+
BridgedType::Bridgeable(b) => b.convert_ffi_expression_to_swift_type(
1521+
expression,
1522+
type_pos,
1523+
types,
1524+
swift_bridge_path,
1525+
),
14901526
BridgedType::StdLib(stdlib_type) => match stdlib_type {
14911527
StdLibType::Null
14921528
| StdLibType::U8
@@ -1530,23 +1566,29 @@ impl BridgedType {
15301566
format!(
15311567
"let slice = {value}; return UnsafeBufferPointer(start: slice.start.assumingMemoryBound(to: {ty}.self), count: Int(slice.len));",
15321568
value = expression,
1533-
ty = ty.ty.to_swift_type(type_pos,types)
1569+
ty = ty.ty.to_swift_type(type_pos,types,swift_bridge_path)
15341570
)
15351571
}
15361572
StdLibType::Str => expression.to_string(),
15371573
StdLibType::Vec(_ty) => {
15381574
format!("RustVec(ptr: {})", expression)
15391575
}
15401576
StdLibType::Option(opt) => opt.convert_ffi_expression_to_swift_type(expression),
1541-
StdLibType::Result(result) => {
1542-
result.convert_ffi_value_to_swift_value(expression, type_pos, types)
1543-
}
1577+
StdLibType::Result(result) => result.convert_ffi_value_to_swift_value(
1578+
expression,
1579+
type_pos,
1580+
types,
1581+
swift_bridge_path,
1582+
),
15441583
StdLibType::BoxedFnOnce(fn_once) => {
15451584
fn_once.convert_ffi_value_to_swift_value(type_pos)
15461585
}
1547-
StdLibType::Tuple(tuple) => {
1548-
tuple.convert_ffi_expression_to_swift_type(expression, type_pos, types)
1549-
}
1586+
StdLibType::Tuple(tuple) => tuple.convert_ffi_expression_to_swift_type(
1587+
expression,
1588+
type_pos,
1589+
types,
1590+
swift_bridge_path,
1591+
),
15501592
},
15511593
BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Struct(shared_struct))) => {
15521594
shared_struct.convert_ffi_expression_to_swift_type(expression)

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

+10-2
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,20 @@ impl BridgeableBoxedFnOnce {
9999
}
100100

101101
/// arg0: UInt8, arg1: SomeType, ...
102-
pub fn params_to_swift_types(&self, types: &TypeDeclarations) -> String {
102+
pub fn params_to_swift_types(
103+
&self,
104+
types: &TypeDeclarations,
105+
swift_bridge_path: &Path,
106+
) -> String {
103107
self.params
104108
.iter()
105109
.enumerate()
106110
.map(|(idx, ty)| {
107-
let ty = ty.to_swift_type(TypePosition::FnArg(HostLang::Rust, idx), types);
111+
let ty = ty.to_swift_type(
112+
TypePosition::FnArg(HostLang::Rust, idx),
113+
types,
114+
swift_bridge_path,
115+
);
108116

109117
format!("_ arg{idx}: {ty}")
110118
})

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ impl BridgeableType for BuiltInPointer {
7373
}
7474
}
7575

76-
fn to_swift_type(&self, _type_pos: TypePosition, _types: &TypeDeclarations) -> String {
76+
fn to_swift_type(
77+
&self,
78+
_type_pos: TypePosition,
79+
_types: &TypeDeclarations,
80+
_swift_bridge_path: &Path,
81+
) -> String {
7782
todo!()
7883
}
7984

@@ -112,6 +117,7 @@ impl BridgeableType for BuiltInPointer {
112117

113118
fn to_ffi_compatible_option_swift_type(
114119
&self,
120+
_type_pos: TypePosition,
115121
_swift_bridge_path: &Path,
116122
_types: &TypeDeclarations,
117123
) -> String {
@@ -176,6 +182,7 @@ impl BridgeableType for BuiltInPointer {
176182
_expression: &str,
177183
_type_pos: TypePosition,
178184
_types: &TypeDeclarations,
185+
_swift_bridge_path: &Path,
179186
) -> String {
180187
todo!()
181188
}

0 commit comments

Comments
 (0)