1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{Attribute, LitStr, Meta, Result};
4
5#[derive(#[automatically_derived]
impl ::core::clone::Clone for Display {
#[inline]
fn clone(&self) -> Display {
Display {
fmt: ::core::clone::Clone::clone(&self.fmt),
args: ::core::clone::Clone::clone(&self.args),
}
}
}Clone)]
6pub(crate) struct Display {
7 pub(crate) fmt: LitStr,
8 pub(crate) args: TokenStream,
9}
10
11pub(crate) struct VariantDisplay {
12 pub(crate) r#enum: Option<Display>,
13 pub(crate) variant: Display,
14}
15
16impl ToTokens for Display {
17 fn to_tokens(&self, tokens: &mut TokenStream) {
18 let fmt = &self.fmt;
19 let args = &self.args;
20 tokens.extend({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "write");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "formatter");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&fmt, &mut _s);
::quote::ToTokens::to_tokens(&args, &mut _s);
_s
});
_s
}quote! {
21 write!(formatter, #fmt #args)
22 });
23 }
24}
25
26impl ToTokens for VariantDisplay {
27 fn to_tokens(&self, tokens: &mut TokenStream) {
28 if let Some(ref r#enum) = self.r#enum {
29 r#enum.to_tokens(tokens);
30 tokens.extend({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_question(&mut _s);
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "write");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "formatter");
::quote::__private::push_comma(&mut _s);
::quote::__private::parse(&mut _s, "\": \"");
_s
});
::quote::__private::push_question(&mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! { ?; write!(formatter, ": ")?; });
31 }
32 self.variant.to_tokens(tokens);
33 }
34}
35
36pub(crate) struct AttrsHelper {
37 ignore_extra_doc_attributes: bool,
38 prefix_enum_doc_attributes: bool,
39}
40
41impl 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 literals = attrs
73 .iter()
74 .filter(|attr| attr.path().is_ident("doc"))
75 .map(|attr| match &attr.meta {
76 Meta::NameValue(syn::MetaNameValue {
77 value:
78 syn::Expr::Lit(syn::ExprLit {
79 lit: syn::Lit::Str(lit),
80 ..
81 }),
82 ..
83 }) => lit,
84 _ => ::core::panicking::panic("not implemented")unimplemented!(),
85 });
86
87 let span = match literals.clone().next() {
88 Some(lit) => lit.span(),
89 None => return Ok(None),
90 };
91
92 let strs = literals.map(|lit| {
93 let doc_str = lit
95 .value()
96 .lines()
97 .map(|line| line.trim().trim_start_matches('*').trim())
98 .collect::<Vec<&str>>()
99 .join("\n")
100 .trim()
101 .to_string();
102 (!doc_str.is_empty()).then(|| doc_str)
103 });
104
105 let joined = if self.ignore_extra_doc_attributes {
106 strs.take_while(|x| x.is_some()).collect::<Option<Vec<_>>>()
107 } else {
108 strs.collect::<Option<Vec<_>>>()
109 }.unwrap_or_else(|| {
110 {
::core::panicking::panic_fmt(format_args!("Paragraph breaks in multi-line doc 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"));
};panic!("Paragraph breaks in multi-line doc 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");
111 }).join(" ");
112
113 let mut display = Display {
114 fmt: LitStr::new(&joined, span),
115 args: TokenStream::new(),
116 };
117
118 display.expand_shorthand();
119 Ok(Some(display))
120 }
121
122 pub(crate) fn display_with_input(
123 &self,
124 r#enum: &[Attribute],
125 variant: &[Attribute],
126 ) -> Result<Option<VariantDisplay>> {
127 let r#enum = if self.prefix_enum_doc_attributes {
128 let result = self
129 .display(r#enum)?
130 .expect("Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.");
131
132 Some(result)
133 } else {
134 None
135 };
136
137 Ok(self
138 .display(variant)?
139 .map(|variant| VariantDisplay { r#enum, variant }))
140 }
141}