1
1
use proc_macro2:: Span ;
2
2
use quote:: { quote, ToTokens } ;
3
- use std:: collections:: HashMap ;
4
3
use syn:: {
5
- parse_quote,
6
- visit_mut:: { visit_file_mut, VisitMut } ,
7
- Attribute , File , ForeignItem , Ident , Item , ItemConst , ItemEnum , ItemFn ,
8
- ItemForeignMod , ItemImpl , ItemMod , ItemStatic , ItemStruct , ItemType ,
9
- ItemUnion , ItemUse ,
4
+ Attribute , File , ForeignItem , Ident , Item , ItemConst , ItemEnum , ItemFn , ItemForeignMod ,
5
+ ItemImpl , ItemMod , ItemStatic , ItemStruct , ItemType , ItemUnion , ItemUse ,
10
6
} ;
11
-
7
+ use itertools:: Itertools ;
8
+ use crate :: HashMap ;
12
9
use crate :: HashSet ;
13
10
14
11
pub fn merge_cfg_attributes ( file : & mut File ) {
15
- let mut visitor = Visitor ;
16
- visitor. visit_file_mut ( file) ;
12
+ let mut visitor = Visitor :: new ( ) ;
13
+ visitor. visit_file ( file) ;
17
14
}
18
15
19
- struct Visitor ;
16
+ struct Visitor {
17
+ synthetic_mods : HashMap < Ident , ( AttributeSet , Vec < Item > ) > ,
18
+ new_items : Vec < Item > ,
19
+ }
20
20
21
- impl VisitMut for Visitor {
22
- fn visit_file_mut ( & mut self , file : & mut File ) {
23
- process_items ( & mut file. items ) ;
21
+ impl Visitor {
22
+ fn new ( ) -> Self {
23
+ Self {
24
+ synthetic_mods : HashMap :: default ( ) ,
25
+ new_items : Vec :: new ( ) ,
26
+ }
27
+ }
28
+
29
+ fn visit_file ( & mut self , file : & mut File ) {
30
+ self . visit_items ( & mut file. items ) ;
31
+
32
+ for ( ident, ( attr_set, items) ) in self . synthetic_mods . drain ( ) {
33
+ let cfg_attrs: Vec < _ > = attr_set. cfg_attrs . iter ( ) . collect ( ) ;
34
+ let cc_attrs: Vec < _ > = attr_set. cc_attrs . iter ( ) . collect ( ) ;
35
+ let block = if cc_attrs. is_empty ( ) {
36
+ quote ! {
37
+ #( #items) *
38
+ }
39
+ } else {
40
+ quote ! {
41
+ #( #cc_attrs) *
42
+ unsafe extern "C" {
43
+ #( #items) *
44
+ }
45
+ }
46
+ } ;
47
+
48
+ self . new_items . push ( Item :: Verbatim ( quote ! {
49
+ #( #cfg_attrs) *
50
+ pub mod #ident {
51
+ #block
52
+ }
53
+
54
+ #( #cfg_attrs) *
55
+ pub use #ident:: * ;
56
+ } ) ) ;
57
+ }
58
+
59
+ file. items = std:: mem:: take ( & mut self . new_items ) ;
60
+ }
61
+
62
+ fn visit_items ( & mut self , items : & mut Vec < Item > ) {
63
+ for mut item in std:: mem:: take ( items) {
64
+ match & mut item {
65
+ Item :: Const ( ItemConst { ref mut attrs, .. } )
66
+ | Item :: Struct ( ItemStruct { ref mut attrs, .. } )
67
+ | Item :: Enum ( ItemEnum { ref mut attrs, .. } )
68
+ | Item :: Fn ( ItemFn { ref mut attrs, .. } )
69
+ | Item :: Union ( ItemUnion { ref mut attrs, .. } )
70
+ | Item :: Type ( ItemType { ref mut attrs, .. } )
71
+ | Item :: Impl ( ItemImpl { ref mut attrs, .. } )
72
+ | Item :: Mod ( ItemMod { ref mut attrs, .. } )
73
+ | Item :: Use ( ItemUse { ref mut attrs, .. } )
74
+ | Item :: Static ( ItemStatic { ref mut attrs, .. } ) => {
75
+ let attr_set = partition_attributes ( attrs) ;
76
+ * attrs = attr_set. other_attrs . iter ( ) . cloned ( ) . collect ( ) ;
77
+ self . insert_item_into_mod ( attr_set, item) ;
78
+ }
79
+ Item :: ForeignMod ( foreign_mod) => {
80
+ self . visit_foreign_mod ( foreign_mod) ;
81
+ }
82
+ _ => {
83
+ self . new_items . push ( item) ;
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ fn visit_foreign_mod ( & mut self , foreign_mod : & mut ItemForeignMod ) {
90
+ for mut foreign_item in std:: mem:: take ( & mut foreign_mod. items ) {
91
+ let mut attr_set = partition_attributes ( & foreign_mod. attrs ) ;
92
+ let inner_attrs = match & mut foreign_item {
93
+ ForeignItem :: Fn ( f) => & mut f. attrs ,
94
+ ForeignItem :: Static ( s) => & mut s. attrs ,
95
+ ForeignItem :: Type ( t) => & mut t. attrs ,
96
+ ForeignItem :: Macro ( m) => & mut m. attrs ,
97
+ _ => & mut Vec :: new ( ) ,
98
+ } ;
99
+
100
+ let inner_attr_set = partition_attributes ( inner_attrs) ;
101
+ attr_set. other_attrs . extend ( inner_attr_set. other_attrs ) ;
102
+ attr_set. cfg_attrs . extend ( inner_attr_set. cfg_attrs ) ;
103
+ attr_set. cc_attrs . extend ( inner_attr_set. cc_attrs ) ;
104
+ * inner_attrs = attr_set. other_attrs . iter ( ) . cloned ( ) . collect ( ) ;
105
+
106
+ self . insert_item_into_mod (
107
+ attr_set,
108
+ Item :: Verbatim ( quote ! { #foreign_item } ) ,
109
+ ) ;
110
+ }
111
+ }
112
+
113
+ fn insert_item_into_mod ( & mut self , attr_set : AttributeSet , item : Item ) {
114
+ if !attr_set. cfg_attrs . is_empty ( ) || !attr_set. cc_attrs . is_empty ( ) {
115
+ let ( _, items) = self . synthetic_mods
116
+ . entry ( attr_set. ident ( ) )
117
+ . or_insert_with ( || ( attr_set, Vec :: new ( ) ) ) ;
118
+ items. push ( item) ;
119
+ } else {
120
+ self . new_items . push ( item) ;
121
+ }
24
122
}
25
123
}
26
124
@@ -30,7 +128,6 @@ struct AttributeSet {
30
128
cc_attrs : HashSet < Attribute > ,
31
129
other_attrs : HashSet < Attribute > ,
32
130
}
33
- use itertools:: Itertools ;
34
131
35
132
impl AttributeSet {
36
133
fn ident ( & self ) -> Ident {
@@ -64,113 +161,6 @@ impl AttributeSet {
64
161
}
65
162
}
66
163
67
- fn process_items ( items : & mut Vec < Item > ) {
68
- let mut synthetic_mods: HashMap < Ident , ( AttributeSet , Vec < Item > ) > =
69
- HashMap :: new ( ) ;
70
- let mut new_items = Vec :: new ( ) ;
71
-
72
- for mut item in std:: mem:: take ( items) {
73
- match & mut item {
74
- Item :: Const ( ItemConst { ref mut attrs, .. } ) |
75
- Item :: Struct ( ItemStruct { ref mut attrs, .. } ) |
76
- Item :: Enum ( ItemEnum { ref mut attrs, .. } ) |
77
- Item :: Fn ( ItemFn { ref mut attrs, .. } ) |
78
- Item :: Union ( ItemUnion { ref mut attrs, .. } ) |
79
- Item :: Type ( ItemType { ref mut attrs, .. } ) |
80
- Item :: Impl ( ItemImpl { ref mut attrs, .. } ) |
81
- Item :: Mod ( ItemMod { ref mut attrs, .. } ) |
82
- Item :: Use ( ItemUse { ref mut attrs, .. } ) |
83
- Item :: Static ( ItemStatic { ref mut attrs, .. } ) => {
84
- let attr_set = partition_attributes ( attrs) ;
85
- * attrs = attr_set. other_attrs . iter ( ) . cloned ( ) . collect ( ) ;
86
-
87
- let items = if !attr_set. cfg_attrs . is_empty ( ) || !attr_set. cc_attrs . is_empty ( ) {
88
- & mut synthetic_mods
89
- . entry ( attr_set. ident ( ) )
90
- . or_insert_with ( || ( attr_set, vec ! [ ] ) )
91
- . 1
92
- } else {
93
- & mut new_items
94
- } ;
95
- items. push ( item) ;
96
- }
97
-
98
- Item :: ForeignMod ( ItemForeignMod {
99
- ref mut attrs,
100
- ref mut items,
101
- ..
102
- } ) => {
103
- for foreign_item in items. iter_mut ( ) {
104
- let mut attr_set = partition_attributes ( & attrs) ;
105
- let inner_attrs = match foreign_item {
106
- ForeignItem :: Fn ( ref mut foreign_fn) => {
107
- & mut foreign_fn. attrs
108
- }
109
- ForeignItem :: Static ( ref mut foreign_static) => {
110
- & mut foreign_static. attrs
111
- }
112
- _ => & mut vec ! [ ] ,
113
- } ;
114
-
115
- let inner_attr_set = partition_attributes ( inner_attrs) ;
116
- attr_set
117
- . other_attrs
118
- . extend ( inner_attr_set. other_attrs . clone ( ) ) ;
119
- attr_set. cfg_attrs . extend ( inner_attr_set. cfg_attrs ) ;
120
- attr_set. cc_attrs . extend ( inner_attr_set. cc_attrs ) ;
121
- * inner_attrs =
122
- inner_attr_set. other_attrs . into_iter ( ) . collect ( ) ;
123
-
124
- let items = if !attr_set. cfg_attrs . is_empty ( ) || !attr_set. cc_attrs . is_empty ( ) {
125
- & mut synthetic_mods
126
- . entry ( attr_set. ident ( ) )
127
- . or_insert_with ( || ( attr_set, vec ! [ ] ) )
128
- . 1
129
- } else {
130
- & mut new_items
131
- } ;
132
- items. push ( Item :: Verbatim ( quote ! {
133
- #foreign_item
134
- } ) ) ;
135
- }
136
- }
137
- _ => {
138
- new_items. push ( item) ;
139
- }
140
- }
141
- }
142
-
143
- for ( ident, ( attr_set, items) ) in synthetic_mods {
144
- let cfg_attrs: Vec < _ > = attr_set. cfg_attrs . iter ( ) . collect ( ) ;
145
- let cc_attrs: Vec < _ > = attr_set. cc_attrs . iter ( ) . collect ( ) ;
146
- let block = if cc_attrs. is_empty ( ) {
147
- quote ! {
148
- #( #items) *
149
- }
150
- } else {
151
- // TODO: include unsafe and abi from original items
152
- quote ! {
153
- #( #cc_attrs) *
154
- unsafe extern "C" {
155
- #( #items) *
156
- }
157
- }
158
- } ;
159
-
160
- new_items. push ( Item :: Verbatim ( quote ! {
161
- #( #cfg_attrs) *
162
- pub mod #ident {
163
- #block
164
- }
165
-
166
- #( #cfg_attrs) *
167
- pub use #ident:: * ;
168
- } ) ) ;
169
- }
170
-
171
- items. extend ( new_items) ;
172
- }
173
-
174
164
fn partition_attributes ( attrs : & [ Attribute ] ) -> AttributeSet {
175
165
let mut attribute_set = AttributeSet :: default ( ) ;
176
166
0 commit comments