From 53b93f47cc32d605377194a43f3164745cea6dd6 Mon Sep 17 00:00:00 2001 From: naturecodevoid <44983869+naturecodevoid@users.noreply.github.com> Date: Wed, 5 Apr 2023 18:38:03 -0700 Subject: [PATCH] Support derive(Debug) on enums (#194) Related issue: #190 Example: ```rs // Rust #[swift_bridge::bridge] mod ffi { #[derive(Debug)] enum DeriveDebugEnum { Variant, } } ``` ```swift // Swift let debugString = String(reflecting: DeriveDebugEnum.Variant) XCTAssertEqual(debugString, "Variant") ``` --- .../SharedEnumAttributeTests.swift | 7 ++ SwiftRustIntegrationTestRunner/build-rust.sh | 2 +- crates/swift-bridge-ir/src/bridged_type.rs | 2 +- .../src/bridged_type/shared_enum.rs | 6 + .../src/codegen/codegen_tests.rs | 1 + .../derive_attribute_codegen_tests.rs | 68 +++++++++++ .../src/codegen/generate_c_header.rs | 12 +- .../generate_rust_tokens/shared_enum.rs | 30 ++++- .../vec/vec_of_transparent_enum.rs | 3 +- .../src/codegen/generate_swift/shared_enum.rs | 15 ++- crates/swift-bridge-ir/src/errors.rs | 6 + .../swift-bridge-ir/src/parse/parse_enum.rs | 115 +++++------------- .../src/parse/parse_enum/enum_attributes.rs | 108 ++++++++++++++++ .../tests/ui/unrecognized-enum-attribute.rs | 11 ++ .../ui/unrecognized-enum-attribute.stderr | 5 + .../src/enum_attributes.rs | 1 + .../src/enum_attributes/derive.rs | 7 ++ test-swift-rust-integration.sh | 2 +- 18 files changed, 307 insertions(+), 94 deletions(-) create mode 100644 crates/swift-bridge-ir/src/codegen/codegen_tests/derive_attribute_codegen_tests.rs create mode 100644 crates/swift-bridge-ir/src/parse/parse_enum/enum_attributes.rs create mode 100644 crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.rs create mode 100644 crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.stderr create mode 100644 crates/swift-integration-tests/src/enum_attributes/derive.rs diff --git a/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift b/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift index 22f55fb1..04d17a65 100644 --- a/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift +++ b/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/SharedEnumAttributeTests.swift @@ -30,5 +30,12 @@ class SharedEnumAttributeTests: XCTestCase { AlreadyDeclaredEnumTest.Variant ) } + + + /// Verify that we can use the generated Debug impl. + func testSharedEnumDeriveDebug() throws { + let debugString = String(reflecting: DeriveDebugEnum.Variant) + XCTAssertEqual(debugString, "Variant") + } } diff --git a/SwiftRustIntegrationTestRunner/build-rust.sh b/SwiftRustIntegrationTestRunner/build-rust.sh index b0a00f49..dbd551d0 100755 --- a/SwiftRustIntegrationTestRunner/build-rust.sh +++ b/SwiftRustIntegrationTestRunner/build-rust.sh @@ -15,7 +15,7 @@ if [[ -n "${DEVELOPER_SDK_DIR:-}" ]]; then export LIBRARY_PATH="${DEVELOPER_SDK_DIR}/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}" fi -cd $PROJECT_DIR +cd "$PROJECT_DIR" if [[ $CONFIGURATION == "Release" ]]; then echo "BUIlDING FOR RELEASE" diff --git a/crates/swift-bridge-ir/src/bridged_type.rs b/crates/swift-bridge-ir/src/bridged_type.rs index 1f378533..5dc71559 100644 --- a/crates/swift-bridge-ir/src/bridged_type.rs +++ b/crates/swift-bridge-ir/src/bridged_type.rs @@ -17,7 +17,7 @@ use crate::bridged_type::built_in_tuple::BuiltInTuple; use crate::parse::{HostLang, TypeDeclaration, TypeDeclarations}; use self::bridged_option::BridgedOption; -pub(crate) use self::shared_enum::{EnumVariant, SharedEnum}; +pub(crate) use self::shared_enum::{DeriveAttrs, EnumVariant, SharedEnum}; pub(crate) use self::shared_struct::{SharedStruct, StructFields, StructSwiftRepr}; pub(crate) mod boxed_fn; 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 297e9a82..59f0b7ec 100644 --- a/crates/swift-bridge-ir/src/bridged_type/shared_enum.rs +++ b/crates/swift-bridge-ir/src/bridged_type/shared_enum.rs @@ -9,12 +9,18 @@ pub(crate) use self::enum_variant::EnumVariant; use super::StructFields; +#[derive(Default, Clone)] +pub(crate) struct DeriveAttrs { + pub debug: bool, +} + #[derive(Clone)] pub(crate) struct SharedEnum { pub name: Ident, pub variants: Vec, pub already_declared: bool, pub swift_name: Option, + pub derive: DeriveAttrs, } impl SharedEnum { diff --git a/crates/swift-bridge-ir/src/codegen/codegen_tests.rs b/crates/swift-bridge-ir/src/codegen/codegen_tests.rs index 4ef66cd9..bf9671b5 100644 --- a/crates/swift-bridge-ir/src/codegen/codegen_tests.rs +++ b/crates/swift-bridge-ir/src/codegen/codegen_tests.rs @@ -33,6 +33,7 @@ mod async_function_codegen_tests; mod boxed_fnonce_codegen_tests; mod built_in_tuple_codegen_tests; mod conditional_compilation_codegen_tests; +mod derive_attribute_codegen_tests; mod derive_struct_attribute_codegen_tests; mod extern_rust_function_opaque_rust_type_argument_codegen_tests; mod extern_rust_function_opaque_rust_type_return_codegen_tests; diff --git a/crates/swift-bridge-ir/src/codegen/codegen_tests/derive_attribute_codegen_tests.rs b/crates/swift-bridge-ir/src/codegen/codegen_tests/derive_attribute_codegen_tests.rs new file mode 100644 index 00000000..f5b563b1 --- /dev/null +++ b/crates/swift-bridge-ir/src/codegen/codegen_tests/derive_attribute_codegen_tests.rs @@ -0,0 +1,68 @@ +use super::{CodegenTest, ExpectedCHeader, ExpectedRustTokens, ExpectedSwiftCode}; +use proc_macro2::TokenStream; +use quote::quote; + +/// Verify that we generate debugDescription in Swift and Debug function in Rust when using #\[derive(Debug)] +mod derive_debug_enum { + use super::*; + + fn bridge_module_tokens() -> TokenStream { + quote! { + #[swift_bridge::bridge] + mod ffi { + #[derive(Debug)] + enum SomeEnum { + Variant1 + } + } + } + } + + fn expected_rust_tokens() -> ExpectedRustTokens { + ExpectedRustTokens::ContainsMany(vec![ + quote! { + #[derive(Copy, Clone, ::std::fmt::Debug)] + pub enum SomeEnum { + Variant1 + } + }, + quote! { + #[export_name = "__swift_bridge__$SomeEnum$Debug"] + pub extern "C" fn __swift_bridge__SomeEnum_Debug(this: __swift_bridge__SomeEnum) -> *mut swift_bridge::string::RustString { + swift_bridge::string::RustString(format!("{:?}", this.into_rust_repr())).box_into_raw() + } + }, + ]) + } + + fn expected_swift_code() -> ExpectedSwiftCode { + ExpectedSwiftCode::ContainsAfterTrim( + r#" +extension SomeEnum: CustomDebugStringConvertible { + public var debugDescription: String { + RustString(ptr: __swift_bridge__$SomeEnum$Debug(self.intoFfiRepr())).toString() + } +} +"#, + ) + } + + fn expected_c_header() -> ExpectedCHeader { + ExpectedCHeader::ContainsAfterTrim( + r#" +void* __swift_bridge__$SomeEnum$Debug(__swift_bridge__$SomeEnum this); +"#, + ) + } + + #[test] + fn generates_enum_to_and_from_ffi_conversions_no_data() { + 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(); + } +} 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 30ba0db9..05871eec 100644 --- a/crates/swift-bridge-ir/src/codegen/generate_c_header.rs +++ b/crates/swift-bridge-ir/src/codegen/generate_c_header.rs @@ -152,6 +152,12 @@ typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi variants += &variant; } + let derive_debug_impl = if ty_enum.derive.debug { + format!("void* {ffi_name}$Debug({ffi_name} this);") + } else { + "".to_string() + }; + let maybe_vec_support = if ty_enum.has_one_or_more_variants_with_data() { "".to_string() } else { @@ -162,7 +168,8 @@ typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi let enum_decl = format!( r#"typedef enum {ffi_tag_name} {{ {variants}}} {ffi_tag_name}; typedef struct {ffi_name} {{ {ffi_tag_name} tag; }} {ffi_name}; -typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi_name};{maybe_vec_support}"#, +typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi_name}; +{derive_debug_impl}{maybe_vec_support}"#, ffi_name = ffi_name, ffi_tag_name = ffi_tag_name, option_ffi_name = option_ffi_name, @@ -223,7 +230,8 @@ typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi r#"{variant_fields}union {ffi_union_name} {union_fields}; typedef enum {ffi_tag_name} {{ {variants}}} {ffi_tag_name}; typedef struct {ffi_name} {{ {ffi_tag_name} tag; union {ffi_union_name} payload;}} {ffi_name}; -typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi_name};{maybe_vec_support}"#, +typedef struct {option_ffi_name} {{ bool is_some; {ffi_name} val; }} {option_ffi_name}; +{derive_debug_impl}{maybe_vec_support}"#, union_fields = ffi_union_field_names, variant_fields = variant_fields, ffi_name = ffi_name, 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 f22a1ae4..398ec57a 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 @@ -130,14 +130,34 @@ impl SwiftBridgeModule { convert_ffi_variants_to_rust.push(convert_ffi_variant_to_rust); } - // TODO: - // Parse any derives that the user has specified and combine those with our auto derives. - let automatic_derives = if shared_enum.has_one_or_more_variants_with_data() { + // Auto derives + let mut derives = if shared_enum.has_one_or_more_variants_with_data() { vec![] } else { vec![quote! {Copy}, quote! {Clone}] }; + // User derives + let mut derive_impl_ffi_bridges = vec![]; + + // We currently only allow derive(Debug) on non data carrying enums in order + // to prevent a potential memory safety issue. + // https://github.com/chinedufn/swift-bridge/pull/194#discussion_r1134386788 + if shared_enum.derive.debug && !shared_enum.has_one_or_more_variants_with_data() { + derives.push(quote! {::std::fmt::Debug}); + + // __swift_bridge__$SomeEnum$Debug + let export_name = format!("{}$Debug", shared_enum.ffi_name_string()); + // __swift_bridge__SomeEnum_Debug + let fn_name = format_ident!("{}_Debug", enum_ffi_name); + derive_impl_ffi_bridges.push(quote! { + #[export_name = #export_name] + pub extern "C" fn #fn_name(this: #enum_ffi_name) -> *mut swift_bridge::string::RustString { + swift_bridge::string::RustString(format!("{:?}", this.into_rust_repr())).box_into_raw() + } + }); + } + let vec_support = if shared_enum.has_one_or_more_variants_with_data() { // Enums with variants that contain data are not yet supported. quote! {} @@ -146,7 +166,7 @@ impl SwiftBridgeModule { }; let definition = quote! { - #[derive(#(#automatic_derives),*)] + #[derive(#(#derives),*)] pub enum #enum_name { #(#enum_variants),* } @@ -217,6 +237,8 @@ impl SwiftBridgeModule { } #vec_support + + #(#derive_impl_ffi_bridges),* }; Some(definition) diff --git a/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/vec/vec_of_transparent_enum.rs b/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/vec/vec_of_transparent_enum.rs index 6b567dc7..a936916e 100644 --- a/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/vec/vec_of_transparent_enum.rs +++ b/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/vec/vec_of_transparent_enum.rs @@ -96,7 +96,7 @@ pub(in super::super) fn generate_vec_of_transparent_enum_functions( #[cfg(test)] mod tests { use super::*; - use crate::test_utils::assert_tokens_eq; + use crate::{bridged_type::DeriveAttrs, test_utils::assert_tokens_eq}; use proc_macro2::{Ident, Span}; /// Verify that we can generate the functions for an opaque Rust type that get exposed to Swift @@ -168,6 +168,7 @@ mod tests { variants: vec![], already_declared: false, swift_name: None, + derive: DeriveAttrs::default(), }; assert_tokens_eq( &generate_vec_of_transparent_enum_functions(&shared_enum), 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 b726d281..31da252b 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 @@ -130,6 +130,19 @@ extension {enum_name}: Vectorizable {{ ) }; + let derive_debug_impl = if shared_enum.derive.debug { + format!( + r#" +extension {enum_name}: CustomDebugStringConvertible {{ + public var debugDescription: String {{ + RustString(ptr: __swift_bridge__${enum_name}$Debug(self.intoFfiRepr())).toString() + }} +}}"# + ) + } else { + "".to_string() + }; + let swift_enum = format!( r#"public enum {enum_name} {{{variants}}} extension {enum_name} {{ @@ -159,7 +172,7 @@ extension {option_ffi_name} {{ return {option_ffi_name}(is_some: false, val: {ffi_repr_name}()) }} }} -}}{vectorizable_impl}"#, +}}{vectorizable_impl}{derive_debug_impl}"#, enum_name = enum_name, enum_ffi_name = enum_ffi_name, option_ffi_name = option_ffi_name, diff --git a/crates/swift-bridge-ir/src/errors.rs b/crates/swift-bridge-ir/src/errors.rs index e7bcf92c..7d73724a 100644 --- a/crates/swift-bridge-ir/src/errors.rs +++ b/crates/swift-bridge-ir/src/errors.rs @@ -14,6 +14,12 @@ impl ParseErrors { self.errors.push(error); } + pub fn append(&mut self, errors: Vec) { + for error in errors { + self.push(error); + } + } + pub fn combine_all(mut self) -> Result<(), syn::Error> { if self.errors.len() == 0 { return Ok(()); diff --git a/crates/swift-bridge-ir/src/parse/parse_enum.rs b/crates/swift-bridge-ir/src/parse/parse_enum.rs index 83a3c1bb..7f275a89 100644 --- a/crates/swift-bridge-ir/src/parse/parse_enum.rs +++ b/crates/swift-bridge-ir/src/parse/parse_enum.rs @@ -1,95 +1,24 @@ use crate::bridged_type::{EnumVariant, SharedEnum, StructFields}; -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, LitStr, Token}; +use crate::errors::ParseErrors; +use syn::ItemEnum; -pub(crate) struct SharedEnumDeclarationParser<'a> { - pub item_enum: ItemEnum, - // Will be used in a future commit.. - #[allow(unused)] - pub errors: &'a mut ParseErrors, -} - -enum EnumAttr { - AlreadyDeclared, - Error(EnumAttrParseError), - SwiftName(LitStr), -} - -enum EnumAttrParseError { - UnrecognizedAttribute(Ident), -} - -#[derive(Default)] -struct EnumAttribs { - already_declared: bool, - swift_name: Option, -} - -struct ParsedAttribs(Vec); -impl Parse for ParsedAttribs { - fn parse(input: ParseStream) -> syn::Result { - if input.is_empty() { - return Ok(ParsedAttribs(vec![])); - } +use self::enum_attributes::SharedEnumAllAttributes; - let opts = syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated(input)?; +mod enum_attributes; - 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, - "swift_name" => { - input.parse::()?; - - let name = input.parse()?; - EnumAttr::SwiftName(name) - } - _ => { - move_input_cursor_to_next_comma(input); - EnumAttr::Error(EnumAttrParseError::UnrecognizedAttribute(key)) - } - }; - - Ok(attr) - } +pub(crate) struct SharedEnumDeclarationParser<'a> { + pub errors: &'a mut ParseErrors, + pub item_enum: ItemEnum, } impl<'a> SharedEnumDeclarationParser<'a> { pub fn parse(self) -> Result { let item_enum = self.item_enum; - let mut variants = vec![]; + let attribs = SharedEnumAllAttributes::from_attributes(&item_enum.attrs)?; + self.errors.append(attribs.errors); - 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 }); - } - }, - EnumAttr::SwiftName(name) => { - attribs.swift_name = Some(name); - } - } - } - } + let mut variants = vec![]; for v in item_enum.variants { let variant = EnumVariant { @@ -102,8 +31,9 @@ impl<'a> SharedEnumDeclarationParser<'a> { let shared_enum = SharedEnum { name: item_enum.ident, variants, - already_declared: attribs.already_declared, - swift_name: attribs.swift_name, + already_declared: attribs.swift_bridge.already_declared, + swift_name: attribs.swift_bridge.swift_name, + derive: attribs.derive, }; Ok(shared_enum) @@ -253,4 +183,23 @@ mod tests { _ => panic!(), }; } + + /// Verify that we can parse #[derive(Debug)] on enums + #[test] + fn derive_debug() { + let tokens = quote! { + #[swift_bridge::bridge] + mod ffi { + #[derive(Debug)] + enum Foo { + Variant1 + } + } + }; + + let module = parse_ok(tokens); + + let ty = module.types.types()[0].unwrap_shared_enum(); + assert!(ty.derive.debug); + } } diff --git a/crates/swift-bridge-ir/src/parse/parse_enum/enum_attributes.rs b/crates/swift-bridge-ir/src/parse/parse_enum/enum_attributes.rs new file mode 100644 index 00000000..db13d55a --- /dev/null +++ b/crates/swift-bridge-ir/src/parse/parse_enum/enum_attributes.rs @@ -0,0 +1,108 @@ +use crate::bridged_type::DeriveAttrs; +use crate::errors::ParseError; +use crate::parse::move_input_cursor_to_next_comma; +use proc_macro2::Ident; +use quote::ToTokens; +use syn::parse::{Parse, ParseStream}; +use syn::{Attribute, LitStr, Path, Token}; + +#[derive(Default)] +pub(super) struct SharedEnumAllAttributes { + pub errors: Vec, + pub swift_bridge: SharedEnumSwiftBridgeAttributes, + pub derive: DeriveAttrs, +} + +impl SharedEnumAllAttributes { + pub(super) fn from_attributes(attribs: &[Attribute]) -> Result { + let mut attributes = SharedEnumAllAttributes::default(); + + for attr in attribs { + let attribute_name = attr.path.to_token_stream().to_string(); + + match attribute_name.as_str() { + "derive" => { + let parser = + syn::punctuated::Punctuated::::parse_terminated; + let args = attr.parse_args_with(parser)?; + for arg in args.into_iter() { + match arg.get_ident().unwrap().to_string().as_str() { + "Debug" => attributes.derive.debug = true, + _ => todo!("Unsupported derive macro; please see https://github.com/chinedufn/swift-bridge/issues/190#issuecomment-1463234027"), + } + } + } + "swift_bridge" => { + attributes.swift_bridge = attr.parse_args()?; + attributes + .errors + .append(&mut attributes.swift_bridge.errors); + } + _ => todo!("Push unsupported attribute error."), + }; + } + + Ok(attributes) + } +} + +pub(super) enum EnumAttr { + AlreadyDeclared, + Error(ParseError), + SwiftName(LitStr), +} + +#[derive(Default)] +pub(super) struct SharedEnumSwiftBridgeAttributes { + pub errors: Vec, + pub already_declared: bool, + pub swift_name: Option, +} + +impl SharedEnumSwiftBridgeAttributes { + pub(super) fn store_attrib(&mut self, attrib: EnumAttr) -> syn::Result<()> { + match attrib { + EnumAttr::AlreadyDeclared => self.already_declared = true, + EnumAttr::Error(error) => self.errors.push(error), + EnumAttr::SwiftName(name) => self.swift_name = Some(name), + }; + Ok(()) + } +} + +impl Parse for SharedEnumSwiftBridgeAttributes { + fn parse(input: ParseStream) -> syn::Result { + let mut attributes = SharedEnumSwiftBridgeAttributes::default(); + + let punctuated = + syn::punctuated::Punctuated::::parse_terminated(input)?; + + for attr in punctuated.into_iter() { + attributes.store_attrib(attr)?; + } + + Ok(attributes) + } +} + +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, + "swift_name" => { + input.parse::()?; + + let name = input.parse()?; + EnumAttr::SwiftName(name) + } + _ => { + move_input_cursor_to_next_comma(input); + EnumAttr::Error(ParseError::EnumUnrecognizedAttribute { attribute: key }) + } + }; + + Ok(attr) + } +} diff --git a/crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.rs b/crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.rs new file mode 100644 index 00000000..5b6dd604 --- /dev/null +++ b/crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.rs @@ -0,0 +1,11 @@ +//! # To Run +//! cargo test -p swift-bridge-macro -- ui trybuild=unrecognized-enum-attribute.rs +// TODO: combine all unrecognized attribute tests + +#[swift_bridge::bridge] +mod ffi { + #[swift_bridge(InvalidAttribute)] + enum SomeEnum {} +} + +fn main() {} diff --git a/crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.stderr b/crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.stderr new file mode 100644 index 00000000..5a16893b --- /dev/null +++ b/crates/swift-bridge-macro/tests/ui/unrecognized-enum-attribute.stderr @@ -0,0 +1,5 @@ +error: Did not recognize enum attribute "InvalidAttribute". + --> tests/ui/unrecognized-enum-attribute.rs:7:20 + | +7 | #[swift_bridge(InvalidAttribute)] + | ^^^^^^^^^^^^^^^^ diff --git a/crates/swift-integration-tests/src/enum_attributes.rs b/crates/swift-integration-tests/src/enum_attributes.rs index 6fc2cf4d..eb0571b4 100644 --- a/crates/swift-integration-tests/src/enum_attributes.rs +++ b/crates/swift-integration-tests/src/enum_attributes.rs @@ -1,2 +1,3 @@ mod already_declared; +mod derive; mod swift_name; diff --git a/crates/swift-integration-tests/src/enum_attributes/derive.rs b/crates/swift-integration-tests/src/enum_attributes/derive.rs new file mode 100644 index 00000000..902480ef --- /dev/null +++ b/crates/swift-integration-tests/src/enum_attributes/derive.rs @@ -0,0 +1,7 @@ +#[swift_bridge::bridge] +mod ffi { + #[derive(Debug)] + enum DeriveDebugEnum { + Variant, + } +} diff --git a/test-swift-rust-integration.sh b/test-swift-rust-integration.sh index c9ef8704..bc6d7946 100755 --- a/test-swift-rust-integration.sh +++ b/test-swift-rust-integration.sh @@ -9,7 +9,7 @@ export RUSTFLAGS="-D warnings" # Change to the root directory of the Xcode project THIS_DIR=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) ROOT_DIR="$THIS_DIR" -cd $ROOT_DIR +cd "$ROOT_DIR" cd SwiftRustIntegrationTestRunner # If project files don't exist before Xcode begins building we get something like: