1
- use crate :: bridged_type:: { SharedStruct , StructFields , StructSwiftRepr } ;
1
+ use crate :: bridged_type:: {
2
+ shared_struct:: StructDerives , SharedStruct , StructFields , StructSwiftRepr ,
3
+ } ;
2
4
use crate :: errors:: { ParseError , ParseErrors } ;
3
5
use crate :: parse:: move_input_cursor_to_next_comma;
4
6
use proc_macro2:: Ident ;
7
+ use quote:: ToTokens ;
5
8
use syn:: parse:: { Parse , ParseStream } ;
6
- use syn:: { ItemStruct , LitStr , Token } ;
9
+ use syn:: { ItemStruct , LitStr , Meta , Token } ;
7
10
8
11
pub ( crate ) struct SharedStructDeclarationParser < ' a > {
9
12
pub item_struct : ItemStruct ,
@@ -27,6 +30,16 @@ struct StructAttribs {
27
30
swift_repr : Option < ( StructSwiftRepr , LitStr ) > ,
28
31
swift_name : Option < LitStr > ,
29
32
already_declared : bool ,
33
+ derives : StructDerives ,
34
+ }
35
+
36
+ impl Default for StructDerives {
37
+ fn default ( ) -> Self {
38
+ StructDerives {
39
+ copy : false ,
40
+ clone : false ,
41
+ }
42
+ }
30
43
}
31
44
32
45
struct ParsedAttribs ( Vec < StructAttr > ) ;
@@ -81,32 +94,52 @@ impl<'a> SharedStructDeclarationParser<'a> {
81
94
let mut attribs = StructAttribs :: default ( ) ;
82
95
83
96
for attr in item_struct. attrs {
84
- let sections: ParsedAttribs = attr. parse_args ( ) ?;
85
-
86
- for attr in sections. 0 {
87
- match attr {
88
- StructAttr :: SwiftRepr ( ( repr, lit_str) ) => {
89
- attribs. swift_repr = Some ( ( repr, lit_str) ) ;
90
- }
91
- StructAttr :: SwiftName ( name) => {
92
- attribs. swift_name = Some ( name) ;
97
+ let attribute_name = attr. path . to_token_stream ( ) . to_string ( ) ;
98
+
99
+ match attribute_name. as_str ( ) {
100
+ "swift_bridge" => {
101
+ let sections: ParsedAttribs = attr. parse_args ( ) ?;
102
+
103
+ for attr in sections. 0 {
104
+ match attr {
105
+ StructAttr :: SwiftRepr ( ( repr, lit_str) ) => {
106
+ attribs. swift_repr = Some ( ( repr, lit_str) ) ;
107
+ }
108
+ StructAttr :: SwiftName ( name) => {
109
+ attribs. swift_name = Some ( name) ;
110
+ }
111
+ StructAttr :: Error ( err) => match err {
112
+ StructAttrParseError :: InvalidSwiftRepr ( val) => {
113
+ self . errors . push ( ParseError :: StructInvalidSwiftRepr {
114
+ swift_repr_attr_value : val. clone ( ) ,
115
+ } ) ;
116
+ attribs. swift_repr = Some ( ( StructSwiftRepr :: Structure , val) ) ;
117
+ }
118
+ StructAttrParseError :: UnrecognizedAttribute ( attribute) => {
119
+ self . errors . push ( ParseError :: StructUnrecognizedAttribute {
120
+ attribute,
121
+ } ) ;
122
+ }
123
+ } ,
124
+ StructAttr :: AlreadyDeclared => {
125
+ attribs. already_declared = true ;
126
+ }
127
+ } ;
93
128
}
94
- StructAttr :: Error ( err) => match err {
95
- StructAttrParseError :: InvalidSwiftRepr ( val) => {
96
- self . errors . push ( ParseError :: StructInvalidSwiftRepr {
97
- swift_repr_attr_value : val. clone ( ) ,
98
- } ) ;
99
- attribs. swift_repr = Some ( ( StructSwiftRepr :: Structure , val) ) ;
100
- }
101
- StructAttrParseError :: UnrecognizedAttribute ( attribute) => {
102
- self . errors
103
- . push ( ParseError :: StructUnrecognizedAttribute { attribute } ) ;
129
+ }
130
+ "derive" => match attr. parse_meta ( ) ? {
131
+ Meta :: List ( meta_list) => {
132
+ for derive in meta_list. nested {
133
+ match derive. to_token_stream ( ) . to_string ( ) . as_str ( ) {
134
+ "Copy" => attribs. derives . copy = true ,
135
+ "Clone" => attribs. derives . clone = true ,
136
+ _ => { }
137
+ }
104
138
}
105
- } ,
106
- StructAttr :: AlreadyDeclared => {
107
- attribs. already_declared = true ;
108
139
}
109
- } ;
140
+ _ => todo ! ( "Push parse error that derive attribute is in incorrect format" ) ,
141
+ } ,
142
+ _ => todo ! ( "Push unsupported attribute error." ) ,
110
143
}
111
144
}
112
145
@@ -137,6 +170,7 @@ impl<'a> SharedStructDeclarationParser<'a> {
137
170
fields : StructFields :: from_syn_fields ( item_struct. fields ) ,
138
171
swift_name : attribs. swift_name ,
139
172
already_declared : attribs. already_declared ,
173
+ derives : attribs. derives ,
140
174
} ;
141
175
142
176
Ok ( shared_struct)
@@ -302,6 +336,33 @@ mod tests {
302
336
assert_eq ! ( ty. swift_name. as_ref( ) . unwrap( ) . value( ) , "FfiFoo" ) ;
303
337
}
304
338
339
+ /// Verify that we parse the derive(...)
340
+ #[ test]
341
+ fn parse_derive_attribute ( ) {
342
+ let tokens = quote ! {
343
+ #[ swift_bridge:: bridge]
344
+ mod ffi {
345
+ #[ derive( Copy , Clone ) ]
346
+ struct Foo ;
347
+
348
+ #[ derive( Clone ) ]
349
+ struct Bar ;
350
+ }
351
+ } ;
352
+
353
+ let module = parse_ok ( tokens) ;
354
+
355
+ let ty = module. types . types ( ) [ 0 ] . unwrap_shared_struct ( ) ;
356
+
357
+ assert_eq ! ( ty. derives. copy, true ) ;
358
+ assert_eq ! ( ty. derives. clone, true ) ;
359
+
360
+ let ty2 = module. types . types ( ) [ 1 ] . unwrap_shared_struct ( ) ;
361
+
362
+ assert_eq ! ( ty2. derives. copy, false ) ;
363
+ assert_eq ! ( ty2. derives. clone, true ) ;
364
+ }
365
+
305
366
/// Verify that we properly parse multiple comma separated struct attributes.
306
367
#[ test]
307
368
fn parses_multiple_struct_attributes ( ) {
@@ -322,6 +383,29 @@ mod tests {
322
383
assert_eq ! ( ty. swift_repr, StructSwiftRepr :: Class ) ;
323
384
}
324
385
386
+ /// Verify that we properly parse multiple comma separated struct attributes and derive attributes.
387
+ #[ test]
388
+ fn parses_multiple_struct_attributes_and_derive ( ) {
389
+ let tokens = quote ! {
390
+ #[ swift_bridge:: bridge]
391
+ mod ffi {
392
+ #[ swift_bridge( swift_name = "FfiFoo" , swift_repr = "class" ) ]
393
+ #[ derive( Copy , Clone ) ]
394
+ struct Foo {
395
+ fied: u8
396
+ }
397
+ }
398
+ } ;
399
+
400
+ let module = parse_ok ( tokens) ;
401
+
402
+ let ty = module. types . types ( ) [ 0 ] . unwrap_shared_struct ( ) ;
403
+ assert_eq ! ( ty. swift_name. as_ref( ) . unwrap( ) . value( ) , "FfiFoo" ) ;
404
+ assert_eq ! ( ty. swift_repr, StructSwiftRepr :: Class ) ;
405
+ assert_eq ! ( ty. derives. copy, true ) ;
406
+ assert_eq ! ( ty. derives. clone, true ) ;
407
+ }
408
+
325
409
/// Verify that we can parse an `already_defined = "struct"` attribute.
326
410
#[ test]
327
411
fn parses_struct_already_declared_attribute ( ) {
0 commit comments