77use crate :: extract:: { Extract , ExtractIterator , ExtractMap } ;
88use itertools:: Itertools ;
99use proc_macro2:: { Ident , Span } ;
10+ use std:: fmt:: Debug ;
1011use syn:: parse:: discouraged:: Speculative ;
1112use syn:: parse:: { Parse , ParseStream } ;
1213use syn:: punctuated:: Punctuated ;
1314use syn:: spanned:: Spanned ;
1415use syn:: token:: Comma ;
15- use syn:: { Expr , GenericParam , Lit , LitStr , Type } ;
16+ use syn:: { Expr , ExprLit , FnArg , GenericParam , Lit , LitStr , Pat , Type } ;
1617
17- use crate :: params:: Param ;
18+ use crate :: params:: { Param , ParamType } ;
1819
1920/// The value of an [`Argument`]; everything after the equal sign
2021#[ derive( Clone , Debug ) ]
2122pub ( crate ) enum ArgumentValue {
2223 TypeList ( Vec < Type > ) ,
2324 LitList ( Vec < Lit > ) ,
25+ ExprList ( Vec < Expr > ) ,
2426 Str ( String ) ,
2527}
2628
@@ -45,20 +47,31 @@ fn parse_typelist(input: ParseStream) -> Option<syn::Result<ArgumentValue>> {
4547
4648/// Parse a bracketed list of literals
4749fn parse_litlist ( input : ParseStream ) -> Option < syn:: Result < ArgumentValue > > {
48- let parse = || {
49- let exprs = input. parse :: < syn:: ExprArray > ( ) ?;
50- let entries: syn:: Result < Vec < Lit > > = exprs
50+ // match on brackets. anything invalid after is an error
51+ return if input. peek ( syn:: token:: Bracket ) {
52+ let exprs = input. parse :: < syn:: ExprArray > ( ) . ok ( ) ?;
53+ let entries: Option < Vec < Lit > > = exprs
5154 . elems
5255 . iter ( )
53- . map ( |expr : & Expr | -> syn :: Result < Lit > {
54- return if let Expr :: Lit ( lit) = expr {
55- Ok ( lit. lit . clone ( ) )
56+ . map ( |expr : & Expr | -> Option < Lit > {
57+ if let Expr :: Lit ( lit) = expr {
58+ Some ( lit. lit . clone ( ) )
5659 } else {
57- Err ( syn :: Error :: new ( expr . span ( ) , "Expression is not a literal" ) )
58- } ;
60+ None
61+ }
5962 } )
6063 . collect ( ) ;
61- Ok ( ArgumentValue :: LitList ( entries?) )
64+ Some ( Ok ( ArgumentValue :: LitList ( entries?) ) )
65+ } else {
66+ None
67+ } ;
68+ }
69+
70+ fn parse_exprlist ( input : ParseStream ) -> Option < syn:: Result < ArgumentValue > > {
71+ let parse = || {
72+ let exprs = input. parse :: < syn:: ExprArray > ( ) ?;
73+ let entries = exprs. elems . iter ( ) . cloned ( ) . collect_vec ( ) ;
74+ Ok ( ArgumentValue :: ExprList ( entries) )
6275 } ;
6376
6477 // match on brackets. anything invalid after is an error
@@ -81,7 +94,7 @@ impl Parse for Argument {
8194 input. parse :: < syn:: token:: Eq > ( ) ?;
8295
8396 // iterate over the known parse functions for arguments
84- [ parse_typelist, parse_litlist, parse_str]
97+ [ parse_typelist, parse_litlist, parse_exprlist , parse_str]
8598 . iter ( )
8699 . find_map ( |f| {
87100 // fork the buffer, so we can rewind if there isnt a match
@@ -110,6 +123,7 @@ impl Argument {
110123 ArgumentValue :: TypeList ( _) => "type list" ,
111124 ArgumentValue :: LitList ( _) => "const list" ,
112125 ArgumentValue :: Str ( _) => "string" ,
126+ ArgumentValue :: ExprList ( _) => "expression list" ,
113127 }
114128 }
115129}
@@ -145,50 +159,96 @@ impl Extract for ArgumentList {
145159}
146160
147161impl ArgumentList {
148- /// consume a paramlist from the argument list that matches the given generic parameter
149- /// and return it.
150- /// Returns an error if there is a type mismatch, or if there is not exactly one match
151- pub fn consume_paramlist ( & mut self , gp : & GenericParam ) -> syn:: Result < Vec < ( Ident , Param ) > > {
152- let ( g_ident, g_name) = match gp {
153- GenericParam :: Lifetime ( lt) => Err ( syn:: Error :: new (
154- lt. span ( ) ,
155- "Parameterizing lifetimes is not supported" ,
156- ) ) ,
157- GenericParam :: Type ( t) => Ok ( ( & t. ident , "type" ) ) ,
158- GenericParam :: Const ( c) => Ok ( ( & c. ident , "const" ) ) ,
159- } ?;
162+ fn consume_paramlist (
163+ & mut self ,
164+ ident : & Ident ,
165+ ty : & ParamType ,
166+ ) -> syn:: Result < Vec < ( Ident , Param ) > > {
160167 self . extract_map ( |arg| -> Option < syn:: Result < Vec < ( Ident , Param ) > > > {
161- return if & arg. ident == g_ident {
162- match ( & arg. value , gp ) {
163- ( ArgumentValue :: TypeList ( tl) , GenericParam :: Type ( _ ) ) => Some (
168+ return if & arg. ident == ident {
169+ match ( & arg. value , ty ) {
170+ ( ArgumentValue :: TypeList ( tl) , ParamType :: GenericType ) => Some (
164171 Ok ( tl. iter ( )
165- . map ( |ty| ( arg. ident . clone ( ) , Param :: Type ( ty. clone ( ) ) ) )
172+ . map ( |ty| ( arg. ident . clone ( ) , Param :: GenericType ( ty. clone ( ) ) ) )
166173 . collect ( ) ) ,
167174 ) ,
168- ( ArgumentValue :: LitList ( ll) , GenericParam :: Const ( _ ) ) => Some (
175+ ( ArgumentValue :: LitList ( ll) , ParamType :: GenericConst ) => Some (
169176 Ok ( ll. iter ( )
170- . map ( |lit| ( arg. ident . clone ( ) , Param :: Lit ( lit. clone ( ) ) ) )
177+ . map ( |lit| ( arg. ident . clone ( ) , Param :: GenericConst ( lit. clone ( ) ) ) )
178+ . collect ( ) ) ,
179+ ) ,
180+ ( ArgumentValue :: LitList ( ll) , ParamType :: FnArg ) => Some (
181+ Ok ( ll. iter ( )
182+ . map ( |lit| ( arg. ident . clone ( ) , Param :: FnArg (
183+ Expr :: Lit ( ExprLit { attrs : vec ! [ ] , lit : lit. clone ( ) } ) ) ) )
184+ . collect ( ) ) ,
185+ ) ,
186+ ( ArgumentValue :: ExprList ( el) , ParamType :: FnArg ) => Some (
187+ Ok ( el. iter ( )
188+ . map ( |e| ( arg. ident . clone ( ) , Param :: FnArg ( e. clone ( ) ) ) )
171189 . collect ( ) ) ,
172190 ) ,
173191 ( ArgumentValue :: TypeList ( _) , _) | ( ArgumentValue :: LitList ( _) , _) => Some ( Err ( syn:: Error :: new (
174192 arg. ident . span ( ) ,
175- format ! ( "Mismatched parameterization: Expected {} list but found {}" , g_name , arg. short_type( ) ) ,
193+ format ! ( "Mismatched parameterization: Expected {} list but found {}" , ty , arg. short_type( ) ) ,
176194 ) ) ) ,
177195 /* fall through, in case theres a generic argument named for example "fmt". there probably shouldn't be though */
178- ( _, _) => None }
196+ ( _, _) => None
197+ }
179198 } else {
180199 None
181200 }
182201 } )
183- . at_most_one ( )
184- . map_err ( |_| {
185- // more than one match
186- syn:: Error :: new (
187- Span :: call_site ( ) ,
188- format ! ( "Multiple {g_name } parameterizations provided for `{g_ident }`" ) ,
189- )
190- } ) ?
191- . ok_or ( syn:: Error :: new ( Span :: call_site ( ) , format ! ( "No {g_name } parameterization provided for `{g_ident }`" ) ) ) ?
202+ . at_most_one ( )
203+ . map_err ( |_| {
204+ // more than one match
205+ syn:: Error :: new (
206+ Span :: call_site ( ) ,
207+ format ! ( "Multiple {ty } parameterizations provided for `{ident }`" ) ,
208+ )
209+ } ) ?
210+ . ok_or ( syn:: Error :: new ( Span :: call_site ( ) , format ! ( "No {ty } parameterization provided for `{ident }`" ) ) ) ?
192211 // no matches
193212 }
213+ /// consume a paramlist from the argument list that matches the given generic parameter
214+ /// and return it.
215+ /// Returns an error if there is a type mismatch, or if there is not exactly one match
216+ pub fn consume_generic_paramlist (
217+ & mut self ,
218+ gp : & GenericParam ,
219+ ) -> syn:: Result < Vec < ( Ident , Param ) > > {
220+ let ( ident, ty) = match gp {
221+ GenericParam :: Lifetime ( lt) => Err ( syn:: Error :: new (
222+ lt. span ( ) ,
223+ "Parameterizing lifetimes is not supported" ,
224+ ) ) ,
225+ GenericParam :: Type ( t) => Ok ( ( & t. ident , ParamType :: GenericType ) ) ,
226+ GenericParam :: Const ( c) => Ok ( ( & c. ident , ParamType :: GenericConst ) ) ,
227+ } ?;
228+ self . consume_paramlist ( ident, & ty)
229+ }
230+
231+ /// consume a paramlist from the argument list that matches the given function argument and return it.
232+ /// Returns an error if there is not exactly one match
233+ pub fn consume_arg_paramlist ( & mut self , arg : & FnArg ) -> syn:: Result < Vec < ( Ident , Param ) > > {
234+ let pat = match arg {
235+ FnArg :: Receiver ( _) => {
236+ return Err ( syn:: Error :: new (
237+ arg. span ( ) ,
238+ "self arguments are not supported" ,
239+ ) )
240+ }
241+ FnArg :: Typed ( pat) => * ( pat. clone ( ) . pat ) ,
242+ } ;
243+ let ident = match pat {
244+ Pat :: Ident ( pat_ident) => pat_ident. ident ,
245+ _ => {
246+ return Err ( syn:: Error :: new (
247+ pat. span ( ) ,
248+ "function arguments must be an identity pattern" ,
249+ ) )
250+ }
251+ } ;
252+ self . consume_paramlist ( & ident, & ParamType :: FnArg )
253+ }
194254}
0 commit comments