From 72e1759e0504e3a5a32587605c98e410f12ea9e7 Mon Sep 17 00:00:00 2001 From: Chinedu Francis Nwafili Date: Thu, 15 Dec 2022 12:21:34 -0500 Subject: [PATCH] Add support for already_declared enums (#125) This commit allows enums to use the `already_declared` attribute. This is useful when you want to use the same enum across multiple bridge modules. --- For example, the following is now possible: ```rust use some_other_bridge_module::SomeEnum; #[swift_bridge::bridge] mod ffi { #[swift_bridge(already_declared)] enum SomeEnum {} extern "Rust" { fn print(val: SomeEnum); } } ``` --- .../project.pbxproj | 4 + .../SharedEnumAttributeTests.swift | 23 ++++ crates/swift-bridge-ir/src/bridged_type.rs | 9 +- .../src/bridged_type/shared_enum.rs | 1 + ...lready_declared_attribute_codegen_tests.rs | 54 ++++++++ .../src/codegen/generate_c_header.rs | 4 + .../generate_rust_tokens/shared_enum.rs | 4 + .../src/codegen/generate_swift/shared_enum.rs | 4 + .../swift-bridge-ir/src/errors/parse_error.rs | 6 + crates/swift-bridge-ir/src/parse.rs | 24 +++- .../swift-bridge-ir/src/parse/parse_enum.rs | 121 +++++++++++++++++- .../swift-bridge-ir/src/parse/parse_struct.rs | 26 +--- .../src/parse/type_declarations.rs | 15 +-- .../src/enum_attributes.rs | 1 + .../src/enum_attributes/already_declared.rs | 25 ++++ crates/swift-integration-tests/src/lib.rs | 1 + .../src/struct_attributes/already_declared.rs | 3 - 17 files changed, 282 insertions(+), 43 deletions(-) create mode 100644 SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift create mode 100644 crates/swift-integration-tests/src/enum_attributes.rs create mode 100644 crates/swift-integration-tests/src/enum_attributes/already_declared.rs diff --git a/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner.xcodeproj/project.pbxproj b/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner.xcodeproj/project.pbxproj index 8ad930e8..47a5b874 100644 --- a/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner.xcodeproj/project.pbxproj +++ b/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 228FE64A274919C600805D9E /* swift-integration-tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228FE648274919C500805D9E /* swift-integration-tests.swift */; }; 22BC10F62799283100A0D046 /* SharedStruct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BC10F52799283100A0D046 /* SharedStruct.swift */; }; 22BC10F82799A3A000A0D046 /* SharedStructAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BC10F72799A3A000A0D046 /* SharedStructAttributes.swift */; }; + 22BC4BBA294B8CCD0032B8A8 /* SharedEnumAttributeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BC4BB9294B8CCD0032B8A8 /* SharedEnumAttributeTests.swift */; }; 22BCAAB927A2607700686A21 /* FunctionAttributeIdentifiableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BCAAB827A2607700686A21 /* FunctionAttributeIdentifiableTests.swift */; }; 22C0625328CE699D007A6F67 /* Callbacks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C0625228CE699D007A6F67 /* Callbacks.swift */; }; 22C0625528CE6C9A007A6F67 /* CallbackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C0625428CE6C9A007A6F67 /* CallbackTests.swift */; }; @@ -99,6 +100,7 @@ 228FE649274919C600805D9E /* swift-integration-tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "swift-integration-tests.h"; path = "swift-integration-tests/swift-integration-tests.h"; sourceTree = ""; }; 22BC10F52799283100A0D046 /* SharedStruct.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedStruct.swift; sourceTree = ""; }; 22BC10F72799A3A000A0D046 /* SharedStructAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedStructAttributes.swift; sourceTree = ""; }; + 22BC4BB9294B8CCD0032B8A8 /* SharedEnumAttributeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedEnumAttributeTests.swift; sourceTree = ""; }; 22BCAAB827A2607700686A21 /* FunctionAttributeIdentifiableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionAttributeIdentifiableTests.swift; sourceTree = ""; }; 22C0625228CE699D007A6F67 /* Callbacks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Callbacks.swift; sourceTree = ""; }; 22C0625428CE6C9A007A6F67 /* CallbackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallbackTests.swift; sourceTree = ""; }; @@ -199,6 +201,7 @@ 222A81EA28EB5DF800D4A412 /* PrimitiveTests.swift */, 220432EB27530AFC00BAE645 /* RustFnUsesOpaqueSwiftTypeTests.swift */, 2202BC0727B2DD1700D43CC4 /* SharedEnumTests.swift */, + 22BC4BB9294B8CCD0032B8A8 /* SharedEnumAttributeTests.swift */, 22C0AD50278ECA9E00A96469 /* SharedStructAttributeTests.swift */, 220432AE274E7BF800BAE645 /* SharedStructTests.swift */, 228FE5E62740DB6D00805D9E /* StringTests.swift */, @@ -402,6 +405,7 @@ 22C0AD51278ECA9E00A96469 /* SharedStructAttributeTests.swift in Sources */, 228FE5E72740DB6D00805D9E /* StringTests.swift in Sources */, 22C0625528CE6C9A007A6F67 /* CallbackTests.swift in Sources */, + 22BC4BBA294B8CCD0032B8A8 /* SharedEnumAttributeTests.swift in Sources */, 228FE61227428A8D00805D9E /* OpaqueSwiftStructTests.swift in Sources */, 22FD1C562753CB3F00F64281 /* SwiftFnUsesOpaqueRustTypeTests.swift in Sources */, 228FE61027416C0300805D9E /* OpaqueRustStructTests.swift in Sources */, diff --git a/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift b/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift new file mode 100644 index 00000000..e2da7afb --- /dev/null +++ b/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift @@ -0,0 +1,23 @@ +// +// SharedEnumAttributeTests.swift +// SwiftRustIntegrationTestRunnerTests +// +// Created by Frankie Nwafili on 12/15/22. +// + +import XCTest +@testable import SwiftRustIntegrationTestRunner + +/// Tests for attributes on transparent enum types. +class SharedEnumAttributeTests: XCTestCase { + /// Verify that we can call a function that uses a type that was already declared in a different bridge module. + func testSharedEnumAlreadyDeclared() throws { + XCTAssertEqual( + reflect_already_declared_enum( + AlreadyDeclaredEnumTest.Variant + ), + AlreadyDeclaredEnumTest.Variant + ) + } +} + diff --git a/crates/swift-bridge-ir/src/bridged_type.rs b/crates/swift-bridge-ir/src/bridged_type.rs index 70b7756a..ee9f70db 100644 --- a/crates/swift-bridge-ir/src/bridged_type.rs +++ b/crates/swift-bridge-ir/src/bridged_type.rs @@ -933,9 +933,14 @@ impl BridgedType { prefixed_ty_name } BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Enum(shared_enum))) => { - let ffi_ty_name = shared_enum.ffi_name_tokens(); + let ty_name = &shared_enum.name; - quote! { #ffi_ty_name } + if shared_enum.already_declared { + quote! { ::FfiRepr } + } else { + let ffi_ty_name = shared_enum.ffi_name_tokens(); + quote! { #ffi_ty_name } + } } }; diff --git a/crates/swift-bridge-ir/src/bridged_type/shared_enum.rs b/crates/swift-bridge-ir/src/bridged_type/shared_enum.rs index bec30dd1..da3a5a60 100644 --- a/crates/swift-bridge-ir/src/bridged_type/shared_enum.rs +++ b/crates/swift-bridge-ir/src/bridged_type/shared_enum.rs @@ -10,6 +10,7 @@ pub(crate) use self::enum_variant::EnumVariant; pub(crate) struct SharedEnum { pub name: Ident, pub variants: Vec, + pub already_declared: bool, } impl SharedEnum { diff --git a/crates/swift-bridge-ir/src/codegen/codegen_tests/already_declared_attribute_codegen_tests.rs b/crates/swift-bridge-ir/src/codegen/codegen_tests/already_declared_attribute_codegen_tests.rs index 7570ac75..a8114a58 100644 --- a/crates/swift-bridge-ir/src/codegen/codegen_tests/already_declared_attribute_codegen_tests.rs +++ b/crates/swift-bridge-ir/src/codegen/codegen_tests/already_declared_attribute_codegen_tests.rs @@ -146,6 +146,60 @@ struct __swift_bridge__$FfiSomeType __swift_bridge__$some_function(struct __swif } } +/// Verify that we do not re-declare an already defined enum. +mod already_declared_enum { + use super::*; + + fn bridge_module_tokens() -> TokenStream { + quote! { + mod ffi { + #[swift_bridge(already_declared, swift_repr = "enum")] + enum FfiSomeEnum {} + + extern "Rust" { + fn some_function(arg: FfiSomeEnum) -> FfiSomeEnum; + } + } + } + } + + fn expected_rust_tokens() -> ExpectedRustTokens { + ExpectedRustTokens::ContainsManyAndDoesNotContainMany { + contains: vec![quote! { + pub extern "C" fn __swift_bridge__some_function(arg: ::FfiRepr) -> ::FfiRepr { + super::some_function(arg.into_rust_repr()).into_ffi_repr() + } + }], + does_not_contain: vec![quote! { + enum FfiSomeEnum + }], + } + } + + fn expected_swift_code() -> ExpectedSwiftCode { + ExpectedSwiftCode::DoesNotContainAfterTrim("enum FfiSomeEnum") + } + + fn expected_c_header() -> ExpectedCHeader { + ExpectedCHeader::ExactAfterTrim( + r#" +struct __swift_bridge__$FfiSomeEnum __swift_bridge__$some_function(struct __swift_bridge__$FfiSomeEnum arg); +"#, + ) + } + + #[test] + fn already_declared_enum() { + CodegenTest { + bridge_module: bridge_module_tokens().into(), + expected_rust_tokens: expected_rust_tokens(), + expected_swift_code: expected_swift_code(), + expected_c_header: expected_c_header(), + } + .test(); + } +} + /// Verify that we do not re-declare the Swift struct of an already defined Rust Copy type. /// We still generate the Rust #\[repr(C)] struct since that is private to this module. mod already_declared_rust_copy_type_does_not_redeclare_swift { diff --git a/crates/swift-bridge-ir/src/codegen/generate_c_header.rs b/crates/swift-bridge-ir/src/codegen/generate_c_header.rs index 0378fe8c..e2e8c28c 100644 --- a/crates/swift-bridge-ir/src/codegen/generate_c_header.rs +++ b/crates/swift-bridge-ir/src/codegen/generate_c_header.rs @@ -126,6 +126,10 @@ typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi header += "\n"; } SharedTypeDeclaration::Enum(ty_enum) => { + if ty_enum.already_declared { + continue; + } + let ffi_name = ty_enum.ffi_name_string(); let ffi_tag_name = ty_enum.ffi_tag_name_string(); let option_ffi_name = ty_enum.ffi_option_name_string(); diff --git a/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/shared_enum.rs b/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/shared_enum.rs index 3fca7ce9..68aff638 100644 --- a/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/shared_enum.rs +++ b/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/shared_enum.rs @@ -14,6 +14,10 @@ impl SwiftBridgeModule { &self, shared_enum: &SharedEnum, ) -> Option { + if shared_enum.already_declared { + return None; + } + let enum_name = &shared_enum.name; let swift_bridge_path = &self.swift_bridge_path; diff --git a/crates/swift-bridge-ir/src/codegen/generate_swift/shared_enum.rs b/crates/swift-bridge-ir/src/codegen/generate_swift/shared_enum.rs index fc0a0038..d1564182 100644 --- a/crates/swift-bridge-ir/src/codegen/generate_swift/shared_enum.rs +++ b/crates/swift-bridge-ir/src/codegen/generate_swift/shared_enum.rs @@ -4,6 +4,10 @@ use crate::SwiftBridgeModule; impl SwiftBridgeModule { /// Generate the tokens for a shared enum. pub(super) fn generate_shared_enum_string(&self, shared_enum: &SharedEnum) -> Option { + if shared_enum.already_declared { + return None; + } + let enum_name = shared_enum.swift_name_string(); let enum_ffi_name = shared_enum.ffi_name_string(); let option_ffi_name = shared_enum.ffi_option_name_string(); diff --git a/crates/swift-bridge-ir/src/errors/parse_error.rs b/crates/swift-bridge-ir/src/errors/parse_error.rs index e7fb0c40..ce5223c8 100644 --- a/crates/swift-bridge-ir/src/errors/parse_error.rs +++ b/crates/swift-bridge-ir/src/errors/parse_error.rs @@ -34,6 +34,8 @@ pub(crate) enum ParseError { StructInvalidSwiftRepr { swift_repr_attr_value: LitStr }, /// A struct was declared with an unrecognized attribute. StructUnrecognizedAttribute { attribute: Ident }, + /// An enum was declared with an unrecognized attribute. + EnumUnrecognizedAttribute { attribute: Ident }, /// There is no reason to use `swift_repr = "class"` on an empty struct. /// It's extra overhead with no advantages. EmptyStructHasSwiftReprClass { @@ -157,6 +159,10 @@ struct {struct_name}; let message = format!(r#"Did not recognize struct attribute "{}"."#, attribute); Error::new_spanned(attribute, message) } + ParseError::EnumUnrecognizedAttribute { attribute } => { + let message = format!(r#"Did not recognize enum attribute "{}"."#, attribute); + Error::new_spanned(attribute, message) + } ParseError::FunctionAttribute(fn_attrib) => match fn_attrib { FunctionAttributeParseError::Identifiable(identifiable) => match identifiable { IdentifiableParseError::MustBeRefSelf { fn_ident } => { diff --git a/crates/swift-bridge-ir/src/parse.rs b/crates/swift-bridge-ir/src/parse.rs index d09b5597..62322c5f 100644 --- a/crates/swift-bridge-ir/src/parse.rs +++ b/crates/swift-bridge-ir/src/parse.rs @@ -5,9 +5,10 @@ use crate::parse::parse_enum::SharedEnumDeclarationParser; use crate::parse::parse_extern_mod::ForeignModParser; use crate::parse::parse_struct::SharedStructDeclarationParser; use crate::SwiftBridgeModule; +use proc_macro2::TokenTree; use quote::{quote, ToTokens}; use syn::parse::{Parse, ParseStream}; -use syn::{Item, ItemMod}; +use syn::{Item, ItemMod, Token}; mod parse_enum; mod parse_extern_mod; @@ -139,6 +140,27 @@ impl Parse for SwiftBridgeModuleAndErrors { } } +// Used to fast-forward our attribute parsing to the next attribute when we've run into an +// issue parsing the current attribute. +fn move_input_cursor_to_next_comma(input: ParseStream) { + if !input.peek(Token![,]) { + let _ = input.step(|cursor| { + let mut current_cursor = *cursor; + + while let Some((tt, next)) = current_cursor.token_tree() { + match &tt { + TokenTree::Punct(punct) if punct.as_char() == ',' => { + return Ok(((), current_cursor)); + } + _ => current_cursor = next, + } + } + + Ok(((), current_cursor)) + }); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/swift-bridge-ir/src/parse/parse_enum.rs b/crates/swift-bridge-ir/src/parse/parse_enum.rs index ebb7d32d..e1c0a831 100644 --- a/crates/swift-bridge-ir/src/parse/parse_enum.rs +++ b/crates/swift-bridge-ir/src/parse/parse_enum.rs @@ -1,5 +1,8 @@ use crate::bridged_type::{EnumVariant, SharedEnum, StructFields}; -use crate::errors::ParseErrors; +use crate::errors::{ParseError, ParseErrors}; +use crate::parse::move_input_cursor_to_next_comma; +use proc_macro2::Ident; +use syn::parse::{Parse, ParseStream}; use syn::ItemEnum; pub(crate) struct SharedEnumDeclarationParser<'a> { @@ -9,12 +12,74 @@ pub(crate) struct SharedEnumDeclarationParser<'a> { pub errors: &'a mut ParseErrors, } +enum EnumAttr { + AlreadyDeclared, + Error(EnumAttrParseError), +} + +enum EnumAttrParseError { + UnrecognizedAttribute(Ident), +} + +#[derive(Default)] +struct EnumAttribs { + already_declared: bool, +} + +struct ParsedAttribs(Vec); +impl Parse for ParsedAttribs { + fn parse(input: ParseStream) -> syn::Result { + if input.is_empty() { + return Ok(ParsedAttribs(vec![])); + } + + let opts = syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated(input)?; + + Ok(ParsedAttribs(opts.into_iter().collect())) + } +} + +impl Parse for EnumAttr { + fn parse(input: ParseStream) -> syn::Result { + let key: Ident = input.parse()?; + + let attr = match key.to_string().as_str() { + "already_declared" => EnumAttr::AlreadyDeclared, + _ => { + move_input_cursor_to_next_comma(input); + EnumAttr::Error(EnumAttrParseError::UnrecognizedAttribute(key)) + } + }; + + Ok(attr) + } +} + impl<'a> SharedEnumDeclarationParser<'a> { pub fn parse(self) -> Result { let item_enum = self.item_enum; let mut variants = vec![]; + let mut attribs = EnumAttribs::default(); + for attr in item_enum.attrs { + let sections: ParsedAttribs = attr.parse_args()?; + + for attr in sections.0 { + match attr { + EnumAttr::AlreadyDeclared => { + attribs.already_declared = true; + } + EnumAttr::Error(err) => match err { + EnumAttrParseError::UnrecognizedAttribute(attribute) => { + self.errors + .push(ParseError::EnumUnrecognizedAttribute { attribute }); + } + }, + } + } + } + for v in item_enum.variants { let variant = EnumVariant { name: v.ident, @@ -26,6 +91,7 @@ impl<'a> SharedEnumDeclarationParser<'a> { let shared_enum = SharedEnum { name: item_enum.ident, variants, + already_declared: attribs.already_declared, }; Ok(shared_enum) @@ -35,7 +101,8 @@ impl<'a> SharedEnumDeclarationParser<'a> { #[cfg(test)] mod tests { use crate::bridged_type::StructFields; - use crate::test_utils::parse_ok; + use crate::errors::ParseError; + use crate::test_utils::{parse_errors, parse_ok}; use quote::{quote, ToTokens}; /// Verify that we can parse an enum with no variants. @@ -105,4 +172,54 @@ mod tests { _ => panic!(), } } + + /// Verify that we can parse the `#[swift_bridge(already_declared)`] attribute. + #[test] + fn already_declared_attribute() { + let tokens = quote! { + #[swift_bridge::bridge] + mod ffi { + #[swift_bridge(already_declared)] + enum SomeEnum {} + } + }; + + let module = parse_ok(tokens); + + assert_eq!(module.types.types().len(), 1); + + let ty = &module.types.types()[0].unwrap_shared_enum(); + assert!(ty.already_declared); + } + + /// Verify that we return an error if an attribute isn't recognized. + #[test] + fn error_if_attribute_unrecognized() { + let tokens = quote! { + #[swift_bridge::bridge] + mod ffi { + #[swift_bridge(unrecognized, invalid_attribute = "hi")] + enum SomeEnum{ + Variant + } + } + }; + + let errors = parse_errors(tokens); + + assert_eq!(errors.len(), 2); + + match &errors[0] { + ParseError::EnumUnrecognizedAttribute { attribute } => { + assert_eq!(&attribute.to_string(), "unrecognized"); + } + _ => panic!(), + }; + match &errors[1] { + ParseError::EnumUnrecognizedAttribute { attribute } => { + assert_eq!(&attribute.to_string(), "invalid_attribute"); + } + _ => panic!(), + }; + } } diff --git a/crates/swift-bridge-ir/src/parse/parse_struct.rs b/crates/swift-bridge-ir/src/parse/parse_struct.rs index 10a294db..720b77cb 100644 --- a/crates/swift-bridge-ir/src/parse/parse_struct.rs +++ b/crates/swift-bridge-ir/src/parse/parse_struct.rs @@ -1,6 +1,7 @@ use crate::bridged_type::{SharedStruct, StructFields, StructSwiftRepr}; use crate::errors::{ParseError, ParseErrors}; -use proc_macro2::{Ident, TokenTree}; +use crate::parse::move_input_cursor_to_next_comma; +use proc_macro2::Ident; use syn::parse::{Parse, ParseStream}; use syn::{ItemStruct, LitStr, Token}; @@ -29,7 +30,6 @@ struct StructAttribs { } struct ParsedAttribs(Vec); - impl Parse for ParsedAttribs { fn parse(input: ParseStream) -> syn::Result { if input.is_empty() { @@ -66,7 +66,6 @@ impl Parse for StructAttr { "already_declared" => StructAttr::AlreadyDeclared, _ => { move_input_cursor_to_next_comma(input); - StructAttr::Error(StructAttrParseError::UnrecognizedAttribute(key)) } }; @@ -144,27 +143,6 @@ impl<'a> SharedStructDeclarationParser<'a> { } } -// Used to fast-forward our attribute parsing to the next attribute when we've run into an -// issue parsing the current attribute. -fn move_input_cursor_to_next_comma(input: ParseStream) { - if !input.peek(Token![,]) { - let _ = input.step(|cursor| { - let mut current_cursor = *cursor; - - while let Some((tt, next)) = current_cursor.token_tree() { - match &tt { - TokenTree::Punct(punct) if punct.as_char() == ',' => { - return Ok(((), current_cursor)); - } - _ => current_cursor = next, - } - } - - Ok(((), current_cursor)) - }); - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/swift-bridge-ir/src/parse/type_declarations.rs b/crates/swift-bridge-ir/src/parse/type_declarations.rs index 7678513d..93da07e0 100644 --- a/crates/swift-bridge-ir/src/parse/type_declarations.rs +++ b/crates/swift-bridge-ir/src/parse/type_declarations.rs @@ -36,20 +36,13 @@ impl TypeDeclaration { match self { TypeDeclaration::Shared(SharedTypeDeclaration::Struct(shared_struct)) => { BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Struct( - SharedStruct { - name: shared_struct.name.clone(), - swift_repr: shared_struct.swift_repr, - fields: shared_struct.fields.clone(), - swift_name: shared_struct.swift_name.clone(), - already_declared: shared_struct.already_declared, - }, + shared_struct.clone(), ))) } TypeDeclaration::Shared(SharedTypeDeclaration::Enum(shared_enum)) => { - BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Enum(SharedEnum { - name: shared_enum.name.clone(), - variants: shared_enum.variants.clone(), - }))) + BridgedType::Foreign(CustomBridgedType::Shared(SharedType::Enum( + shared_enum.clone(), + ))) } TypeDeclaration::Opaque(_o) => { BridgedType::Bridgeable(Box::new(self.to_opaque_type(reference, mutable).unwrap())) diff --git a/crates/swift-integration-tests/src/enum_attributes.rs b/crates/swift-integration-tests/src/enum_attributes.rs new file mode 100644 index 00000000..8adf9e7c --- /dev/null +++ b/crates/swift-integration-tests/src/enum_attributes.rs @@ -0,0 +1 @@ +mod already_declared; diff --git a/crates/swift-integration-tests/src/enum_attributes/already_declared.rs b/crates/swift-integration-tests/src/enum_attributes/already_declared.rs new file mode 100644 index 00000000..11cadaa5 --- /dev/null +++ b/crates/swift-integration-tests/src/enum_attributes/already_declared.rs @@ -0,0 +1,25 @@ +//! Verify that the `#[swift_bridge(already_declared)]` module prevents us from emitting the +//! same type definitions twice. + +use self::ffi1::AlreadyDeclaredEnumTest; + +#[swift_bridge::bridge] +mod ffi1 { + enum AlreadyDeclaredEnumTest { + Variant, + } +} + +#[swift_bridge::bridge] +mod ffi2 { + #[swift_bridge(already_declared)] + enum AlreadyDeclaredEnumTest {} + + extern "Rust" { + fn reflect_already_declared_enum(arg: AlreadyDeclaredEnumTest) -> AlreadyDeclaredEnumTest; + } +} + +fn reflect_already_declared_enum(arg: AlreadyDeclaredEnumTest) -> AlreadyDeclaredEnumTest { + arg +} diff --git a/crates/swift-integration-tests/src/lib.rs b/crates/swift-integration-tests/src/lib.rs index 15ef2af1..be55fd2a 100644 --- a/crates/swift-integration-tests/src/lib.rs +++ b/crates/swift-integration-tests/src/lib.rs @@ -17,6 +17,7 @@ mod swift_function_uses_opaque_rust_type; mod swift_function_uses_opaque_swift_type; mod vec; +mod enum_attributes; mod function_attributes; mod opaque_type_attributes; mod struct_attributes; diff --git a/crates/swift-integration-tests/src/struct_attributes/already_declared.rs b/crates/swift-integration-tests/src/struct_attributes/already_declared.rs index adfaa7a1..ffcf0098 100644 --- a/crates/swift-integration-tests/src/struct_attributes/already_declared.rs +++ b/crates/swift-integration-tests/src/struct_attributes/already_declared.rs @@ -1,8 +1,5 @@ //! Verify that the `#[swift_bridge(already_declared)]` module prevents us from emitting the //! same type definitions twice. -//! -//! If the Xcode project is able to compile then we know that our attribute works, -//! because otherwise we would get build time errors that the class was defined twice. use self::ffi1::AlreadyDeclaredStructTest;