11use proc_macro2:: Span ;
22use quote:: { quote, ToTokens } ;
3- use std:: collections:: HashMap ;
43use 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 ,
106} ;
11-
7+ use itertools:: Itertools ;
8+ use crate :: HashMap ;
129use crate :: HashSet ;
1310
1411pub 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) ;
1714}
1815
19- struct Visitor ;
16+ struct Visitor {
17+ synthetic_mods : HashMap < Ident , ( AttributeSet , Vec < Item > ) > ,
18+ new_items : Vec < Item > ,
19+ }
2020
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+ }
24122 }
25123}
26124
@@ -30,7 +128,6 @@ struct AttributeSet {
30128 cc_attrs : HashSet < Attribute > ,
31129 other_attrs : HashSet < Attribute > ,
32130}
33- use itertools:: Itertools ;
34131
35132impl AttributeSet {
36133 fn ident ( & self ) -> Ident {
@@ -64,113 +161,6 @@ impl AttributeSet {
64161 }
65162}
66163
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-
174164fn partition_attributes ( attrs : & [ Attribute ] ) -> AttributeSet {
175165 let mut attribute_set = AttributeSet :: default ( ) ;
176166
0 commit comments