@@ -81,6 +81,52 @@ impl fmt::Display for Cfg {
8181 }
8282}
8383
84+ impl syn:: parse:: Parse for Cfg {
85+ fn parse ( input : syn:: parse:: ParseStream ) -> syn:: Result < Self > {
86+ let arg: syn:: Meta = input. parse ( ) ?;
87+
88+ match arg {
89+ syn:: Meta :: Path ( path) => path
90+ . get_ident ( )
91+ . map ( |ident| Cfg :: Boolean ( ident. to_string ( ) ) )
92+ . ok_or_else ( || input. error ( "path must be identifier" ) ) ,
93+ syn:: Meta :: NameValue ( syn:: MetaNameValue {
94+ path,
95+ value :
96+ syn:: Expr :: Lit ( syn:: ExprLit {
97+ lit : syn:: Lit :: Str ( lit) ,
98+ ..
99+ } ) ,
100+ ..
101+ } ) => path
102+ . get_ident ( )
103+ . map ( |ident| Cfg :: Named ( ident. to_string ( ) , lit. value ( ) ) )
104+ . ok_or_else ( || input. error ( "path must be identifier" ) ) ,
105+ syn:: Meta :: List ( meta) => {
106+ if meta. path . is_ident ( "not" ) {
107+ let cfg = meta. parse_args ( ) ?;
108+ Ok ( Cfg :: Not ( Box :: new ( cfg) ) )
109+ } else if meta. path . is_ident ( "all" ) {
110+ let cfgs = meta. parse_args_with (
111+ syn:: punctuated:: Punctuated :: < Cfg , syn:: Token ![ , ] > :: parse_terminated,
112+ ) ?;
113+
114+ Ok ( Cfg :: All ( cfgs. into_iter ( ) . collect ( ) ) )
115+ } else if meta. path . is_ident ( "any" ) {
116+ let cfgs = meta. parse_args_with (
117+ syn:: punctuated:: Punctuated :: < Cfg , syn:: Token ![ , ] > :: parse_terminated,
118+ ) ?;
119+
120+ Ok ( Cfg :: Any ( cfgs. into_iter ( ) . collect ( ) ) )
121+ } else {
122+ Err ( input. error ( "invalid list argument" ) )
123+ }
124+ }
125+ _ => Err ( input. error ( "Failed to parse cfg" ) ) ,
126+ }
127+ }
128+ }
129+
84130impl Cfg {
85131 pub fn join ( cfgs : & [ Cfg ] ) -> Option < Cfg > {
86132 if cfgs. is_empty ( ) {
@@ -103,12 +149,14 @@ impl Cfg {
103149 let mut configs = Vec :: new ( ) ;
104150
105151 for attr in attrs {
106- if let Ok ( syn:: Meta :: List ( syn:: MetaList { path, nested , .. } ) ) = attr. parse_meta ( ) {
107- if !path. is_ident ( "cfg" ) || nested . len ( ) != 1 {
152+ if let syn:: Meta :: List ( meta @ syn:: MetaList { path, .. } ) = & attr. meta {
153+ if !path. is_ident ( "cfg" ) {
108154 continue ;
109155 }
110156
111- if let Some ( config) = Cfg :: load_single ( nested. first ( ) . unwrap ( ) ) {
157+ let cfg = meta. parse_args ( ) . ok ( ) ;
158+
159+ if let Some ( config) = cfg {
112160 configs. push ( config) ;
113161 }
114162 }
@@ -126,73 +174,20 @@ impl Cfg {
126174 match syn:: parse_str :: < syn:: Meta > ( target) {
127175 Ok ( target) => {
128176 // Parsing succeeded using the #[cfg] syntax
129- if let syn:: Meta :: List ( syn :: MetaList { path , nested , .. } ) = target {
130- if !path. is_ident ( "cfg" ) || nested . len ( ) != 1 {
177+ if let syn:: Meta :: List ( meta ) = target {
178+ if !meta . path . is_ident ( "cfg" ) {
131179 return None ;
132180 }
133- Cfg :: load_single ( nested . first ( ) . unwrap ( ) )
181+ meta . parse_args ( ) . ok ( )
134182 } else {
135183 None
136184 }
137185 }
138186 Err ( _) => {
139187 // Parsing failed using #[cfg], this may be a literal target
140188 // name
141- Cfg :: load_single ( & syn:: NestedMeta :: Lit ( syn:: Lit :: Str ( syn:: LitStr :: new (
142- target,
143- proc_macro2:: Span :: call_site ( ) ,
144- ) ) ) )
145- }
146- }
147- }
148-
149- fn load_single ( item : & syn:: NestedMeta ) -> Option < Cfg > {
150- Some ( match * item {
151- syn:: NestedMeta :: Meta ( syn:: Meta :: Path ( ref path) ) => {
152- Cfg :: Boolean ( format ! ( "{}" , path. segments. first( ) . unwrap( ) . ident) )
189+ Some ( Cfg :: Boolean ( target. clone ( ) ) )
153190 }
154- syn:: NestedMeta :: Meta ( syn:: Meta :: NameValue ( syn:: MetaNameValue {
155- ref path,
156- lit : syn:: Lit :: Str ( ref value) ,
157- ..
158- } ) ) => Cfg :: Named (
159- format ! ( "{}" , path. segments. first( ) . unwrap( ) . ident) ,
160- value. value ( ) ,
161- ) ,
162- syn:: NestedMeta :: Meta ( syn:: Meta :: List ( syn:: MetaList {
163- ref path,
164- ref nested,
165- ..
166- } ) ) => {
167- if path. is_ident ( "any" ) {
168- Cfg :: Any ( Cfg :: load_list ( nested. iter ( ) ) ?)
169- } else if path. is_ident ( "all" ) {
170- Cfg :: All ( Cfg :: load_list ( nested. iter ( ) ) ?)
171- } else if path. is_ident ( "not" ) {
172- if nested. len ( ) != 1 {
173- return None ;
174- }
175-
176- Cfg :: Not ( Box :: new ( Cfg :: load_single ( & nested[ 0 ] ) ?) )
177- } else {
178- return None ;
179- }
180- }
181- _ => return None ,
182- } )
183- }
184-
185- fn load_list < ' a , I : Iterator < Item = & ' a syn:: NestedMeta > > ( attrs : I ) -> Option < Vec < Cfg > > {
186- let mut configs = Vec :: new ( ) ;
187-
188- for attr in attrs {
189- configs. push ( Cfg :: load_single ( attr) ?) ;
190- }
191-
192- if configs. is_empty ( ) {
193- None
194- } else {
195- Some ( configs)
196191 }
197192 }
198193}
0 commit comments