1#![allow(clippy::style)]
4
5extern crate proc_macro;
6
7mod utils;
8use utils::*;
9
10use proc_macro::TokenStream;
11use quote::quote;
12
13use core::fmt::{self, Write};
14
15struct ArgumentEnvInit<'a> {
16 env_key: &'a Option<String>,
17 prefix: &'a str,
18 field_name: &'a str,
19}
20
21impl fmt::Display for ArgumentEnvInit<'_> {
22 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
23 let Self {
24 env_key,
25 prefix,
26 field_name,
27 } = self;
28 if let Some(env_key) = env_key {
29 fmt.write_fmt(format_args!("else if let Ok(_value_) = ::std::env::var(\"{prefix}{env_key}\") {{ match {FROM_FN}(&_value_) {{ Ok(_value_) => _value_, Err(error) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{field_name}\", \"${prefix}{env_key}\"))) }} }}"))
30 } else {
31 Ok(())
32 }
33 }
34}
35
36struct ArgumentEnvDesc<'a> {
37 env_key: &'a Option<String>,
38 prefix: &'a str,
39 desc: &'a str,
40}
41
42impl fmt::Display for ArgumentEnvDesc<'_> {
43 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
44 let Self {
45 env_key,
46 prefix,
47 desc,
48 } = self;
49
50 if let Some(env_key) = &env_key {
51 let desc = desc.trim().trim_end_matches('.');
52 if !desc.is_empty() {
53 fmt.write_str(desc)?;
54 fmt.write_str(". ")?;
55 }
56 fmt.write_fmt(format_args!("Can be set via env {prefix}{env_key}"))
57 } else {
58 fmt.write_str(desc)
59 }
60 }
61}
62
63
64struct Argument {
65 field_name: String,
66 name: String,
67 desc: String,
68 required: bool,
69 is_optional: bool,
70 default: Option<String>,
71 env_key: Option<String>,
72}
73
74impl Argument {
75 #[inline]
76 fn env_init_fmt<'a>(&'a self, prefix: &'a str, field_name: &'a str) -> ArgumentEnvInit<'a> {
77 ArgumentEnvInit {
78 env_key: &self.env_key,
79 prefix,
80 field_name,
81 }
82 }
83
84 #[inline]
85 fn env_desc_fmt<'a>(&'a self, prefix: &'a str) -> ArgumentEnvDesc<'a> {
86 ArgumentEnvDesc {
87 env_key: &self.env_key,
88 prefix,
89 desc: &self.desc
90 }
91 }
92}
93
94#[derive(PartialEq, Eq, Debug)]
95enum OptValueType {
96 Help,
97 Bool,
98 Value,
99 MultiValue,
100}
101
102struct Opt {
103 arg: Argument,
104 long: String,
105 short: Option<String>,
106 typ: OptValueType,
107}
108
109struct Command {
110 variant_name: String,
111 command_name: String,
112 desc: String,
113}
114
115const CONCAT_DEFAULT_PROG_NAME_ARGS: &str = "env!(\"CARGO_PKG_NAME\"), \" \", env!(\"CARGO_PKG_VERSION\")";
116const FROM_FN: &str = "::core::str::FromStr::from_str";
117const TAB: &str = " ";
118const PARSER_TRAIT: &str = "arg::Args";
119const DEFAULT_INIT: &str = "Default::default()";
120const INVALID_ARG_TYPE_STRING: &str = "Attribute accepts only str";
121const INVALID_REQUIRED_BOOL: &str = "Attribute required cannot be applied to bool switch";
122const UNKNOWN_ARG_ATTR: &str = "Unknown attribute is used";
123const ARG_INVALID_CHARS: &[char] = &[' ', '\t'];
124const ARG_NAME_SPACE_ERROR: &str = "Name contains space character";
125
126fn parse_segment(segment: &syn::PathSegment) -> OptValueType {
127 if segment.ident == "bool" {
128 OptValueType::Bool
129 } else if segment.ident == "Vec" {
130 OptValueType::MultiValue
131 } else {
132 OptValueType::Value
133 }
134}
135
136fn from_enum(ast: &syn::DeriveInput, payload: &syn::DataEnum) -> TokenStream {
137 let mut about_prog = String::new();
138 for attr in ast.attrs.iter() {
139 match &attr.meta {
140 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
141 let literal = match &value.value {
142 syn::Expr::Lit(literal) => &literal.lit,
143 _ => return syn::Error::new_spanned(value.clone(), "Attribute should be literal").to_compile_error().into()
144 };
145 if let syn::Lit::Str(ref text) = literal {
146 about_prog.push_str(&text.value());
147 about_prog.push_str("\n");
148 }
149 },
150 _ => (),
151 }
152 }
153 about_prog.pop();
154
155 let mut commands = Vec::new();
156 for variant in payload.variants.iter() {
157 let mut desc = String::new();
158 let variant_name = variant.ident.to_string();
159 if variant_name.is_empty() {
160 return syn::Error::new_spanned(&variant.ident, "Oi, mate, You cannot have enum variant without name").to_compile_error().into()
161 }
162 let command_name = to_hyphenated_lower_case(&variant_name);
163 if command_name.eq_ignore_ascii_case("help") {
164 return syn::Error::new_spanned(&variant.ident, "Oi, mate, You cannot use variant 'Help'").to_compile_error().into()
165 }
166
167 for attr in variant.attrs.iter() {
168 match &attr.meta {
169 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
170 let literal = match &value.value {
171 syn::Expr::Lit(literal) => &literal.lit,
172 _ => return syn::Error::new_spanned(value.clone(), "Attribute should be literal").to_compile_error().into()
173 };
174
175 if let syn::Lit::Str(ref text) = literal {
176 desc.push_str(&text.value());
177 desc.push_str(" ");
178 }
179 },
180 _ => continue
181 }
182 }
183
184 let field = match &variant.fields {
185 syn::Fields::Unit => return syn::Error::new_spanned(&variant.fields, "Unit variant cannot be used").to_compile_error().into(),
186 syn::Fields::Named(_) => return syn::Error::new_spanned(&variant.fields, "I'm too lazy to support named variant").to_compile_error().into(),
187 syn::Fields::Unnamed(fields) => {
188 if fields.unnamed.empty_or_trailing() {
189 return syn::Error::new_spanned(&fields, "MUST specify single field").to_compile_error().into();
190 } else if fields.unnamed.len() > 1 {
191 return syn::Error::new_spanned(fields, "MUST not specify more than 1 field").to_compile_error().into();
192 } else {
193 fields.unnamed.first().unwrap()
194 }
195 },
196 };
197
198 match &field.ty {
199 syn::Type::Path(ref ty) => {
200 let ty = ty.path.segments.last().expect("To have at least one segment");
201 if ty.ident == "Option" {
202 return syn::Error::new_spanned(ty, "Command cannot be optional").to_compile_error().into()
203 } else {
204 match parse_segment(ty) {
205 OptValueType::Bool => return syn::Error::new_spanned(ty, "Command value cannot be boolean").to_compile_error().into(),
206 OptValueType::MultiValue => return syn::Error::new_spanned(ty, "Command value Vec<_>").to_compile_error().into(),
207 _ => (),
208 }
209 }
210 },
211 ty => {
212 return syn::Error::new_spanned(ty, "Expected simple ident or path").to_compile_error().into()
213 }
214 }
215
216 commands.push(Command {
217 command_name,
218 variant_name,
219 desc
220 })
221 }
222
223 if commands.is_empty() {
224 return syn::Error::new_spanned(ast, "Enum must have at least one variant").to_compile_error().into()
225 }
226
227 let (impl_gen, type_gen, where_clause) = ast.generics.split_for_impl();
228
229 let help_msg = {
230 use std::io::Write;
231 use tabwriter::TabWriter;
232
233 let mut tw = TabWriter::new(vec![]);
234
235 let _ = writeln!(tw, "COMMANDS:");
236 for command in commands.iter() {
237 let _ = writeln!(tw, "\t{}\t{}", command.command_name, command.desc);
238 }
239
240 let _ = tw.flush();
241
242 String::from_utf8(tw.into_inner().unwrap()).unwrap()
243 };
244
245 let mut result = String::new();
246 let _ = writeln!(result, "{} {} for {}{} {{", quote!(impl#impl_gen), PARSER_TRAIT, ast.ident, quote!(#type_gen #where_clause));
247
248 let _ = writeln!(result, "{}const HELP: &'static str = \"{}\";", TAB, help_msg);
249
250 let _ = writeln!(result, "{}fn from_args<'a, T: IntoIterator<Item = &'a str>>(_args_: T) -> Result<Self, arg::ParseKind<'a>> {{", TAB);
252
253 let _ = writeln!(result, "{0}{0}let mut _args_ = _args_.into_iter();\n", TAB);
254
255 let _ = writeln!(result, "{0}{0}while let Some(_arg_) = _args_.next() {{", TAB);
257
258 let _ = writeln!(result, "{0}{0}{0}if _arg_.eq_ignore_ascii_case(\"help\") {{", TAB);
260 let _ = writeln!(result, "{0}{0}{0}{0}return Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(Self::HELP)));", TAB);
261 let _ = write!(result, "{0}{0}{0}}}", TAB);
262
263 let mut allowed_commands = String::new();
264 for command in commands.iter() {
265 allowed_commands.push_str(command.command_name.as_str());
266 allowed_commands.push(',');
267 allowed_commands.push(' ');
268
269 let _ = writeln!(result, " else if _arg_.eq_ignore_ascii_case(\"{}\") {{", command.command_name);
271
272 let _ = writeln!(result, "{0}{0}{0}{0}match {1}::from_args(_args_) {{", TAB, PARSER_TRAIT);
273 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(res) => return Ok(Self::{1}(res)),", TAB, command.variant_name);
274 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(error)) => return Err(arg::ParseKind::Sub(\"{1}\", error)),", TAB, command.command_name);
275 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Sub(name, error)) => return Err(arg::ParseKind::Sub(name, error)),", TAB);
276 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
277
278 let _ = write!(result, "{0}{0}{0}}}", TAB);
280 }
281
282 let _ = writeln!(result, " else {{");
284 let _ = writeln!(result, "{0}{0}{0}{0}return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"command\", _arg_)))", TAB);
285 let _ = write!(result, "{0}{0}{0}}}", TAB);
286
287 let _ = writeln!(result, "\n{0}{0}}}", TAB);
289
290 allowed_commands.pop();
291 allowed_commands.pop();
292 let _ = writeln!(result, "{0}{0}Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(\"Missing command, possible values: [{1}]\nSee 'help' for details\")))", TAB, allowed_commands);
294
295 let _ = writeln!(result, "{}}}", TAB);
297
298 let _ = writeln!(result, "}}");
299
300 if let Ok(val) = std::env::var("ARG_RS_PRINT_PARSER") {
301 match val.trim() {
302 "0" | "false" => (),
303 _ => println!("{result}"),
304 }
305 }
306 result.parse().expect("To parse generated code")
307}
308
309fn from_struct(ast: &syn::DeriveInput, payload: &syn::DataStruct) -> TokenStream {
310 let mut env_prefix = None;
311 let mut env_value_default = false;
312 let mut infer_prog_name = false;
313 let mut about_prog = String::new();
314 for attr in ast.attrs.iter() {
315 match &attr.meta {
316 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
317 let literal = match &value.value {
318 syn::Expr::Lit(literal) => &literal.lit,
319 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
320 };
321 if let syn::Lit::Str(ref text) = literal {
322 about_prog.push_str(&text.value());
323 about_prog.push('\n');
324 }
325 },
326 syn::Meta::List(list) => if list.path.is_ident("arg") {
327 let nested = match attr.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated) {
328 Ok(nested) => nested,
329 Err(error) => {
330 let error = format!("arg attribute should be list of attributes: {error}");
331 return syn::Error::new_spanned(list, error).to_compile_error().into();
332 }
333 };
334 for value_attr in nested {
335 match value_attr {
336 syn::Meta::Path(value_attr) => if value_attr.is_ident("infer_name") {
337 infer_prog_name = true;
338 } else if value_attr.is_ident("env_value_all") {
339 env_value_default = true;
340 } else {
341 let ident = utils::FormatOptionalIdent(value_attr.get_ident());
342 return syn::Error::new_spanned(&value_attr, format!("Unknown attribute: '{ident}'. Expected: infer_name")).to_compile_error().into();
343 },
344 syn::Meta::NameValue(value_attr) => if value_attr.path.is_ident("env_prefix") {
345 match &value_attr.value {
346 syn::Expr::Lit(literal) => match &literal.lit {
347 syn::Lit::Str(literal) => {
348 env_prefix = Some(literal.value());
349 }
350 _ => return syn::Error::new_spanned(attr, "Attribute should be string").to_compile_error().into(),
351 },
352 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into(),
353 }
354 } else {
355 return syn::Error::new_spanned(&value_attr, format!("Unknown attribute: '{}'. Expected: infer_name", value_attr.path.get_ident().unwrap())).to_compile_error().into();
356 }
357 unexpected => return syn::Error::new_spanned(&unexpected, "Unexpected attribute").to_compile_error().into(),
358 }
359 }
360 },
361 _ => (),
362 }
363 }
364
365 let env_prefix = match env_prefix {
366 Some(prefix) => {
367 let prefix = prefix.trim();
368 if prefix.is_empty() {
369 String::new()
370 } else {
371 format!("{prefix}_")
372 }
373 },
374 None => "ARG_".to_owned(),
375 };
376
377 about_prog.pop();
378
379 let mut options = Vec::new();
380 let mut arguments = Vec::new();
381
382 options.push(Opt {
383 arg: Argument {
384 field_name: "_".to_owned(),
385 name: "help".to_owned(),
386 desc: "Prints this help information".to_owned(),
387 required: false,
388 is_optional: false,
389 default: None,
390 env_key: None,
391 },
392 short: Some("h".to_owned()),
393 long: "help".to_owned(),
394 typ: OptValueType::Help,
395 });
396
397 let mut sub_command = None;
398 let mut multi_argument = None;
399
400 for field in payload.fields.iter() {
401 let field_name = field.ident.as_ref().unwrap().to_string();
402 let name = field.ident.as_ref().unwrap().to_string().trim_matches(|ch| !char::is_alphanumeric(ch)).to_owned();
403 let mut desc = String::new();
404 let mut short = None;
405 let mut long = None;
406 let mut required = false;
407 let mut is_sub = false;
408
409 let (is_optional, typ) = match field.ty {
410 syn::Type::Path(ref ty) => {
411 let ty = ty.path.segments.last().expect("To have at least one segment");
412
413 if ty.ident == "Option" {
414 let ty = match &ty.arguments {
415 syn::PathArguments::AngleBracketed(ref args) => match args.args.len() {
416 0 => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option is without type arguments. Fix it").to_compile_error().into(),
417 1 => match args.args.first().unwrap() {
418 syn::GenericArgument::Type(syn::Type::Path(ty)) => parse_segment(ty.path.segments.last().expect("To have at least one segment")),
419 _ => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option should have type argument, but got some other shite. Fix it").to_compile_error().into(),
420 },
421 _ => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option has too many type arguments. Fix it").to_compile_error().into()
422 },
423 syn::PathArguments::None => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option is without type arguments. Fix it").to_compile_error().into(),
424 syn::PathArguments::Parenthesized(_) => return syn::Error::new_spanned(&ty.ident, "Oi, mate, you got wrong brackets for your Option . Fix it").to_compile_error().into(),
425 };
426
427 (true, ty)
428 } else {
429 (false, parse_segment(ty))
430 }
431 },
432 _ => (false, OptValueType::Value),
433 };
434
435 if is_optional && typ == OptValueType::MultiValue {
436 return syn::Error::new_spanned(field, "Option<Vec<_>> makes no sense. Just use plain Vec<_>").to_compile_error().into();
437 }
438
439 let mut default = None;
440 let mut env_key = if env_value_default {
441 Some(name.to_uppercase())
442 } else {
443 None
444 };
445
446 for attr in field.attrs.iter() {
447 match &attr.meta {
448 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
449 let literal = match &value.value {
450 syn::Expr::Lit(literal) => &literal.lit,
451 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
452 };
453 if let syn::Lit::Str(ref text) = literal {
454 desc.push_str(&text.value());
455 desc.push(' ');
456 }
457 },
458 syn::Meta::List(value) => if value.path.is_ident("arg") {
459 let nested = match attr.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated) {
460 Ok(nested) => nested,
461 Err(error) => {
462 let error = format!("arg attribute should be list of attributes: {error}");
463 return syn::Error::new_spanned(value, error).to_compile_error().into();
464 }
465 };
466
467 for value_attr in nested {
468 match value_attr {
469 syn::Meta::Path(value_attr) => if value_attr.is_ident("short") {
470 short = Some(format!("{}", name.chars().next().unwrap()).to_lowercase());
471 } else if value_attr.is_ident("long") {
472 long = Some(name.to_lowercase());
473 } else if value_attr.is_ident("default_value") {
474 default = Some(DEFAULT_INIT.to_owned());
475 } else if value_attr.is_ident("env_value") {
476 if env_key.is_none() {
477 env_key = Some(name.to_uppercase());
478 }
479 } else if value_attr.is_ident("required") {
480 required = true;
481 } else if value_attr.is_ident("sub") {
482 if typ == OptValueType::Value {
483 is_sub = true;
484 } else {
485 return syn::Error::new_spanned(value_attr, "Sub-command must be simple value").to_compile_error().into();
486 }
487 } else {
488 return syn::Error::new_spanned(&value_attr, UNKNOWN_ARG_ATTR).to_compile_error().into();
489 }
490 syn::Meta::NameValue(value_attr) => if value_attr.path.is_ident("short") {
491 let literal = match &value_attr.value {
492 syn::Expr::Lit(literal) => &literal.lit,
493 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
494 };
495
496 if let syn::Lit::Str(ref text) = literal {
497 let value_attr_text = text.value();
498
499 if value_attr_text.contains(ARG_INVALID_CHARS) {
500 return syn::Error::new_spanned(literal.clone(), ARG_NAME_SPACE_ERROR).to_compile_error().into();
501 }
502
503 short = Some(value_attr_text);
504 } else {
505 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
506 }
507 } else if value_attr.path.is_ident("long") {
508 let literal = match &value_attr.value {
509 syn::Expr::Lit(literal) => &literal.lit,
510 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
511 };
512
513 if let syn::Lit::Str(ref text) = literal {
514 let value_attr_text = text.value();
515
516 if value_attr_text.contains(ARG_INVALID_CHARS) {
517 return syn::Error::new_spanned(literal.clone(), ARG_NAME_SPACE_ERROR).to_compile_error().into();
518 }
519
520 long = Some(value_attr_text)
521 } else {
522 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
523 }
524 } else if value_attr.path.is_ident("default_value") {
525 let literal = match &value_attr.value {
526 syn::Expr::Lit(literal) => &literal.lit,
527 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
528 };
529
530 if let syn::Lit::Str(ref text) = literal {
531 default = Some(text.value());
532 } else {
533 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
534 }
535 } else if value_attr.path.is_ident("env_value") {
536 let literal = match &value_attr.value {
537 syn::Expr::Lit(literal) => &literal.lit,
538 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
539 };
540
541 if let syn::Lit::Str(ref text) = literal {
542 env_key = Some(text.value());
543 } else {
544 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
545 }
546 } else {
547 return syn::Error::new_spanned(value_attr.path.clone(), UNKNOWN_ARG_ATTR).to_compile_error().into();
548 }
549 _ => {
550 },
551 }
552 } },
554 _ => (),
555 }
556 }
557
558 desc.pop();
559
560 if required && default.is_some() {
561 return syn::Error::new_spanned(field.ident.clone(), "Marked as required, but default value is provided?").to_compile_error().into();
562 } else if is_optional && default.is_some() {
563 return syn::Error::new_spanned(field.ident.clone(), "Optional, but default value is provided?").to_compile_error().into();
564 } else if is_sub && is_optional {
565 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot be optional").to_compile_error().into();
566 } else if is_sub && default.is_some() {
567 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot have default value").to_compile_error().into();
568 } else if !required && !is_optional && default.is_none() {
569 default = Some(DEFAULT_INIT.to_owned());
570 }
571
572 if short.is_none() && long.is_none() {
573 if typ == OptValueType::MultiValue {
574 if multi_argument.is_some() {
575 return syn::Error::new_spanned(field.ident.clone(), "Second argument collection. There can be only one").to_compile_error().into();
576 } else if sub_command.is_some() {
577 return syn::Error::new_spanned(field.ident.clone(), "Multi-argument collection and sub-command are mutually exclusive").to_compile_error().into();
578 } else if env_key.is_some() {
579 return syn::Error::new_spanned(field.ident.clone(), "Multi-argument cannot be supplied with `env_value` parameter").to_compile_error().into();
580 }
581
582 multi_argument = Some(Argument {
583 field_name,
584 name,
585 desc,
586 required,
587 is_optional,
588 default,
589 env_key,
590 });
591
592 } else if is_sub {
593 if sub_command.is_some() {
594 return syn::Error::new_spanned(field.ident.clone(), "Second sub-command. There can be only one").to_compile_error().into();
595 } else if multi_argument.is_some() {
596 return syn::Error::new_spanned(field.ident.clone(), "Sub-command and multi-argument collection are mutually exclusive").to_compile_error().into();
597 } else if env_key.is_some() {
598 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot be supplied with `env_value` parameter").to_compile_error().into();
599 }
600
601 sub_command = Some(Argument {
602 field_name,
603 name,
604 desc,
605 required: true,
606 is_optional: false,
607 default: None,
608 env_key,
609 });
610 } else {
611 arguments.push(Argument {
612 field_name,
613 name,
614 desc,
615 required,
616 is_optional,
617 default,
618 env_key,
619 })
620 }
621 } else {
622 if OptValueType::Bool == typ && required {
624 return syn::Error::new_spanned(field.ident.clone(), INVALID_REQUIRED_BOOL).to_compile_error().into();
626 }
627
628 let long = match long {
629 Some(long) => long,
630 None => name.clone()
631 };
632
633 options.push(Opt {
634 arg: Argument {
635 field_name,
636 name,
637 desc,
638 required,
639 is_optional,
640 default,
641 env_key,
642 },
643 short,
644 long,
645 typ
646 })
647 }
648 }
649
650 let (impl_gen, type_gen, where_clause) = ast.generics.split_for_impl();
651
652 let help_msg = {
653 use std::io::Write;
654 use tabwriter::TabWriter;
655
656 let mut tw = TabWriter::new(vec![]);
657
658 let _ = write!(tw, "{}
659
660USAGE:", about_prog);
661
662 if !options.is_empty() {
663 let _ = write!(tw, " [OPTIONS]");
664 }
665
666 for argument in arguments.iter() {
667 let _ = if argument.required {
668 write!(tw, " <{}>", argument.name)
669 } else {
670 write!(tw, " [{}]", argument.name)
671 };
672 }
673
674 if let Some(argument) = multi_argument.as_ref() {
675 let _ = if argument.required {
676 write!(tw, " <{}>...", argument.name)
677 } else {
678 write!(tw, " [{}]...", argument.name)
679 };
680 } else if let Some(argument) = sub_command.as_ref() {
681 let _ = write!(tw, " <{}>", argument.name);
682 }
683
684 if !options.is_empty() {
685 let _ = write!(tw, "\n\nOPTIONS:\n");
686 }
687
688 for option in options.iter() {
689 let _ = write!(tw, "\t");
690 if let Some(short) = option.short.as_ref() {
691 let _ = write!(tw, "-{},", short);
692 }
693 let _ = write!(tw, "\t");
694
695 let _ = write!(tw, "--{}", option.long);
696
697 let _ = match option.typ {
698 OptValueType::MultiValue => write!(tw, " <{}>...", option.arg.name),
699 OptValueType::Value => write!(tw, " <{}>", option.arg.name),
700 _ => Ok(()),
701 };
702
703
704 let desc = option.arg.env_desc_fmt(&env_prefix);
705 let _ = writeln!(tw, "\t{desc}");
706 }
707
708 if !arguments.is_empty() || multi_argument.is_some() || sub_command.is_some() {
709 let _ = write!(tw, "\nARGS:\n");
710 }
711
712 for argument in arguments.iter() {
713 let arg_desc = argument.env_desc_fmt(&env_prefix);
714 let _ = if argument.required {
715 writeln!(tw, "\t<{}>\t{arg_desc}", argument.name)
716 } else {
717 writeln!(tw, "\t[{}]\t{arg_desc}", argument.name)
718 };
719 }
720
721 if let Some(argument) = multi_argument.as_ref() {
722 let arg_desc = argument.desc.trim();
723 let _ = writeln!(tw, "\t<{}>...\t{arg_desc}", argument.name);
724 } else if let Some(command) = sub_command.as_ref() {
725 let arg_desc = command.desc.trim();
726 let _ = writeln!(tw, "\t<{}>\t{arg_desc}", command.name);
727 }
728
729 let _ = tw.flush();
730
731 String::from_utf8(tw.into_inner().unwrap()).unwrap()
732 };
733
734 let mut result = String::new();
735 let _ = writeln!(result, "{} {} for {}{} {{", quote!(impl#impl_gen), PARSER_TRAIT, ast.ident, quote!(#type_gen #where_clause));
736 if infer_prog_name {
737 let _ = writeln!(result, "{}const HELP: &'static str = core::concat!({CONCAT_DEFAULT_PROG_NAME_ARGS}, \"\n\", \"{}\");", TAB, help_msg);
738 } else {
739 let _ = writeln!(result, "{}const HELP: &'static str = \"{}\";", TAB, help_msg);
740 }
741
742 let _ = writeln!(result, "{}fn from_args<'a, T: IntoIterator<Item = &'a str>>(_args_: T) -> Result<Self, arg::ParseKind<'a>> {{", TAB);
743
744 for option in options.iter() {
745 if option.arg.field_name == "_" {
746 continue;
747 }
748
749 let _ = match option.typ {
750 OptValueType::MultiValue => writeln!(result, "{0}{0}let mut {1} = Vec::new();", TAB, option.arg.field_name),
751 OptValueType::Bool => match &option.arg.env_key {
752 Some(env_key) => {
753 let _ = writeln!(result, "{0}{0}let mut {1} = if let Ok(_env_val_) = ::std::env::var(\"{env_prefix}{env_key}\") {{", TAB, option.arg.field_name);
754 let _ = writeln!(result, "{0}{0}{0}match {FROM_FN}(_env_val_.trim()) {{", TAB);
755 let _ = writeln!(result, "{0}{0}{0}{0}Ok(_env_val_) => _env_val_,", TAB);
756 let _ = writeln!(result, "{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", \"${env_prefix}{env_key}\"))),", TAB, option.arg.field_name);
757 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
758 let _ = writeln!(result, "{0}{0}}} else {{", TAB);
759 let _ = writeln!(result, "{0}{0}{0}false", TAB);
760 writeln!(result, "{0}{0}}};", TAB)
761 },
762 None => writeln!(result, "{0}{0}let mut {1} = false;", TAB, option.arg.field_name),
763 },
764 _ => writeln!(result, "{0}{0}let mut {1} = None;", TAB, option.arg.field_name),
765 };
766 }
767
768 for argument in arguments.iter() {
769 let _ = writeln!(result, "{0}{0}let mut {1} = None;", TAB, argument.field_name);
770 }
771
772 if let Some(argument) = multi_argument.as_ref() {
773 let _ = writeln!(result, "{0}{0}let mut {1} = Vec::new();", TAB, argument.field_name);
774 } else if let Some(command) = sub_command.as_ref() {
775 let _ = writeln!(result, "{0}{0}let mut {1} = None;", TAB, command.field_name);
776 }
777
778 let _ = writeln!(result, "{0}{0}let mut _args_ = _args_.into_iter();\n", TAB);
779 let _ = writeln!(result, "{0}{0}while let Some(_arg_) = _args_.next() {{", TAB);
780
781 let _ = writeln!(result, "{0}{0}{0}if let Some(_arg_) = _arg_.strip_prefix('-') {{", TAB);
783 let _ = writeln!(result, "{0}{0}{0}{0}match _arg_ {{", TAB);
784 let _ = writeln!(result, "{0}{0}{0}{0}{0}\"h\" | \"-help\" => return Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(Self::HELP))),", TAB);
785 let _ = writeln!(result, "{0}{0}{0}{0}{0}\"\" => (),", TAB);
786
787 for option in options.iter() {
788 if option.arg.field_name == "_" {
789 continue;
790 }
791
792 let _ = write!(result, "{0}{0}{0}{0}{0}", TAB);
793
794 if let Some(short) = option.short.as_ref() {
795 let _ = write!(result, "\"{}\" | ", short);
796 }
797
798 let _ = write!(result, "\"-{}\" => ", option.long);
799
800 let _ = match option.typ {
801 OptValueType::Help => panic!("Option Help is invalid here. Bug report it"),
802 OptValueType::Bool => write!(result, "{{ {0} = !{0}; continue }},", option.arg.field_name),
803 OptValueType::Value => write!(result, "match _args_.next() {{
804{0}{0}{0}{0}{0}{0}Some(_next_arg_) => match {1}(_next_arg_) {{
805{0}{0}{0}{0}{0}{0}{0}Ok(value) => {{ {2} = Some(value); continue }},
806{0}{0}{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidFlagValue(\"{3}\", _next_arg_))),
807{0}{0}{0}{0}{0}{0}}},
808{0}{0}{0}{0}{0}{0}None => return Err(arg::ParseKind::Top(arg::ParseError::MissingValue(\"{3}\"))),
809{0}{0}{0}{0}{0}}}", TAB, FROM_FN, option.arg.field_name, option.arg.name),
810 OptValueType::MultiValue => write!(result, "match _args_.next() {{
811{0}{0}{0}{0}{0}{0}Some(_next_arg_) => match {1}(_next_arg_) {{
812{0}{0}{0}{0}{0}{0}{0}Ok(value) => {{ {2}.push(value); continue }},
813{0}{0}{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidFlagValue(\"{3}\", _next_arg_))),
814{0}{0}{0}{0}{0}{0}}},
815{0}{0}{0}{0}{0}{0}None => return Err(arg::ParseKind::Top(arg::ParseError::MissingValue(\"{3}\"))),
816{0}{0}{0}{0}{0}}}", TAB, FROM_FN, option.arg.field_name, option.arg.name),
817 };
818 result.push('\n');
819 }
820 let _ = writeln!(result, "{0}{0}{0}{0}{0}_ => return Err(arg::ParseKind::Top(arg::ParseError::UnknownFlag(_arg_))),", TAB);
821
822 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
823 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
824 for (idx, arg) in arguments.iter().enumerate() {
826 if idx == 0 {
827 let _ = writeln!(result, "{0}{0}{0}if {1}.is_none() {{", TAB, arg.field_name);
828 } else {
829 let _ = writeln!(result, "{0}{0}{0}}} else if {1}.is_none() {{", TAB, arg.field_name);
830 }
831 let _ = writeln!(result, "{0}{0}{0}{0}match {1}(_arg_) {{", TAB, FROM_FN);
832 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {1} = Some(_res_),", TAB, arg.field_name);
833 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", _arg_))),", TAB, arg.field_name);
834 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
835 }
836 if !arguments.is_empty() {
838 let _ = writeln!(result, "{0}{0}{0}}} else {{", TAB);
839 }
840
841 if let Some(arg) = multi_argument.as_ref() {
842 let _ = writeln!(result, "{0}{0}{0}{0}match {1}(_arg_) {{", TAB, FROM_FN);
843 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {1}.push(_res_),", TAB, arg.field_name);
844 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", _arg_))),", TAB, arg.field_name);
845 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
846 } else if let Some(command) = sub_command.as_ref() {
847 let _ = writeln!(result, "{0}{0}{0}{0}match {1}::from_args(core::iter::once(_arg_).chain(_args_)) {{", TAB, PARSER_TRAIT);
848 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {{ {1} = Some(_res_); break; }},", TAB, command.field_name);
849 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(_, invalid_value))) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", invalid_value))),", TAB, command.field_name);
850 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(_)) => return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{1}\"))),", TAB, command.field_name);
851 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Sub(name, error)) => return Err(arg::ParseKind::Sub(name, error)),", TAB);
852 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
853 } else {
854 let _ = writeln!(result, "{0}{0}{0}{0} return Err(arg::ParseKind::Top(arg::ParseError::TooManyArgs));", TAB);
855 }
856 if !arguments.is_empty() {
858 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
859 let _ = writeln!(result, "{0}{0}}}", TAB);
860 } else {
861 let _ = writeln!(result, "{0}{0}}}", TAB);
862 }
863
864 for option in options.iter() {
866 if option.arg.field_name == "_" {
867 continue;
868 }
869
870 let env_init = option.arg.env_init_fmt(&env_prefix, &option.arg.field_name);
871 let _ = match option.typ {
872 OptValueType::MultiValue => {
873 if let Some(env_key) = option.arg.env_key.as_ref() {
874 let _ = writeln!(result, "\n{0}{0}if let Ok(_env_val_) = ::std::env::var(\"{env_prefix}{env_key}\") {{", TAB);
875 let _ = writeln!(result, "{0}{0}{0}for _env_val_ in _env_val_.split(',') {{", TAB);
876 let _ = writeln!(result, "{0}{0}{0}{0}{1}.push(match {FROM_FN}(_env_val_.trim()) {{ Ok(_env_val_) => {{ _env_val_ }}, Err(_) => {{ return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", \"${env_prefix}{env_key}\"))); }} }})", TAB, option.arg.field_name);
877 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
878 let _ = writeln!(result, "{0}{0}}}\n", TAB);
879 }
880 Ok(())
881 },
882 OptValueType::Bool => Ok(()),
883 _ => match option.arg.default {
884 Some(ref default) => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ {2} }};", TAB, option.arg.field_name, default),
885 None => match option.arg.is_optional {
886 true => if let Some(env_key) = option.arg.env_key.as_ref() {
887 writeln!(result, "{0}{0}if {1}.is_none() {{ {1} = ::std::env::var(\"{env_prefix}{env_key}\").ok().and_then(|value| {FROM_FN}(value.trim()).ok()); }}", TAB, option.arg.field_name)
888 } else {
889 Ok(())
890 },
891 false => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{2}\"))) }};", TAB, option.arg.field_name, option.arg.name),
892 },
893 },
894 };
895 }
896
897 for arg in arguments.iter() {
898 let env_init = arg.env_init_fmt(&env_prefix, &arg.field_name);
899 let _ = match arg.default {
900 Some(ref default) => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ {2} }};", TAB, arg.field_name, default),
901 None => match arg.is_optional {
902 true => Ok(()),
903 false => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{2}\"))) }};", TAB, arg.field_name, arg.name),
904 }
905 };
906 }
907
908 if let Some(command) = sub_command.as_ref() {
909 let _ = writeln!(result, "{0}{0}let {1} = match {1} {{", TAB, command.field_name);
910 let _ = writeln!(result, "{0}{0}{0}Some({1}) => {1},", TAB, command.field_name);
911 let _ = writeln!(result, "{0}{0}{0}None => match {1}::from_args([]) {{", TAB, PARSER_TRAIT);
913 let _ = writeln!(result, "{0}{0}{0}{0}Ok({1}) => {1},", TAB, command.field_name);
914 let _ = writeln!(result, "{0}{0}{0}{0}Err(error) => return Err(error),", TAB);
915 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
916 let _ = writeln!(result, "{0}{0}}};", TAB);
918 }
919
920 let _ = writeln!(result, "{0}{0}Ok(Self {{", TAB);
922
923 for option in options.iter() {
924 if option.arg.field_name == "_" {
925 continue;
926 }
927
928 let _ = if option.arg.is_optional && option.typ == OptValueType::Bool {
929 writeln!(result, "{0}{0}{0}{1}: Some({1}),", TAB, option.arg.field_name)
930 } else {
931 writeln!(result, "{0}{0}{0}{1},", TAB, option.arg.field_name)
932 };
933 }
934
935 for arg in arguments.iter() {
936 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
937 }
938
939 if let Some(arg) = multi_argument.as_ref() {
940 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
941 } else if let Some(arg) = sub_command.as_ref() {
942 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
943 }
944
945 let _ = writeln!(result, "{0}{0}}})", TAB);
946
947 let _ = writeln!(result, "{}}}", TAB);
949
950 let _ = writeln!(result, "}}");
951
952 if let Ok(val) = std::env::var("ARG_RS_PRINT_PARSER") {
953 match val.trim() {
954 "0" | "false" => (),
955 _ => println!("{result}"),
956 }
957 }
958 result.parse().expect("To parse generated code")
959}
960
961#[proc_macro_derive(Args, attributes(parser, arg))]
962pub fn parser_derive(input: TokenStream) -> TokenStream {
963 const INVALID_INPUT_TYPE: &str = "Unsupported parser input type. Expect: struct";
964 let ast: syn::DeriveInput = syn::parse(input).unwrap();
965
966 match ast.data {
967 syn::Data::Struct(ref data) => from_struct(&ast, data),
968 syn::Data::Enum(ref data) => from_enum(&ast, data),
969 _ => syn::Error::new_spanned(ast.ident, INVALID_INPUT_TYPE).to_compile_error().into(),
970 }
971}