1 | use proc_macro2::TokenStream;
|
2 | use quote::{quote, ToTokens};
|
3 | use syn::{Attribute, LitStr, Meta, Result};
|
4 |
|
5 | #[derive (Clone)]
|
6 | pub(crate) struct Display {
|
7 | pub(crate) fmt: LitStr,
|
8 | pub(crate) args: TokenStream,
|
9 | }
|
10 |
|
11 | pub(crate) struct VariantDisplay {
|
12 | pub(crate) r#enum: Option<Display>,
|
13 | pub(crate) variant: Display,
|
14 | }
|
15 |
|
16 | impl ToTokens for Display {
|
17 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
18 | let fmt: &LitStr = &self.fmt;
|
19 | let args: &TokenStream = &self.args;
|
20 | tokens.extend(iter:quote! {
|
21 | write!(formatter, #fmt #args)
|
22 | });
|
23 | }
|
24 | }
|
25 |
|
26 | impl ToTokens for VariantDisplay {
|
27 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
28 | if let Some(ref r#enum: &Display) = self.r#enum {
|
29 | r#enum.to_tokens(tokens);
|
30 | tokens.extend(iter:quote! { ?; write!(formatter, ": " )?; });
|
31 | }
|
32 | self.variant.to_tokens(tokens);
|
33 | }
|
34 | }
|
35 |
|
36 | pub(crate) struct AttrsHelper {
|
37 | ignore_extra_doc_attributes: bool,
|
38 | prefix_enum_doc_attributes: bool,
|
39 | }
|
40 |
|
41 | impl AttrsHelper {
|
42 | pub(crate) fn new(attrs: &[Attribute]) -> Self {
|
43 | let ignore_extra_doc_attributes = attrs
|
44 | .iter()
|
45 | .any(|attr| attr.path().is_ident("ignore_extra_doc_attributes" ));
|
46 | let prefix_enum_doc_attributes = attrs
|
47 | .iter()
|
48 | .any(|attr| attr.path().is_ident("prefix_enum_doc_attributes" ));
|
49 |
|
50 | Self {
|
51 | ignore_extra_doc_attributes,
|
52 | prefix_enum_doc_attributes,
|
53 | }
|
54 | }
|
55 |
|
56 | pub(crate) fn display(&self, attrs: &[Attribute]) -> Result<Option<Display>> {
|
57 | let displaydoc_attr = attrs.iter().find(|attr| attr.path().is_ident("displaydoc" ));
|
58 |
|
59 | if let Some(displaydoc_attr) = displaydoc_attr {
|
60 | let lit = displaydoc_attr
|
61 | .parse_args()
|
62 | .expect("#[displaydoc( \"foo \")] must contain string arguments" );
|
63 | let mut display = Display {
|
64 | fmt: lit,
|
65 | args: TokenStream::new(),
|
66 | };
|
67 |
|
68 | display.expand_shorthand();
|
69 | return Ok(Some(display));
|
70 | }
|
71 |
|
72 | let num_doc_attrs = attrs
|
73 | .iter()
|
74 | .filter(|attr| attr.path().is_ident("doc" ))
|
75 | .count();
|
76 |
|
77 | if !self.ignore_extra_doc_attributes && num_doc_attrs > 1 {
|
78 | panic!("Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive." );
|
79 | }
|
80 |
|
81 | for attr in attrs {
|
82 | if attr.path().is_ident("doc" ) {
|
83 | let lit = match &attr.meta {
|
84 | Meta::NameValue(syn::MetaNameValue {
|
85 | value:
|
86 | syn::Expr::Lit(syn::ExprLit {
|
87 | lit: syn::Lit::Str(lit),
|
88 | ..
|
89 | }),
|
90 | ..
|
91 | }) => lit,
|
92 | _ => unimplemented!(),
|
93 | };
|
94 |
|
95 | // Make an attempt at cleaning up multiline doc comments.
|
96 | let doc_str = lit
|
97 | .value()
|
98 | .lines()
|
99 | .map(|line| line.trim().trim_start_matches('*' ).trim())
|
100 | .collect::<Vec<&str>>()
|
101 | .join(" \n" );
|
102 |
|
103 | let lit = LitStr::new(doc_str.trim(), lit.span());
|
104 |
|
105 | let mut display = Display {
|
106 | fmt: lit,
|
107 | args: TokenStream::new(),
|
108 | };
|
109 |
|
110 | display.expand_shorthand();
|
111 | return Ok(Some(display));
|
112 | }
|
113 | }
|
114 |
|
115 | Ok(None)
|
116 | }
|
117 |
|
118 | pub(crate) fn display_with_input(
|
119 | &self,
|
120 | r#enum: &[Attribute],
|
121 | variant: &[Attribute],
|
122 | ) -> Result<Option<VariantDisplay>> {
|
123 | let r#enum = if self.prefix_enum_doc_attributes {
|
124 | let result = self
|
125 | .display(r#enum)?
|
126 | .expect("Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself." );
|
127 |
|
128 | Some(result)
|
129 | } else {
|
130 | None
|
131 | };
|
132 |
|
133 | Ok(self
|
134 | .display(variant)?
|
135 | .map(|variant| VariantDisplay { r#enum, variant }))
|
136 | }
|
137 | }
|
138 | |