@ -1,28 +1,39 @@
use syn ::{
use syn ::{
parse ::{ Parse , ParseStream } ,
parse ::{ Parse , ParseStream } ,
punctuated ::{ Pair , Punctuated } ,
punctuated ::{ Pair , Punctuated } ,
token ::Eq ,
Error , Ident , LitStr , Result , Token ,
Error , Ident , LitStr , Result , Token ,
} ;
} ;
pub ( crate ) struct NameValue {
pub ( crate ) struct NameValue {
name : Ident ,
name : Ident ,
_eq : Eq ,
value : LitStr ,
value : LitStr ,
}
}
pub ( crate ) enum Arg {
String ( NameValue ) ,
Bool ( Ident ) ,
}
pub ( crate ) struct Args {
pub ( crate ) struct Args {
pub ( crate ) args : Vec < NameValue > ,
pub ( crate ) args : Vec < Arg > ,
}
}
impl Parse for Args {
impl Parse for Args {
fn parse ( input : ParseStream ) -> Result < Args > {
fn parse ( input : ParseStream ) -> Result < Args > {
let args = Punctuated ::< NameValue , Token ! [ , ] > ::parse_terminated_with ( input , | input | {
let args = Punctuated ::< Arg , Token ! [ , ] > ::parse_terminated_with ( input , | input | {
Ok ( NameValue {
let ident = input . parse ::< Ident > ( ) ? ;
name : input . parse ( ) ? ,
let lookahead = input . lookahead1 ( ) ;
_eq : input . parse ( ) ? ,
if input . is_empty ( ) | | lookahead . peek ( Token ! [ , ] ) {
Ok ( Arg ::Bool ( ident ) )
} else if lookahead . peek ( Token ! [ = ] ) {
let _ : Token ! [ = ] = input . parse ( ) ? ;
Ok ( Arg ::String ( NameValue {
name : ident ,
value : input . parse ( ) ? ,
value : input . parse ( ) ? ,
} )
} ) )
} else {
Err ( lookahead . error ( ) )
}
} ) ?
} ) ?
. into_pairs ( )
. into_pairs ( )
. map ( | pair | match pair {
. map ( | pair | match pair {
@ -35,35 +46,55 @@ impl Parse for Args {
}
}
}
}
pub ( crate ) fn pop_arg ( args : & mut Args , name : & str ) -> Option < String > {
pub ( crate ) fn pop_string_arg ( args : & mut Args , name : & str ) -> Option < String > {
match args . args . iter ( ) . position ( | arg | arg . name = = name ) {
args . args
Some ( index ) = > Some ( args . args . remove ( index ) . value . value ( ) ) ,
. iter ( )
None = > None ,
. position ( | arg | matches! ( arg , Arg ::String ( name_val ) if name_val . name = = name ) )
}
. map ( | index | match args . args . remove ( index ) {
Arg ::String ( v ) = > v . value . value ( ) ,
_ = > panic! ( "impossible variant" ) ,
} )
}
}
pub ( crate ) fn pop_required_arg ( args : & mut Args , name : & str ) -> Result < String > {
pub ( crate ) fn pop_bool_arg ( args : & mut Args , name : & str ) -> bool {
let value = match args . args . iter ( ) . position ( | arg | arg . name = = name ) {
args . args
Some ( index ) = > Some ( args . args . remove ( index ) . value . value ( ) ) ,
. iter ( )
None = > None ,
. position ( | arg | matches! ( arg , Arg ::Bool ( ident ) if ident = = name ) )
. map ( | index | match args . args . remove ( index ) {
Arg ::Bool ( ident ) = > ident ,
_ = > panic! ( "impossible variant" ) ,
} )
. is_some ( )
}
pub ( crate ) fn pop_required_string_arg ( args : & mut Args , name : & str ) -> Result < String > {
args . args
. iter ( )
. position ( | arg | matches! ( arg , Arg ::String ( name_val ) if name_val . name = = name ) )
. map ( | index | match args . args . remove ( index ) {
Arg ::String ( v ) = > v . value . value ( ) ,
_ = > panic! ( "impossible variant" ) ,
} )
. ok_or_else ( | | {
let tokens = match args . args . first ( ) . unwrap ( ) {
Arg ::String ( name_val ) = > & name_val . name ,
Arg ::Bool ( ident ) = > ident ,
} ;
} ;
match value {
Error ::new_spanned ( tokens , "missing required argument" )
Some ( value ) = > Ok ( value ) ,
} )
None = > Err ( Error ::new_spanned (
args . args . first ( ) . unwrap ( ) . name . clone ( ) ,
format! ( "missing required argument `{}`" , name ) ,
) ) ,
}
}
}
pub ( crate ) fn err_on_unknown_args ( args : & Args ) -> Result < ( ) > {
pub ( crate ) fn err_on_unknown_args ( args : & Args ) -> Result < ( ) > {
if let Some ( arg ) = args . args . get ( 0 ) {
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 ( ( ) )
Ok ( ( ) )
}
}
pub ( crate ) fn name_arg ( args : & mut Args ) -> Result < Option < String > > {
pub ( crate ) fn name_arg ( args : & mut Args ) -> Option < String > {
let name = pop_arg ( args , "name" ) ;
pop_string_arg ( args , "name" )
Ok ( name )
}
}