@ -7,22 +7,32 @@ use syn::{
pub ( crate ) struct NameValue {
name : Ident ,
_eq : Eq ,
value : LitStr ,
}
pub ( crate ) enum Arg {
String ( NameValue ) ,
Bool ( Ident ) ,
}
pub ( crate ) struct Args {
pub ( crate ) args : Vec < NameValue > ,
pub ( crate ) args : Vec < Arg > ,
}
impl Parse for Args {
fn parse ( input : ParseStream ) -> Result < Args > {
let args = Punctuated ::< NameValue , Token ! [ , ] > ::parse_terminated_with ( input , | input | {
Ok ( NameValue {
name : input . parse ( ) ? ,
_eq : input . parse ( ) ? ,
let args = Punctuated ::< Arg , Token ! [ , ] > ::parse_terminated_with ( input , | input | {
let ident = input . parse ::< Ident > ( ) ? ;
let lookahead = input . lookahead1 ( ) ;
if lookahead . peek ( Token ! [ = ] ) {
let _ = input . parse ::< Eq > ( ) ? ;
Ok ( Arg ::String ( NameValue {
name : ident ,
value : input . parse ( ) ? ,
} )
} ) )
} else {
Ok ( Arg ::Bool ( ident ) )
}
} ) ?
. into_pairs ( )
. map ( | pair | match pair {
@ -35,35 +45,66 @@ impl Parse for Args {
}
}
pub ( crate ) fn pop_arg ( args : & mut Args , name : & str ) -> Option < String > {
match args . args . iter ( ) . position ( | arg | arg . name = = name ) {
Some ( index ) = > Some ( args . args . remove ( index ) . value . value ( ) ) ,
pub ( crate ) fn pop_string_arg ( args : & mut Args , name : & str ) -> Option < String > {
let value = match args . args . iter ( ) . position ( | arg | match arg {
Arg ::String ( name_val ) = > name_val . name = = name ,
Arg ::Bool ( _ ) = > false ,
} ) {
Some ( index ) = > Some ( args . args . remove ( index ) ) ,
None = > None ,
} ;
match value {
Some ( Arg ::String ( value ) ) = > Some ( value . value . value ( ) ) ,
Some ( Arg ::Bool ( _ ) ) | None = > None ,
}
}
pub ( crate ) fn pop_required_arg ( args : & mut Args , name : & str ) -> Result < String > {
let value = match args . args . iter ( ) . position ( | arg | arg . name = = name ) {
Some ( index ) = > Some ( args . args . remove ( index ) . value . value ( ) ) ,
pub ( crate ) fn pop_bool_arg ( args : & mut Args , name : & str ) -> bool {
let value = match args . args . iter ( ) . position ( | arg | match arg {
Arg ::String ( _ ) = > false ,
Arg ::Bool ( ident ) = > ident = = name ,
} ) {
Some ( index ) = > Some ( args . args . remove ( index ) ) ,
None = > None ,
} ;
value . is_some ( )
}
pub ( crate ) fn pop_required_string_arg ( args : & mut Args , name : & str ) -> Result < String > {
let value = match args . args . iter ( ) . position ( | arg | match arg {
Arg ::String ( name_val ) = > name_val . name = = name ,
Arg ::Bool ( _ ) = > false ,
} ) {
Some ( index ) = > Some ( args . args . remove ( index ) ) ,
None = > None ,
} ;
match value {
Some ( value ) = > Ok ( value ) ,
None = > Err ( Error ::new_spanned (
args . args . first ( ) . unwrap ( ) . name . clone ( ) ,
Some ( Arg ::String ( value ) ) = > Ok ( value . value . value ( ) ) ,
Some ( Arg ::Bool ( _ ) ) = > unreachable! ( "arg bool were filtered out" ) ,
None = > {
let tokens = match args . args . first ( ) . unwrap ( ) {
Arg ::String ( name_val ) = > & name_val . name ,
Arg ::Bool ( ident ) = > ident ,
} ;
Err ( Error ::new_spanned (
tokens ,
format! ( "missing required argument `{}`" , name ) ,
) ) ,
) )
}
}
}
pub ( crate ) fn err_on_unknown_args ( args : & Args ) -> Result < ( ) > {
if let Some ( arg ) = args . args . get ( 0 ) {
return Err ( Error ::new_spanned ( & arg . name , "invalid argument" ) ) ;
let tokens = match arg {
Arg ::String ( name_val ) = > name_val . name . clone ( ) ,
Arg ::Bool ( ident ) = > ident . clone ( ) ,
} ;
return Err ( Error ::new_spanned ( tokens , "invalid argument" ) ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn name_arg ( args : & mut Args ) -> Result < Option < String > > {
let name = pop_arg ( args , "name" ) ;
Ok ( name )
pub ( crate ) fn name_arg ( args : & mut Args ) -> Option < String > {
pop_string_arg ( args , "name" )
}