Skip to content

Commit 832498a

Browse files
authored
Support opaque types as enum variant fields (#181)
This commit adds support for opaque types as enum variant fields. However, This PR doesn't support generic opaque types. I'll write the reason later. Here's an example: ```rust #[swift_bridge::bridge] mod ffi { extern "Rust" { #[swift_bridge(Equatable)] type Foo; #[swift_bridge(associated_to = Foo)] fn new() -> Foo; } enum EnumWithNamedData { Variant1 { hello: String, data_u8: u8 }, Variant2 { data_i32: i32 }, Variant3 { foo: Foo }, } extern "Rust" { fn reflect_enum_with_named_data(arg: EnumWithNamedData) -> EnumWithNamedData; } } ``` ```Swift let enumWithNamedData3 = EnumWithNamedData.Variant3(foo: Foo.new()) switch reflect_enum_with_named_data(enumWithNamedData3) { case .Variant3(let foo): XCTAssertEqual(foo, Foo.new()) break default: XCTFail() } ```
1 parent 27d7be9 commit 832498a

File tree

15 files changed

+593
-174
lines changed

15 files changed

+593
-174
lines changed

SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumTests.swift

+55-14
Original file line numberDiff line numberDiff line change
@@ -33,58 +33,99 @@ class SharedEnumTests: XCTestCase {
3333
}
3434

3535
func testEnumWithUnnamedData() {
36-
let enumWithUnnamedData1 = EnumWithUnnamedData.Variant1(create_string("hello"), 0)
36+
let enumWithUnnamedData1 = EnumWithUnnamedData.TwoFields(create_string("hello"), OpaqueRustForEnumTest())
3737
switch reflect_enum_with_unnamed_data(enumWithUnnamedData1) {
38-
case .Variant1(let rustString, let valueUInt32):
38+
case .TwoFields(let rustString, let opaqueRustForEnumTest):
3939
XCTAssertEqual(rustString.toString(), "hello")
40-
XCTAssertEqual(valueUInt32, 0)
40+
XCTAssertEqual(opaqueRustForEnumTest, OpaqueRustForEnumTest())
4141
default:
4242
XCTFail()
4343
}
4444

45-
let enumWithUnnamedData2 = EnumWithUnnamedData.Variant2(1000, 10)
45+
let enumWithUnnamedData2 = EnumWithUnnamedData.OneField(1000)
4646
switch reflect_enum_with_unnamed_data(enumWithUnnamedData2) {
47-
case .Variant2(let valueInt32, let valueUInt8):
47+
case .OneField(let valueInt32):
4848
XCTAssertEqual(valueInt32, 1000)
49-
XCTAssertEqual(valueUInt8, 10)
5049
default:
5150
XCTFail()
5251
}
5352

54-
let enumWithUnnamedData3 = EnumWithUnnamedData.Variant3
53+
let enumWithUnnamedData3 = EnumWithUnnamedData.NoFields
5554
switch reflect_enum_with_unnamed_data(enumWithUnnamedData3) {
56-
case .Variant3:
55+
case .NoFields:
5756
break
5857
default:
5958
XCTFail()
6059
}
6160
}
6261

6362
func testEnumWithNamedData() {
64-
let enumWithNamedData1 = EnumWithNamedData.Variant1(hello: create_string("hello"), data_u8: 123)
63+
let enumWithNamedData1 = EnumWithNamedData.TwoFields(hello: create_string("hello"), data_u8: 123)
6564
switch reflect_enum_with_named_data(enumWithNamedData1) {
66-
case .Variant1(let hello, let dataU8):
65+
case .TwoFields(let hello, let dataU8):
6766
XCTAssertEqual(hello.toString(), "hello")
6867
XCTAssertEqual(dataU8, 123)
6968
default:
7069
XCTFail()
7170
}
7271

73-
let enumWithNamedData2 = EnumWithNamedData.Variant2(data_i32: -123)
72+
let enumWithNamedData2 = EnumWithNamedData.OneField(data_i32: -123)
7473
switch reflect_enum_with_named_data(enumWithNamedData2) {
75-
case .Variant2(let dataI32):
74+
case .OneField(let dataI32):
7675
XCTAssertEqual(dataI32, -123)
7776
default:
7877
XCTFail()
7978
}
8079

81-
let enumWithNamedData3 = EnumWithNamedData.Variant3
80+
let enumWithNamedData3 = EnumWithNamedData.NoFields
8281
switch reflect_enum_with_named_data(enumWithNamedData3) {
83-
case .Variant3:
82+
case .NoFields:
8483
break
8584
default:
8685
XCTFail()
8786
}
87+
}
88+
89+
func testEnumWithOpaqueRust() {
90+
let named = EnumWithOpaqueRust.Named(data: OpaqueRustForEnumTest())
91+
switch reflect_enum_with_opaque_type(named) {
92+
case .Named(let value):
93+
XCTAssertEqual(value, OpaqueRustForEnumTest())
94+
case .Unnamed(_):
95+
XCTFail()
96+
}
97+
98+
let unnamed = EnumWithOpaqueRust.Unnamed(OpaqueRustForEnumTest())
99+
switch reflect_enum_with_opaque_type(unnamed) {
100+
case .Named(_):
101+
XCTFail()
102+
case .Unnamed(let value):
103+
XCTAssertEqual(value, OpaqueRustForEnumTest())
104+
}
105+
}
88106

107+
func testEnumWithGenericOpaqueRust() {
108+
let named = EnumWithGenericOpaqueRust.Named(data: new_generic_opaque_rust_for_enum_test())
109+
switch reflect_enum_with_generic_opaque_type(named) {
110+
case .Named(_):
111+
// TODO: call a method on GenericOpaqueRustForEnumTest<Int32>
112+
// after we add support for methods on generic opaque Rust Types.
113+
// See https://github.com/chinedufn/swift-bridge/issues/44#issuecomment-1114198605
114+
break
115+
case .Unnamed(_):
116+
XCTFail()
117+
}
118+
119+
let unnamed = EnumWithGenericOpaqueRust.Unnamed(new_generic_opaque_rust_for_enum_test())
120+
switch reflect_enum_with_generic_opaque_type(unnamed) {
121+
case .Named(_):
122+
XCTFail()
123+
case .Unnamed(_):
124+
// TODO: call a method on GenericOpaqueRustForEnumTest<Int32>
125+
// after we add support for methods on generic opaque Rust Types.
126+
// See https://github.com/chinedufn/swift-bridge/issues/44#issuecomment-1114198605
127+
break
128+
}
89129
}
130+
90131
}

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

