1use std::env;
16
17use heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
18use proc_macro2::{self, Span, TokenStream};
19use quote::{format_ident, quote, quote_spanned, ToTokens};
20use syn::DeriveInput;
21use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Field, Ident, LitStr, Type, Variant};
22
23use crate::attr::{AttrKind, AttrValue, ClapAttr, MagicAttrName};
24use crate::utils::{extract_doc_comment, format_doc_comment, inner_type, is_simple_ty, Sp, Ty};
25
26pub(crate) const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
28
29pub(crate) const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
31
32#[derive(Clone)]
33pub(crate) struct Item {
34 name: Name,
35 casing: Sp<CasingStyle>,
36 env_casing: Sp<CasingStyle>,
37 ty: Option<Type>,
38 doc_comment: Vec<Method>,
39 methods: Vec<Method>,
40 deprecations: Vec<Deprecation>,
41 value_parser: Option<ValueParser>,
42 action: Option<Action>,
43 verbatim_doc_comment: bool,
44 force_long_help: bool,
45 next_display_order: Option<Method>,
46 next_help_heading: Option<Method>,
47 is_enum: bool,
48 is_positional: bool,
49 skip_group: bool,
50 group_id: Name,
51 group_methods: Vec<Method>,
52 kind: Sp<Kind>,
53}
54
55impl Item {
56 pub(crate) fn from_args_struct(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
57 let ident = input.ident.clone();
58 let span = input.ident.span();
59 let attrs = &input.attrs;
60 let argument_casing = Sp::new(DEFAULT_CASING, span);
61 let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
62 let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
63
64 let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
65 let parsed_attrs = ClapAttr::parse_all(attrs)?;
66 res.infer_kind(&parsed_attrs)?;
67 res.push_attrs(&parsed_attrs)?;
68 res.push_doc_comment(attrs, "about", Some("long_about"));
69
70 Ok(res)
71 }
72
73 pub(crate) fn from_subcommand_enum(
74 input: &DeriveInput,
75 name: Name,
76 ) -> Result<Self, syn::Error> {
77 let ident = input.ident.clone();
78 let span = input.ident.span();
79 let attrs = &input.attrs;
80 let argument_casing = Sp::new(DEFAULT_CASING, span);
81 let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
82 let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
83
84 let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
85 let parsed_attrs = ClapAttr::parse_all(attrs)?;
86 res.infer_kind(&parsed_attrs)?;
87 res.push_attrs(&parsed_attrs)?;
88 res.push_doc_comment(attrs, "about", Some("long_about"));
89
90 Ok(res)
91 }
92
93 pub(crate) fn from_value_enum(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
94 let ident = input.ident.clone();
95 let span = input.ident.span();
96 let attrs = &input.attrs;
97 let argument_casing = Sp::new(DEFAULT_CASING, span);
98 let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
99 let kind = Sp::new(Kind::Value, span);
100
101 let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
102 let parsed_attrs = ClapAttr::parse_all(attrs)?;
103 res.infer_kind(&parsed_attrs)?;
104 res.push_attrs(&parsed_attrs)?;
105 if res.has_explicit_methods() {
109 abort!(
110 res.methods[0].name.span(),
111 "{} doesn't exist for `ValueEnum` enums",
112 res.methods[0].name
113 );
114 }
115
116 Ok(res)
117 }
118
119 pub(crate) fn from_subcommand_variant(
120 variant: &Variant,
121 struct_casing: Sp<CasingStyle>,
122 env_casing: Sp<CasingStyle>,
123 ) -> Result<Self, syn::Error> {
124 let name = variant.ident.clone();
125 let ident = variant.ident.clone();
126 let span = variant.span();
127 let ty = match variant.fields {
128 syn::Fields::Unnamed(syn::FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
129 Ty::from_syn_ty(&unnamed[0].ty)
130 }
131 syn::Fields::Named(_) | syn::Fields::Unnamed(..) | syn::Fields::Unit => {
132 Sp::new(Ty::Other, span)
133 }
134 };
135 let kind = Sp::new(Kind::Command(ty), span);
136 let mut res = Self::new(
137 Name::Derived(name),
138 ident,
139 None,
140 struct_casing,
141 env_casing,
142 kind,
143 );
144 let parsed_attrs = ClapAttr::parse_all(&variant.attrs)?;
145 res.infer_kind(&parsed_attrs)?;
146 res.push_attrs(&parsed_attrs)?;
147 if matches!(&*res.kind, Kind::Command(_) | Kind::Subcommand(_)) {
148 res.push_doc_comment(&variant.attrs, "about", Some("long_about"));
149 }
150
151 match &*res.kind {
152 Kind::Flatten(_) => {
153 if res.has_explicit_methods() {
154 abort!(
155 res.kind.span(),
156 "methods are not allowed for flattened entry"
157 );
158 }
159 }
160
161 Kind::Subcommand(_)
162 | Kind::ExternalSubcommand
163 | Kind::FromGlobal(_)
164 | Kind::Skip(_, _)
165 | Kind::Command(_)
166 | Kind::Value
167 | Kind::Arg(_) => (),
168 }
169
170 Ok(res)
171 }
172
173 pub(crate) fn from_value_enum_variant(
174 variant: &Variant,
175 argument_casing: Sp<CasingStyle>,
176 env_casing: Sp<CasingStyle>,
177 ) -> Result<Self, syn::Error> {
178 let ident = variant.ident.clone();
179 let span = variant.span();
180 let kind = Sp::new(Kind::Value, span);
181 let mut res = Self::new(
182 Name::Derived(variant.ident.clone()),
183 ident,
184 None,
185 argument_casing,
186 env_casing,
187 kind,
188 );
189 let parsed_attrs = ClapAttr::parse_all(&variant.attrs)?;
190 res.infer_kind(&parsed_attrs)?;
191 res.push_attrs(&parsed_attrs)?;
192 if matches!(&*res.kind, Kind::Value) {
193 res.push_doc_comment(&variant.attrs, "help", None);
194 }
195
196 Ok(res)
197 }
198
199 pub(crate) fn from_args_field(
200 field: &Field,
201 struct_casing: Sp<CasingStyle>,
202 env_casing: Sp<CasingStyle>,
203 ) -> Result<Self, syn::Error> {
204 let name = field.ident.clone().unwrap();
205 let ident = field.ident.clone().unwrap();
206 let span = field.span();
207 let ty = Ty::from_syn_ty(&field.ty);
208 let kind = Sp::new(Kind::Arg(ty), span);
209 let mut res = Self::new(
210 Name::Derived(name),
211 ident,
212 Some(field.ty.clone()),
213 struct_casing,
214 env_casing,
215 kind,
216 );
217 let parsed_attrs = ClapAttr::parse_all(&field.attrs)?;
218 res.infer_kind(&parsed_attrs)?;
219 res.push_attrs(&parsed_attrs)?;
220 if matches!(&*res.kind, Kind::Arg(_)) {
221 res.push_doc_comment(&field.attrs, "help", Some("long_help"));
222 }
223
224 match &*res.kind {
225 Kind::Flatten(_) => {
226 if res.has_explicit_methods() {
227 abort!(
228 res.kind.span(),
229 "methods are not allowed for flattened entry"
230 );
231 }
232 }
233
234 Kind::Subcommand(_) => {
235 if res.has_explicit_methods() {
236 abort!(
237 res.kind.span(),
238 "methods in attributes are not allowed for subcommand"
239 );
240 }
241 }
242 Kind::Skip(_, _)
243 | Kind::FromGlobal(_)
244 | Kind::Arg(_)
245 | Kind::Command(_)
246 | Kind::Value
247 | Kind::ExternalSubcommand => {}
248 }
249
250 Ok(res)
251 }
252
253 fn new(
254 name: Name,
255 ident: Ident,
256 ty: Option<Type>,
257 casing: Sp<CasingStyle>,
258 env_casing: Sp<CasingStyle>,
259 kind: Sp<Kind>,
260 ) -> Self {
261 let group_id = Name::Derived(ident);
262 Self {
263 name,
264 ty,
265 casing,
266 env_casing,
267 doc_comment: vec![],
268 methods: vec![],
269 deprecations: vec![],
270 value_parser: None,
271 action: None,
272 verbatim_doc_comment: false,
273 force_long_help: false,
274 next_display_order: None,
275 next_help_heading: None,
276 is_enum: false,
277 is_positional: true,
278 skip_group: false,
279 group_id,
280 group_methods: vec![],
281 kind,
282 }
283 }
284
285 fn push_method(&mut self, kind: AttrKind, name: Ident, arg: impl ToTokens) {
286 self.push_method_(kind, name, arg.to_token_stream());
287 }
288
289 fn push_method_(&mut self, kind: AttrKind, name: Ident, arg: TokenStream) {
290 if name == "id" {
291 match kind {
292 AttrKind::Command | AttrKind::Value => {
293 self.deprecations.push(Deprecation {
294 span: name.span(),
295 id: "id_is_only_for_arg",
296 version: "4.0.0",
297 description: format!(
298 "`#[{}(id)] was allowed by mistake, instead use `#[{}(name)]`",
299 kind.as_str(),
300 kind.as_str()
301 ),
302 });
303 self.name = Name::Assigned(arg);
304 }
305 AttrKind::Group => {
306 self.group_id = Name::Assigned(arg);
307 }
308 AttrKind::Arg | AttrKind::Clap | AttrKind::StructOpt => {
309 self.name = Name::Assigned(arg);
310 }
311 }
312 } else if name == "name" {
313 match kind {
314 AttrKind::Arg => {
315 self.deprecations.push(Deprecation {
316 span: name.span(),
317 id: "id_is_only_for_arg",
318 version: "4.0.0",
319 description: format!(
320 "`#[{}(name)] was allowed by mistake, instead use `#[{}(id)]` or `#[{}(value_name)]`",
321 kind.as_str(),
322 kind.as_str(),
323 kind.as_str()
324 ),
325 });
326 self.name = Name::Assigned(arg);
327 }
328 AttrKind::Group => self.group_methods.push(Method::new(name, arg)),
329 AttrKind::Command | AttrKind::Value | AttrKind::Clap | AttrKind::StructOpt => {
330 self.name = Name::Assigned(arg);
331 }
332 }
333 } else if name == "value_parser" {
334 self.value_parser = Some(ValueParser::Explicit(Method::new(name, arg)));
335 } else if name == "action" {
336 self.action = Some(Action::Explicit(Method::new(name, arg)));
337 } else {
338 if name == "short" || name == "long" {
339 self.is_positional = false;
340 }
341 match kind {
342 AttrKind::Group => self.group_methods.push(Method::new(name, arg)),
343 _ => self.methods.push(Method::new(name, arg)),
344 };
345 }
346 }
347
348 fn infer_kind(&mut self, attrs: &[ClapAttr]) -> Result<(), syn::Error> {
349 for attr in attrs {
350 if let Some(AttrValue::Call(_)) = &attr.value {
351 continue;
352 }
353
354 let actual_attr_kind = *attr.kind.get();
355 let kind = match &attr.magic {
356 Some(MagicAttrName::FromGlobal) => {
357 if attr.value.is_some() {
358 let expr = attr.value_or_abort()?;
359 abort!(expr, "attribute `{}` does not accept a value", attr.name);
360 }
361 let ty = self
362 .kind()
363 .ty()
364 .cloned()
365 .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
366 let kind = Sp::new(Kind::FromGlobal(ty), attr.name.span());
367 Some(kind)
368 }
369 Some(MagicAttrName::Subcommand) if attr.value.is_none() => {
370 if attr.value.is_some() {
371 let expr = attr.value_or_abort()?;
372 abort!(expr, "attribute `{}` does not accept a value", attr.name);
373 }
374 let ty = self
375 .kind()
376 .ty()
377 .cloned()
378 .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
379 let kind = Sp::new(Kind::Subcommand(ty), attr.name.span());
380 Some(kind)
381 }
382 Some(MagicAttrName::ExternalSubcommand) if attr.value.is_none() => {
383 if attr.value.is_some() {
384 let expr = attr.value_or_abort()?;
385 abort!(expr, "attribute `{}` does not accept a value", attr.name);
386 }
387 let kind = Sp::new(Kind::ExternalSubcommand, attr.name.span());
388 Some(kind)
389 }
390 Some(MagicAttrName::Flatten) if attr.value.is_none() => {
391 if attr.value.is_some() {
392 let expr = attr.value_or_abort()?;
393 abort!(expr, "attribute `{}` does not accept a value", attr.name);
394 }
395 let ty = self
396 .kind()
397 .ty()
398 .cloned()
399 .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
400 let kind = Sp::new(Kind::Flatten(ty), attr.name.span());
401 Some(kind)
402 }
403 Some(MagicAttrName::Skip) if actual_attr_kind != AttrKind::Group => {
404 let expr = attr.value.clone();
405 let kind = Sp::new(Kind::Skip(expr, self.kind.attr_kind()), attr.name.span());
406 Some(kind)
407 }
408 _ => None,
409 };
410
411 if let Some(kind) = kind {
412 self.set_kind(kind)?;
413 }
414 }
415
416 Ok(())
417 }
418
419 fn push_attrs(&mut self, attrs: &[ClapAttr]) -> Result<(), syn::Error> {
420 for attr in attrs {
421 let actual_attr_kind = *attr.kind.get();
422 let expected_attr_kind = self.kind.attr_kind();
423 match (actual_attr_kind, expected_attr_kind) {
424 (AttrKind::Clap, _) | (AttrKind::StructOpt, _) => {
425 self.deprecations.push(Deprecation::attribute(
426 "4.0.0",
427 actual_attr_kind,
428 expected_attr_kind,
429 attr.kind.span(),
430 ));
431 }
432
433 (AttrKind::Group, AttrKind::Command) => {}
434
435 _ if attr.kind != expected_attr_kind => {
436 abort!(
437 attr.kind.span(),
438 "Expected `{}` attribute instead of `{}`",
439 expected_attr_kind.as_str(),
440 actual_attr_kind.as_str()
441 );
442 }
443
444 _ => {}
445 }
446
447 if let Some(AttrValue::Call(tokens)) = &attr.value {
448 self.push_method(*attr.kind.get(), attr.name.clone(), quote!(#(#tokens),*));
450 continue;
451 }
452
453 match &attr.magic {
454 Some(MagicAttrName::Short) if attr.value.is_none() => {
455 assert_attr_kind(attr, &[AttrKind::Arg])?;
456
457 self.push_method(
458 *attr.kind.get(),
459 attr.name.clone(),
460 self.name.clone().translate_char(*self.casing),
461 );
462 }
463
464 Some(MagicAttrName::Long) if attr.value.is_none() => {
465 assert_attr_kind(attr, &[AttrKind::Arg])?;
466
467 self.push_method(*attr.kind.get(), attr.name.clone(), self.name.clone().translate(*self.casing));
468 }
469
470 Some(MagicAttrName::ValueParser) if attr.value.is_none() => {
471 assert_attr_kind(attr, &[AttrKind::Arg])?;
472
473 self.deprecations.push(Deprecation {
474 span: attr.name.span(),
475 id: "bare_value_parser",
476 version: "4.0.0",
477 description: "`#[arg(value_parser)]` is now the default and is no longer needed`".to_owned(),
478 });
479 self.value_parser = Some(ValueParser::Implicit(attr.name.clone()));
480 }
481
482 Some(MagicAttrName::Action) if attr.value.is_none() => {
483 assert_attr_kind(attr, &[AttrKind::Arg])?;
484
485 self.deprecations.push(Deprecation {
486 span: attr.name.span(),
487 id: "bare_action",
488 version: "4.0.0",
489 description: "`#[arg(action)]` is now the default and is no longer needed`".to_owned(),
490 });
491 self.action = Some(Action::Implicit(attr.name.clone()));
492 }
493
494 Some(MagicAttrName::Env) if attr.value.is_none() => {
495 assert_attr_kind(attr, &[AttrKind::Arg])?;
496
497 self.push_method(
498 *attr.kind.get(),
499 attr.name.clone(),
500 self.name.clone().translate(*self.env_casing),
501 );
502 }
503
504 Some(MagicAttrName::ValueEnum) if attr.value.is_none() => {
505 assert_attr_kind(attr, &[AttrKind::Arg])?;
506
507 self.is_enum = true;
508 }
509
510 Some(MagicAttrName::VerbatimDocComment) if attr.value.is_none() => {
511 self.verbatim_doc_comment = true;
512 }
513
514 Some(MagicAttrName::About) if attr.value.is_none() => {
515 assert_attr_kind(attr, &[AttrKind::Command])?;
516
517 if let Some(method) =
518 Method::from_env(attr.name.clone(), "CARGO_PKG_DESCRIPTION")?
519 {
520 self.methods.push(method);
521 }
522 }
523
524 Some(MagicAttrName::LongAbout) if attr.value.is_none() => {
525 assert_attr_kind(attr, &[AttrKind::Command])?;
526
527 self.force_long_help = true;
528 }
529
530 Some(MagicAttrName::LongHelp) if attr.value.is_none() => {
531 assert_attr_kind(attr, &[AttrKind::Arg])?;
532
533 self.force_long_help = true;
534 }
535
536 Some(MagicAttrName::Author) if attr.value.is_none() => {
537 assert_attr_kind(attr, &[AttrKind::Command])?;
538
539 if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_AUTHORS")? {
540 self.methods.push(method);
541 }
542 }
543
544 Some(MagicAttrName::Version) if attr.value.is_none() => {
545 assert_attr_kind(attr, &[AttrKind::Command])?;
546
547 if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_VERSION")? {
548 self.methods.push(method);
549 }
550 }
551
552 Some(MagicAttrName::DefaultValueT) => {
553 assert_attr_kind(attr, &[AttrKind::Arg])?;
554
555 let ty = if let Some(ty) = self.ty.as_ref() {
556 ty
557 } else {
558 abort!(
559 attr.name.clone(),
560 "#[arg(default_value_t)] (without an argument) can be used \
561 only on field level\n\n= note: {note}\n\n",
562
563 note = "see \
564 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
565 };
566
567 let val = if let Some(expr) = &attr.value {
568 quote!(#expr)
569 } else {
570 quote!(<#ty as ::std::default::Default>::default())
571 };
572
573 let val = if attrs
574 .iter()
575 .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
576 {
577 quote_spanned!(attr.name.span()=> {
578 static DEFAULT_VALUE: ::std::sync::OnceLock<String> = ::std::sync::OnceLock::new();
579 let s = DEFAULT_VALUE.get_or_init(|| {
580 let val: #ty = #val;
581 clap::ValueEnum::to_possible_value(&val).unwrap().get_name().to_owned()
582 });
583 let s: &'static str = &*s;
584 s
585 })
586 } else {
587 quote_spanned!(attr.name.span()=> {
588 static DEFAULT_VALUE: ::std::sync::OnceLock<String> = ::std::sync::OnceLock::new();
589 let s = DEFAULT_VALUE.get_or_init(|| {
590 let val: #ty = #val;
591 ::std::string::ToString::to_string(&val)
592 });
593 let s: &'static str = &*s;
594 s
595 })
596 };
597
598 let raw_ident = Ident::new("default_value", attr.name.span());
599 self.methods.push(Method::new(raw_ident, val));
600 }
601
602 Some(MagicAttrName::DefaultValuesT) => {
603 assert_attr_kind(attr, &[AttrKind::Arg])?;
604
605 let ty = if let Some(ty) = self.ty.as_ref() {
606 ty
607 } else {
608 abort!(
609 attr.name.clone(),
610 "#[arg(default_values_t)] (without an argument) can be used \
611 only on field level\n\n= note: {note}\n\n",
612
613 note = "see \
614 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
615 };
616 let expr = attr.value_or_abort()?;
617
618 let container_type = Ty::from_syn_ty(ty);
619 if *container_type != Ty::Vec {
620 abort!(
621 attr.name.clone(),
622 "#[arg(default_values_t)] can be used only on Vec types\n\n= note: {note}\n\n",
623
624 note = "see \
625 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
626 }
627 let inner_type = inner_type(ty);
628
629 let val = if attrs
632 .iter()
633 .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
634 {
635 quote_spanned!(attr.name.span()=> {
636 {
637 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=String>
638 where
639 T: ::std::borrow::Borrow<#inner_type>
640 {
641 iterable
642 .into_iter()
643 .map(|val| {
644 clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name().to_owned()
645 })
646 }
647
648 static DEFAULT_STRINGS: ::std::sync::OnceLock<Vec<String>> = ::std::sync::OnceLock::new();
649 static DEFAULT_VALUES: ::std::sync::OnceLock<Vec<&str>> = ::std::sync::OnceLock::new();
650 DEFAULT_VALUES.get_or_init(|| {
651 DEFAULT_STRINGS.get_or_init(|| iter_to_vals(#expr).collect()).iter().map(::std::string::String::as_str).collect()
652 }).iter().copied()
653 }
654 })
655 } else {
656 quote_spanned!(attr.name.span()=> {
657 {
658 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=String>
659 where
660 T: ::std::borrow::Borrow<#inner_type>
661 {
662 iterable.into_iter().map(|val| val.borrow().to_string())
663 }
664
665 static DEFAULT_STRINGS: ::std::sync::OnceLock<Vec<String>> = ::std::sync::OnceLock::new();
666 static DEFAULT_VALUES: ::std::sync::OnceLock<Vec<&str>> = ::std::sync::OnceLock::new();
667 DEFAULT_VALUES.get_or_init(|| {
668 DEFAULT_STRINGS.get_or_init(|| iter_to_vals(#expr).collect()).iter().map(::std::string::String::as_str).collect()
669 }).iter().copied()
670 }
671 })
672 };
673
674 self.methods.push(Method::new(
675 Ident::new("default_values", attr.name.span()),
676 val,
677 ));
678 }
679
680 Some(MagicAttrName::DefaultValueOsT) => {
681 assert_attr_kind(attr, &[AttrKind::Arg])?;
682
683 let ty = if let Some(ty) = self.ty.as_ref() {
684 ty
685 } else {
686 abort!(
687 attr.name.clone(),
688 "#[arg(default_value_os_t)] (without an argument) can be used \
689 only on field level\n\n= note: {note}\n\n",
690
691 note = "see \
692 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
693 };
694
695 let val = if let Some(expr) = &attr.value {
696 quote!(#expr)
697 } else {
698 quote!(<#ty as ::std::default::Default>::default())
699 };
700
701 let val = if attrs
702 .iter()
703 .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
704 {
705 quote_spanned!(attr.name.span()=> {
706 static DEFAULT_VALUE: ::std::sync::OnceLock<String> = ::std::sync::OnceLock::new();
707 let s = DEFAULT_VALUE.get_or_init(|| {
708 let val: #ty = #val;
709 clap::ValueEnum::to_possible_value(&val).unwrap().get_name().to_owned()
710 });
711 let s: &'static str = &*s;
712 s
713 })
714 } else {
715 quote_spanned!(attr.name.span()=> {
716 static DEFAULT_VALUE: ::std::sync::OnceLock<::std::ffi::OsString> = ::std::sync::OnceLock::new();
717 let s = DEFAULT_VALUE.get_or_init(|| {
718 let val: #ty = #val;
719 ::std::ffi::OsString::from(val)
720 });
721 let s: &'static ::std::ffi::OsStr = &*s;
722 s
723 })
724 };
725
726 let raw_ident = Ident::new("default_value", attr.name.span());
727 self.methods.push(Method::new(raw_ident, val));
728 }
729
730 Some(MagicAttrName::DefaultValuesOsT) => {
731 assert_attr_kind(attr, &[AttrKind::Arg])?;
732
733 let ty = if let Some(ty) = self.ty.as_ref() {
734 ty
735 } else {
736 abort!(
737 attr.name.clone(),
738 "#[arg(default_values_os_t)] (without an argument) can be used \
739 only on field level\n\n= note: {note}\n\n",
740
741 note = "see \
742 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
743 };
744 let expr = attr.value_or_abort()?;
745
746 let container_type = Ty::from_syn_ty(ty);
747 if *container_type != Ty::Vec {
748 abort!(
749 attr.name.clone(),
750 "#[arg(default_values_os_t)] can be used only on Vec types\n\n= note: {note}\n\n",
751
752 note = "see \
753 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
754 }
755 let inner_type = inner_type(ty);
756
757 let val = if attrs
760 .iter()
761 .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
762 {
763 quote_spanned!(attr.name.span()=> {
764 {
765 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=::std::ffi::OsString>
766 where
767 T: ::std::borrow::Borrow<#inner_type>
768 {
769 iterable
770 .into_iter()
771 .map(|val| {
772 clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name().to_owned().into()
773 })
774 }
775
776 static DEFAULT_STRINGS: ::std::sync::OnceLock<Vec<::std::ffi::OsString>> = ::std::sync::OnceLock::new();
777 static DEFAULT_VALUES: ::std::sync::OnceLock<Vec<&::std::ffi::OsStr>> = ::std::sync::OnceLock::new();
778 DEFAULT_VALUES.get_or_init(|| {
779 DEFAULT_STRINGS.get_or_init(|| iter_to_vals(#expr).collect()).iter().map(::std::ffi::OsString::as_os_str).collect()
780 }).iter().copied()
781 }
782 })
783 } else {
784 quote_spanned!(attr.name.span()=> {
785 {
786 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=::std::ffi::OsString>
787 where
788 T: ::std::borrow::Borrow<#inner_type>
789 {
790 iterable.into_iter().map(|val| val.borrow().into())
791 }
792
793 static DEFAULT_STRINGS: ::std::sync::OnceLock<Vec<::std::ffi::OsString>> = ::std::sync::OnceLock::new();
794 static DEFAULT_VALUES: ::std::sync::OnceLock<Vec<&::std::ffi::OsStr>> = ::std::sync::OnceLock::new();
795 DEFAULT_VALUES.get_or_init(|| {
796 DEFAULT_STRINGS.get_or_init(|| iter_to_vals(#expr).collect()).iter().map(::std::ffi::OsString::as_os_str).collect()
797 }).iter().copied()
798 }
799 })
800 };
801
802 self.methods.push(Method::new(
803 Ident::new("default_values", attr.name.span()),
804 val,
805 ));
806 }
807
808 Some(MagicAttrName::NextDisplayOrder) => {
809 assert_attr_kind(attr, &[AttrKind::Command])?;
810
811 let expr = attr.value_or_abort()?;
812 self.next_display_order = Some(Method::new(attr.name.clone(), quote!(#expr)));
813 }
814
815 Some(MagicAttrName::NextHelpHeading) => {
816 assert_attr_kind(attr, &[AttrKind::Command])?;
817
818 let expr = attr.value_or_abort()?;
819 self.next_help_heading = Some(Method::new(attr.name.clone(), quote!(#expr)));
820 }
821
822 Some(MagicAttrName::RenameAll) => {
823 let lit = attr.lit_str_or_abort()?;
824 self.casing = CasingStyle::from_lit(lit)?;
825 }
826
827 Some(MagicAttrName::RenameAllEnv) => {
828 assert_attr_kind(attr, &[AttrKind::Command, AttrKind::Arg])?;
829
830 let lit = attr.lit_str_or_abort()?;
831 self.env_casing = CasingStyle::from_lit(lit)?;
832 }
833
834 Some(MagicAttrName::Skip) if actual_attr_kind == AttrKind::Group => {
835 self.skip_group = true;
836 }
837
838 None
839 | Some(MagicAttrName::Short)
841 | Some(MagicAttrName::Long)
842 | Some(MagicAttrName::Env)
843 | Some(MagicAttrName::About)
844 | Some(MagicAttrName::LongAbout)
845 | Some(MagicAttrName::LongHelp)
846 | Some(MagicAttrName::Author)
847 | Some(MagicAttrName::Version)
848 => {
849 let expr = attr.value_or_abort()?;
850 self.push_method(*attr.kind.get(), attr.name.clone(), expr);
851 }
852
853 Some(MagicAttrName::ValueParser) | Some(MagicAttrName::Action) => {
855 let expr = attr.value_or_abort()?;
856 self.push_method(*attr.kind.get(), attr.name.clone(), expr);
857 }
858
859 Some(MagicAttrName::ValueEnum)
861 | Some(MagicAttrName::VerbatimDocComment) => {
862 let expr = attr.value_or_abort()?;
863 abort!(expr, "attribute `{}` does not accept a value", attr.name);
864 }
865
866 Some(MagicAttrName::FromGlobal)
868 | Some(MagicAttrName::Subcommand)
869 | Some(MagicAttrName::ExternalSubcommand)
870 | Some(MagicAttrName::Flatten)
871 | Some(MagicAttrName::Skip) => {
872 }
873 }
874 }
875
876 if self.has_explicit_methods() {
877 if let Kind::Skip(_, attr) = &*self.kind {
878 abort!(
879 self.methods[0].name.span(),
880 "`{}` cannot be used with `#[{}(skip)]",
881 self.methods[0].name,
882 attr.as_str(),
883 );
884 }
885 if let Kind::FromGlobal(_) = &*self.kind {
886 abort!(
887 self.methods[0].name.span(),
888 "`{}` cannot be used with `#[arg(from_global)]",
889 self.methods[0].name,
890 );
891 }
892 }
893
894 Ok(())
895 }
896
897 fn push_doc_comment(&mut self, attrs: &[Attribute], short_name: &str, long_name: Option<&str>) {
898 let lines = extract_doc_comment(attrs);
899
900 if !lines.is_empty() {
901 let (short_help, long_help) =
902 format_doc_comment(&lines, !self.verbatim_doc_comment, self.force_long_help);
903 let short_name = format_ident!("{short_name}");
904 let short = Method::new(
905 short_name,
906 short_help
907 .map(|h| quote!(#h))
908 .unwrap_or_else(|| quote!(None)),
909 );
910 self.doc_comment.push(short);
911 if let Some(long_name) = long_name {
912 let long_name = format_ident!("{long_name}");
913 let long = Method::new(
914 long_name,
915 long_help
916 .map(|h| quote!(#h))
917 .unwrap_or_else(|| quote!(None)),
918 );
919 self.doc_comment.push(long);
920 }
921 }
922 }
923
924 fn set_kind(&mut self, kind: Sp<Kind>) -> Result<(), syn::Error> {
925 match (self.kind.get(), kind.get()) {
926 (Kind::Arg(_), Kind::FromGlobal(_))
927 | (Kind::Arg(_), Kind::Subcommand(_))
928 | (Kind::Arg(_), Kind::Flatten(_))
929 | (Kind::Arg(_), Kind::Skip(_, _))
930 | (Kind::Command(_), Kind::Subcommand(_))
931 | (Kind::Command(_), Kind::Flatten(_))
932 | (Kind::Command(_), Kind::Skip(_, _))
933 | (Kind::Command(_), Kind::ExternalSubcommand)
934 | (Kind::Value, Kind::Skip(_, _)) => {
935 self.kind = kind;
936 }
937
938 (_, _) => {
939 let old = self.kind.name();
940 let new = kind.name();
941 abort!(kind.span(), "`{new}` cannot be used with `{old}`");
942 }
943 }
944 Ok(())
945 }
946
947 pub(crate) fn find_default_method(&self) -> Option<&Method> {
948 self.methods
949 .iter()
950 .find(|m| m.name == "default_value" || m.name == "default_value_os")
951 }
952
953 pub(crate) fn initial_top_level_methods(&self) -> TokenStream {
955 let next_display_order = self.next_display_order.as_ref().into_iter();
956 let next_help_heading = self.next_help_heading.as_ref().into_iter();
957 quote!(
958 #(#next_display_order)*
959 #(#next_help_heading)*
960 )
961 }
962
963 pub(crate) fn final_top_level_methods(&self) -> TokenStream {
964 let methods = &self.methods;
965 let doc_comment = &self.doc_comment;
966
967 quote!( #(#doc_comment)* #(#methods)*)
968 }
969
970 pub(crate) fn field_methods(&self) -> TokenStream {
972 let methods = &self.methods;
973 let doc_comment = &self.doc_comment;
974 quote!( #(#doc_comment)* #(#methods)* )
975 }
976
977 pub(crate) fn group_id(&self) -> &Name {
978 &self.group_id
979 }
980
981 pub(crate) fn group_methods(&self) -> TokenStream {
982 let group_methods = &self.group_methods;
983 quote!( #(#group_methods)* )
984 }
985
986 pub(crate) fn deprecations(&self) -> TokenStream {
987 let deprecations = &self.deprecations;
988 quote!( #(#deprecations)* )
989 }
990
991 pub(crate) fn next_display_order(&self) -> TokenStream {
992 let next_display_order = self.next_display_order.as_ref().into_iter();
993 quote!( #(#next_display_order)* )
994 }
995
996 pub(crate) fn next_help_heading(&self) -> TokenStream {
997 let next_help_heading = self.next_help_heading.as_ref().into_iter();
998 quote!( #(#next_help_heading)* )
999 }
1000
1001 pub(crate) fn id(&self) -> &Name {
1002 &self.name
1003 }
1004
1005 pub(crate) fn cased_name(&self) -> TokenStream {
1006 self.name.clone().translate(*self.casing)
1007 }
1008
1009 pub(crate) fn value_name(&self) -> TokenStream {
1010 self.name.clone().translate(CasingStyle::ScreamingSnake)
1011 }
1012
1013 pub(crate) fn value_parser(&self, field_type: &Type) -> Method {
1014 self.value_parser
1015 .clone()
1016 .map(|p| {
1017 let inner_type = inner_type(field_type);
1018 p.resolve(inner_type)
1019 })
1020 .unwrap_or_else(|| {
1021 let inner_type = inner_type(field_type);
1022 if let Some(action) = self.action.as_ref() {
1023 let span = action.span();
1024 default_value_parser(inner_type, span)
1025 } else {
1026 let span = self
1027 .action
1028 .as_ref()
1029 .map(|a| a.span())
1030 .unwrap_or_else(|| self.kind.span());
1031 default_value_parser(inner_type, span)
1032 }
1033 })
1034 }
1035
1036 pub(crate) fn action(&self, field_type: &Type) -> Method {
1037 self.action
1038 .clone()
1039 .map(|p| p.resolve(field_type))
1040 .unwrap_or_else(|| {
1041 if let Some(value_parser) = self.value_parser.as_ref() {
1042 let span = value_parser.span();
1043 default_action(field_type, span)
1044 } else {
1045 let span = self
1046 .value_parser
1047 .as_ref()
1048 .map(|a| a.span())
1049 .unwrap_or_else(|| self.kind.span());
1050 default_action(field_type, span)
1051 }
1052 })
1053 }
1054
1055 pub(crate) fn kind(&self) -> Sp<Kind> {
1056 self.kind.clone()
1057 }
1058
1059 pub(crate) fn is_positional(&self) -> bool {
1060 self.is_positional
1061 }
1062
1063 pub(crate) fn casing(&self) -> Sp<CasingStyle> {
1064 self.casing
1065 }
1066
1067 pub(crate) fn env_casing(&self) -> Sp<CasingStyle> {
1068 self.env_casing
1069 }
1070
1071 pub(crate) fn has_explicit_methods(&self) -> bool {
1072 self.methods
1073 .iter()
1074 .any(|m| m.name != "help" && m.name != "long_help")
1075 }
1076
1077 pub(crate) fn skip_group(&self) -> bool {
1078 self.skip_group
1079 }
1080}
1081
1082#[derive(Clone)]
1083enum ValueParser {
1084 Explicit(Method),
1085 Implicit(Ident),
1086}
1087
1088impl ValueParser {
1089 fn resolve(self, _inner_type: &Type) -> Method {
1090 match self {
1091 Self::Explicit(method) => method,
1092 Self::Implicit(ident) => default_value_parser(_inner_type, ident.span()),
1093 }
1094 }
1095
1096 fn span(&self) -> Span {
1097 match self {
1098 Self::Explicit(method) => method.name.span(),
1099 Self::Implicit(ident) => ident.span(),
1100 }
1101 }
1102}
1103
1104fn default_value_parser(inner_type: &Type, span: Span) -> Method {
1105 let func = Ident::new("value_parser", span);
1106 Method::new(
1107 func,
1108 quote_spanned! { span=>
1109 clap::value_parser!(#inner_type)
1110 },
1111 )
1112}
1113
1114#[derive(Clone)]
1115pub(crate) enum Action {
1116 Explicit(Method),
1117 Implicit(Ident),
1118}
1119
1120impl Action {
1121 pub(crate) fn resolve(self, _field_type: &Type) -> Method {
1122 match self {
1123 Self::Explicit(method) => method,
1124 Self::Implicit(ident) => default_action(_field_type, ident.span()),
1125 }
1126 }
1127
1128 pub(crate) fn span(&self) -> Span {
1129 match self {
1130 Self::Explicit(method) => method.name.span(),
1131 Self::Implicit(ident) => ident.span(),
1132 }
1133 }
1134}
1135
1136fn default_action(field_type: &Type, span: Span) -> Method {
1137 let ty = Ty::from_syn_ty(field_type);
1138 let args = match *ty {
1139 Ty::Vec | Ty::OptionVec | Ty::VecVec | Ty::OptionVecVec => {
1140 quote_spanned! { span=>
1141 clap::ArgAction::Append
1142 }
1143 }
1144 Ty::Option | Ty::OptionOption => {
1145 quote_spanned! { span=>
1146 clap::ArgAction::Set
1147 }
1148 }
1149 _ => {
1150 if is_simple_ty(field_type, "bool") {
1151 quote_spanned! { span=>
1152 clap::ArgAction::SetTrue
1153 }
1154 } else {
1155 quote_spanned! { span=>
1156 clap::ArgAction::Set
1157 }
1158 }
1159 }
1160 };
1161
1162 let func = Ident::new("action", span);
1163 Method::new(func, args)
1164}
1165
1166#[allow(clippy::large_enum_variant)]
1167#[derive(Clone)]
1168pub(crate) enum Kind {
1169 Arg(Sp<Ty>),
1170 Command(Sp<Ty>),
1171 Value,
1172 FromGlobal(Sp<Ty>),
1173 Subcommand(Sp<Ty>),
1174 Flatten(Sp<Ty>),
1175 Skip(Option<AttrValue>, AttrKind),
1176 ExternalSubcommand,
1177}
1178
1179impl Kind {
1180 pub(crate) fn name(&self) -> &'static str {
1181 match self {
1182 Self::Arg(_) => "arg",
1183 Self::Command(_) => "command",
1184 Self::Value => "value",
1185 Self::FromGlobal(_) => "from_global",
1186 Self::Subcommand(_) => "subcommand",
1187 Self::Flatten(_) => "flatten",
1188 Self::Skip(_, _) => "skip",
1189 Self::ExternalSubcommand => "external_subcommand",
1190 }
1191 }
1192
1193 pub(crate) fn attr_kind(&self) -> AttrKind {
1194 match self {
1195 Self::Arg(_) => AttrKind::Arg,
1196 Self::Command(_) => AttrKind::Command,
1197 Self::Value => AttrKind::Value,
1198 Self::FromGlobal(_) => AttrKind::Arg,
1199 Self::Subcommand(_) => AttrKind::Command,
1200 Self::Flatten(_) => AttrKind::Command,
1201 Self::Skip(_, kind) => *kind,
1202 Self::ExternalSubcommand => AttrKind::Command,
1203 }
1204 }
1205
1206 pub(crate) fn ty(&self) -> Option<&Sp<Ty>> {
1207 match self {
1208 Self::Arg(ty)
1209 | Self::Command(ty)
1210 | Self::Flatten(ty)
1211 | Self::FromGlobal(ty)
1212 | Self::Subcommand(ty) => Some(ty),
1213 Self::Value | Self::Skip(_, _) | Self::ExternalSubcommand => None,
1214 }
1215 }
1216}
1217
1218#[derive(Clone)]
1219pub(crate) struct Method {
1220 name: Ident,
1221 args: TokenStream,
1222}
1223
1224impl Method {
1225 pub(crate) fn new(name: Ident, args: TokenStream) -> Self {
1226 Method { name, args }
1227 }
1228
1229 fn from_env(ident: Ident, env_var: &str) -> Result<Option<Self>, syn::Error> {
1230 let mut lit = match env::var(env_var) {
1231 Ok(val) => {
1232 if val.is_empty() {
1233 return Ok(None);
1234 }
1235 LitStr::new(&val, ident.span())
1236 }
1237 Err(_) => {
1238 abort!(
1239 ident,
1240 "cannot derive `{}` from Cargo.toml\n\n= note: {note}\n\n= help: {help}\n\n",
1241 ident,
1242 note = format_args!("`{env_var}` environment variable is not set"),
1243 help = format_args!("use `{ident} = \"...\"` to set {ident} manually")
1244 );
1245 }
1246 };
1247
1248 if ident == "author" {
1249 let edited = process_author_str(&lit.value());
1250 lit = LitStr::new(&edited, lit.span());
1251 }
1252
1253 Ok(Some(Method::new(ident, quote!(#lit))))
1254 }
1255
1256 pub(crate) fn args(&self) -> &TokenStream {
1257 &self.args
1258 }
1259}
1260
1261impl ToTokens for Method {
1262 fn to_tokens(&self, ts: &mut TokenStream) {
1263 let Method { ref name, ref args } = self;
1264
1265 let tokens = quote!( .#name(#args) );
1266
1267 tokens.to_tokens(ts);
1268 }
1269}
1270
1271#[derive(Clone)]
1272pub(crate) struct Deprecation {
1273 pub(crate) span: Span,
1274 pub(crate) id: &'static str,
1275 pub(crate) version: &'static str,
1276 pub(crate) description: String,
1277}
1278
1279impl Deprecation {
1280 fn attribute(version: &'static str, old: AttrKind, new: AttrKind, span: Span) -> Self {
1281 Self {
1282 span,
1283 id: "old_attribute",
1284 version,
1285 description: format!(
1286 "Attribute `#[{}(...)]` has been deprecated in favor of `#[{}(...)]`",
1287 old.as_str(),
1288 new.as_str()
1289 ),
1290 }
1291 }
1292}
1293
1294impl ToTokens for Deprecation {
1295 fn to_tokens(&self, ts: &mut TokenStream) {
1296 let tokens = if cfg!(feature = "deprecated") {
1297 let Deprecation {
1298 span,
1299 id,
1300 version,
1301 description,
1302 } = self;
1303 let span = *span;
1304 let id = Ident::new(id, span);
1305
1306 quote_spanned!(span=> {
1307 #[deprecated(since = #version, note = #description)]
1308 fn #id() {}
1309 #id();
1310 })
1311 } else {
1312 quote!()
1313 };
1314
1315 tokens.to_tokens(ts);
1316 }
1317}
1318
1319fn assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind]) -> Result<(), syn::Error> {
1320 if *attr.kind.get() == AttrKind::Clap || *attr.kind.get() == AttrKind::StructOpt {
1321 } else if !possible_kind.contains(attr.kind.get()) {
1323 let options = possible_kind
1324 .iter()
1325 .map(|k| format!("`#[{}({})]`", k.as_str(), attr.name))
1326 .collect::<Vec<_>>();
1327 abort!(
1328 attr.name,
1329 "Unknown `#[{}({})]` attribute ({} exists)",
1330 attr.kind.as_str(),
1331 attr.name,
1332 options.join(", ")
1333 );
1334 }
1335 Ok(())
1336}
1337
1338fn process_author_str(author: &str) -> String {
1343 let mut res = String::with_capacity(author.len());
1344 let mut inside_angle_braces = 0usize;
1345
1346 for ch in author.chars() {
1347 if inside_angle_braces > 0 && ch == '>' {
1348 inside_angle_braces -= 1;
1349 res.push(ch);
1350 } else if ch == '<' {
1351 inside_angle_braces += 1;
1352 res.push(ch);
1353 } else if inside_angle_braces == 0 && ch == ':' {
1354 res.push_str(", ");
1355 } else {
1356 res.push(ch);
1357 }
1358 }
1359
1360 res
1361}
1362
1363#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1365pub(crate) enum CasingStyle {
1366 Camel,
1368 Kebab,
1370 Pascal,
1372 ScreamingSnake,
1374 Snake,
1376 Lower,
1378 Upper,
1380 Verbatim,
1382}
1383
1384impl CasingStyle {
1385 fn from_lit(name: &LitStr) -> Result<Sp<Self>, syn::Error> {
1386 use self::CasingStyle::{
1387 Camel, Kebab, Lower, Pascal, ScreamingSnake, Snake, Upper, Verbatim,
1388 };
1389
1390 let normalized = name.value().to_upper_camel_case().to_lowercase();
1391 let cs = |kind| Sp::new(kind, name.span());
1392
1393 let s = match normalized.as_ref() {
1394 "camel" | "camelcase" => cs(Camel),
1395 "kebab" | "kebabcase" => cs(Kebab),
1396 "pascal" | "pascalcase" => cs(Pascal),
1397 "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
1398 "snake" | "snakecase" => cs(Snake),
1399 "lower" | "lowercase" => cs(Lower),
1400 "upper" | "uppercase" => cs(Upper),
1401 "verbatim" | "verbatimcase" => cs(Verbatim),
1402 s => abort!(name, "unsupported casing: `{s}`"),
1403 };
1404 Ok(s)
1405 }
1406}
1407
1408#[derive(Clone)]
1409pub(crate) enum Name {
1410 Derived(Ident),
1411 Assigned(TokenStream),
1412}
1413
1414impl Name {
1415 pub(crate) fn translate(self, style: CasingStyle) -> TokenStream {
1416 use CasingStyle::{Camel, Kebab, Lower, Pascal, ScreamingSnake, Snake, Upper, Verbatim};
1417
1418 match self {
1419 Name::Assigned(tokens) => tokens,
1420 Name::Derived(ident) => {
1421 let s = ident.unraw().to_string();
1422 let s = match style {
1423 Pascal => s.to_upper_camel_case(),
1424 Kebab => s.to_kebab_case(),
1425 Camel => s.to_lower_camel_case(),
1426 ScreamingSnake => s.to_shouty_snake_case(),
1427 Snake => s.to_snake_case(),
1428 Lower => s.to_snake_case().replace('_', ""),
1429 Upper => s.to_shouty_snake_case().replace('_', ""),
1430 Verbatim => s,
1431 };
1432 quote_spanned!(ident.span()=> #s)
1433 }
1434 }
1435 }
1436
1437 pub(crate) fn translate_char(self, style: CasingStyle) -> TokenStream {
1438 use CasingStyle::{Camel, Kebab, Lower, Pascal, ScreamingSnake, Snake, Upper, Verbatim};
1439
1440 match self {
1441 Name::Assigned(tokens) => quote!( (#tokens).chars().next().unwrap() ),
1442 Name::Derived(ident) => {
1443 let s = ident.unraw().to_string();
1444 let s = match style {
1445 Pascal => s.to_upper_camel_case(),
1446 Kebab => s.to_kebab_case(),
1447 Camel => s.to_lower_camel_case(),
1448 ScreamingSnake => s.to_shouty_snake_case(),
1449 Snake => s.to_snake_case(),
1450 Lower => s.to_snake_case(),
1451 Upper => s.to_shouty_snake_case(),
1452 Verbatim => s,
1453 };
1454
1455 let s = s.chars().next().unwrap();
1456 quote_spanned!(ident.span()=> #s)
1457 }
1458 }
1459 }
1460}
1461
1462impl ToTokens for Name {
1463 fn to_tokens(&self, tokens: &mut TokenStream) {
1464 match self {
1465 Name::Assigned(t) => t.to_tokens(tokens),
1466 Name::Derived(ident) => {
1467 let s = ident.unraw().to_string();
1468 quote_spanned!(ident.span()=> #s).to_tokens(tokens);
1469 }
1470 }
1471 }
1472}