args.rs 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. use syn::{
  2. parse::{Parse, ParseStream},
  3. punctuated::{Pair, Punctuated},
  4. Error, Ident, LitStr, Result, Token,
  5. };
  6. pub(crate) struct NameValue {
  7. name: Ident,
  8. value: LitStr,
  9. }
  10. pub(crate) enum Arg {
  11. String(NameValue),
  12. Bool(Ident),
  13. }
  14. pub(crate) struct Args {
  15. pub(crate) args: Vec<Arg>,
  16. }
  17. impl Parse for Args {
  18. fn parse(input: ParseStream) -> Result<Args> {
  19. let args = Punctuated::<Arg, Token![,]>::parse_terminated_with(input, |input| {
  20. let ident = input.parse::<Ident>()?;
  21. let lookahead = input.lookahead1();
  22. if input.is_empty() || lookahead.peek(Token![,]) {
  23. Ok(Arg::Bool(ident))
  24. } else if lookahead.peek(Token![=]) {
  25. let _: Token![=] = input.parse()?;
  26. Ok(Arg::String(NameValue {
  27. name: ident,
  28. value: input.parse()?,
  29. }))
  30. } else {
  31. Err(lookahead.error())
  32. }
  33. })?
  34. .into_pairs()
  35. .map(|pair| match pair {
  36. Pair::Punctuated(name_val, _) => name_val,
  37. Pair::End(name_val) => name_val,
  38. })
  39. .collect();
  40. Ok(Args { args })
  41. }
  42. }
  43. pub(crate) fn pop_string_arg(args: &mut Args, name: &str) -> Option<String> {
  44. args.args
  45. .iter()
  46. .position(|arg| matches!(arg, Arg::String(name_val) if name_val.name == name))
  47. .map(|index| match args.args.remove(index) {
  48. Arg::String(v) => v.value.value(),
  49. _ => panic!("impossible variant"),
  50. })
  51. }
  52. pub(crate) fn pop_bool_arg(args: &mut Args, name: &str) -> bool {
  53. args.args
  54. .iter()
  55. .position(|arg| matches!(arg, Arg::Bool(ident) if ident == name))
  56. .map(|index| match args.args.remove(index) {
  57. Arg::Bool(ident) => ident,
  58. _ => panic!("impossible variant"),
  59. })
  60. .is_some()
  61. }
  62. pub(crate) fn err_on_unknown_args(args: &Args) -> Result<()> {
  63. if let Some(arg) = args.args.get(0) {
  64. let tokens = match arg {
  65. Arg::String(name_val) => name_val.name.clone(),
  66. Arg::Bool(ident) => ident.clone(),
  67. };
  68. return Err(Error::new_spanned(tokens, "invalid argument"));
  69. }
  70. Ok(())
  71. }
  72. pub(crate) fn name_arg(args: &mut Args) -> Option<String> {
  73. pop_string_arg(args, "name")
  74. }