+49-105
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub(crate) trait BridgeableType: Debug {
7878

7979
/// Get the Rust representation of this type.
8080
/// For a string this might be `std::string::String`.
81-
fn to_rust_type_path(&self) -> TokenStream;
81+
fn to_rust_type_path(&self, types: &TypeDeclarations) -> TokenStream;
8282

8383
/// Get the Swift representation of this type.
8484
///
@@ -440,25 +440,8 @@ impl BridgeableType for BridgedType {
440440
}
441441
}
442442

443-
/***
444-
fn extract_swift_result_variants(
445-
&self,
446-
type_pos: TypePosition,
447-
types: &TypeDeclarations,
448-
) -> Option<(String, String)> {
449-
match self {
450-
BridgedType::StdLib(StdLibType::Result(result)) => Some((
451-
result.ok_ty.to_swift_type(type_pos, types),
452-
result.err_ty.to_swift_type(type_pos, types),
453-
)),
454-
BridgedType::Bridgeable(ty) => ty.extract_swift_result_variants(type_pos, types),
455-
_ => None,
456-
}
457-
}
458-
***/
459-
460-
fn to_rust_type_path(&self) -> TokenStream {
461-
self.to_rust_type_path()
443+
fn to_rust_type_path(&self, types: &TypeDeclarations) -> TokenStream {
444+
self.to_rust_type_path(types)
462445
}
463446

464447
fn to_swift_type(&self, type_pos: TypePosition, types: &TypeDeclarations) -> String {
@@ -783,58 +766,43 @@ impl BridgedType {
783766
// U8 -> u8
784767
// Vec<U32> -> Vec<u32>
785768
// SomeOpaqueRustType -> super::SomeOpaqueRustType
786-
pub(crate) fn to_rust_type_path(&self) -> TokenStream {
769+
pub(crate) fn to_rust_type_path(&self, types: &TypeDeclarations) -> TokenStream {
787770
match self {
788-
BridgedType::Bridgeable(b) => b.to_rust_type_path(),
789-
BridgedType::StdLib(stdlib_type) => {
790-
match stdlib_type {
791-
StdLibType::Null => {
792-
quote! {()}
793-
}
794-
StdLibType::U8 => quote! { u8 },
795-
StdLibType::I8 => quote! { i8 },
796-
StdLibType::U16 => quote! { u16},
797-
StdLibType::I16 => quote! { i16},
798-
StdLibType::U32 => quote! { u32 },
799-
StdLibType::I32 => quote! { i32 },
800-
StdLibType::U64 => quote! { u64 },
801-
StdLibType::I64 => quote! { i64 },
802-
StdLibType::Usize => quote! { usize },
803-
StdLibType::Isize => quote! { isize },
804-
StdLibType::F32 => quote! { f32 },
805-
StdLibType::F64 => quote! { f64 },
806-
StdLibType::Bool => quote! { bool },
807-
StdLibType::Pointer(ptr) => {
808-
let ptr_kind = &ptr.kind;
809-
810-
match &ptr.pointee {
811-
Pointee::BuiltIn(ty) => {
812-
let ty = ty.to_rust_type_path();
813-
quote! { #ptr_kind #ty}
814-
}
815-
Pointee::Void(_ty) => {
816-
// quote! { * #ptr_kind #ty };
817-
panic!("Add a test case that hits this branch, then make it pass")
818-
}
819-
}
820-
}
821-
StdLibType::RefSlice(ref_slice) => {
822-
let ty = ref_slice.ty.to_rust_type_path();
823-
quote! { &[#ty]}
824-
}
825-
StdLibType::Str => quote! { &str },
826-
StdLibType::Vec(v) => {
827-
let ty = v.ty.to_rust_type_path();
828-
quote! { Vec<#ty> }
829-
}
830-
StdLibType::Option(opt) => {
831-
let ty = opt.ty.to_rust_type_path();
832-
quote! { Option<#ty> }
833-
}
834-
StdLibType::Result(result) => result.to_rust_type_path(),
835-
StdLibType::BoxedFnOnce(fn_once) => fn_once.to_rust_type_path(),
771+
BridgedType::Bridgeable(b) => b.to_rust_type_path(types),
772+
BridgedType::StdLib(stdlib_type) => match stdlib_type {
773+
StdLibType::Null => {
774+
quote! {()}
836775
}
837-
}
776+
StdLibType::U8 => quote! { u8 },
777+
StdLibType::I8 => quote! { i8 },
778+
StdLibType::U16 => quote! { u16},
779+
StdLibType::I16 => quote! { i16},
780+
StdLibType::U32 => quote! { u32 },
781+
StdLibType::I32 => quote! { i32 },
782+
StdLibType::U64 => quote! { u64 },
783+
StdLibType::I64 => quote! { i64 },
784+
StdLibType::Usize => quote! { usize },
785+
StdLibType::Isize => quote! { isize },
786+
StdLibType::F32 => quote! { f32 },
787+
StdLibType::F64 => quote! { f64 },
788+
StdLibType::Bool => quote! { bool },
789+
StdLibType::Pointer(ptr) => ptr.to_rust_type_path(types),
790+
StdLibType::RefSlice(ref_slice) => {
791+
let ty = ref_slice.ty.to_rust_type_path(types);
792+
quote! { &[#ty]}
793+
}
794+
StdLibType::Str => quote! { &str },
795+
StdLibType::Vec(v) => {
796+
let ty = v.ty.to_rust_type_path(types);
797+
quote! { Vec<#ty> }
798+
}
799+
StdLibType::Option(opt) => {
800+
let ty = opt.ty.to_rust_type_path(types);
801+
quote! { Option<#ty> }
802+
}
803+
StdLibType::Result(result) => result.to_rust_type_path(types),
804+
StdLibType::BoxedFnOnce(fn_once) => fn_once.to_rust_type_path(types),
805+
},
838806
BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Struct(shared_struct))) => {
839807
let ty_name = &shared_struct.name;
840808
quote! {
@@ -877,18 +845,7 @@ impl BridgedType {
877845
StdLibType::Isize => quote! { isize },
878846
StdLibType::Bool => quote! { bool },
879847
StdLibType::Pointer(ptr) => {
880-
let kind = ptr.kind.to_token_stream();
881-
882-
let ty = match &ptr.pointee {
883-
Pointee::BuiltIn(ty) => {
884-
ty.to_ffi_compatible_rust_type(swift_bridge_path, types)
885-
}
886-
Pointee::Void(ty) => {
887-
quote! { super::#ty }
888-
}
889-
};
890-
891-
quote! { #kind #ty}
848+
ptr.to_ffi_compatible_rust_type(swift_bridge_path, types)
892849
}
893850
StdLibType::RefSlice(slice) => {
894851
let ty = slice
@@ -903,7 +860,7 @@ impl BridgedType {
903860
quote! { () }
904861
}
905862
StdLibType::Vec(ty) => {
906-
let ty = ty.ty.to_rust_type_path();
863+
let ty = ty.ty.to_rust_type_path(types);
907864
quote! { *mut Vec<#ty> }
908865
}
909866
StdLibType::Option(opt) => match opt.ty.deref() {
@@ -963,7 +920,7 @@ impl BridgedType {
963920
quote! { #swift_bridge_path::string::RustStr }
964921
}
965922
StdLibType::Vec(ty) => {
966-
let ty = ty.ty.to_rust_type_path();
923+
let ty = ty.ty.to_rust_type_path(types);
967924
quote! { *mut Vec<#ty> }
968925
}
969926
StdLibType::Option(_) => {
@@ -990,7 +947,7 @@ impl BridgedType {
990947
}
991948
},
992949
StdLibType::Result(result) => result.to_ffi_compatible_rust_type(swift_bridge_path),
993-
StdLibType::BoxedFnOnce(fn_once) => fn_once.to_ffi_compatible_rust_type(),
950+
StdLibType::BoxedFnOnce(fn_once) => fn_once.to_ffi_compatible_rust_type(types),
994951
},
995952
BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Struct(shared_struct))) => {
996953
let ty_name = &shared_struct.name;
@@ -1223,26 +1180,13 @@ impl BridgedType {
12231180
/// unsafe { __swift_bridge__void_pointers(arg1) }
12241181
/// }
12251182
///
1226-
pub fn maybe_convert_pointer_to_super_pointer(&self) -> TokenStream {
1183+
pub fn maybe_convert_pointer_to_super_pointer(&self, types: &TypeDeclarations) -> TokenStream {
12271184
match self {
1228-
BridgedType::StdLib(stdlib_type) => {
1229-
match stdlib_type {
1230-
StdLibType::Pointer(pointer) => match &pointer.pointee {
1231-
Pointee::BuiltIn(_built_in) => {
1232-
//
1233-
self.to_rust_type_path()
1234-
}
1235-
Pointee::Void(_) => {
1236-
let pointer_kind = &pointer.kind;
1237-
let pointee = &pointer.pointee;
1238-
1239-
quote! { #pointer_kind super:: #pointee }
1240-
}
1241-
},
1242-
_ => self.to_rust_type_path(),
1243-
}
1244-
}
1245-
_ => self.to_rust_type_path(),
1185+
BridgedType::StdLib(stdlib_type) => match stdlib_type {
1186+
StdLibType::Pointer(pointer) => pointer.to_rust_type_path(types),
1187+
_ => self.to_rust_type_path(types),
1188+
},
1189+
_ => self.to_rust_type_path(types),
12461190
}
12471191
}
12481192

@@ -1307,7 +1251,7 @@ impl BridgedType {
13071251
span,
13081252
),
13091253
StdLibType::BoxedFnOnce(fn_once) => {
1310-
fn_once.convert_rust_value_to_ffi_compatible_value(expression)
1254+
fn_once.convert_rust_value_to_ffi_compatible_value(expression, types)
13111255
}
13121256
},
13131257
BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Struct(shared_struct))) => {

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

+21-8
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ impl BridgeableBoxedFnOnce {
3434
}
3535

3636
/// Box<dyn FnOnce(A, B) -> C>
37-
pub fn to_rust_type_path(&self) -> TokenStream {
38-
let args: Vec<TokenStream> = self.params.iter().map(|a| a.to_rust_type_path()).collect();
39-
let ret = &self.ret.to_rust_type_path();
37+
pub fn to_rust_type_path(&self, types: &TypeDeclarations) -> TokenStream {
38+
let args: Vec<TokenStream> = self
39+
.params
40+
.iter()
41+
.map(|a| a.to_rust_type_path(types))
42+
.collect();
43+
let ret = &self.ret.to_rust_type_path(types);
4044
quote! {
4145
Box<dyn FnOnce(#(#args),*) -> #ret>
4246
}
@@ -45,18 +49,27 @@ impl BridgeableBoxedFnOnce {
4549
pub fn convert_rust_value_to_ffi_compatible_value(
4650
&self,
4751
expression: &TokenStream,
52+
types: &TypeDeclarations,
4853
) -> TokenStream {
49-
let args: Vec<TokenStream> = self.params.iter().map(|a| a.to_rust_type_path()).collect();
50-
let ret = &self.ret.to_rust_type_path();
54+
let args: Vec<TokenStream> = self
55+
.params
56+
.iter()
57+
.map(|a| a.to_rust_type_path(types))
58+
.collect();
59+
let ret = &self.ret.to_rust_type_path(types);
5160

5261
quote! {
5362
Box::into_raw(Box::new(#expression)) as *mut Box<dyn FnOnce(#(#args),*) -> #ret>
5463
}
5564
}
5665

57-
pub fn to_ffi_compatible_rust_type(&self) -> TokenStream {
58-
let params: Vec<TokenStream> = self.params.iter().map(|a| a.to_rust_type_path()).collect();
59-
let ret = &self.ret.to_rust_type_path();
66+
pub fn to_ffi_compatible_rust_type(&self, types: &TypeDeclarations) -> TokenStream {
67+
let params: Vec<TokenStream> = self
68+
.params
69+
.iter()
70+
.map(|a| a.to_rust_type_path(types))
71+
.collect();
72+
let ret = &self.ret.to_rust_type_path(types);
6073
quote! {
6174
*mut Box<dyn FnOnce(#(#params),*) -> #ret>
6275
}

0 commit comments

Comments
 (0)