Revision control
Copy as Markdown
Other Tools
use proc_macro2::TokenStream;↩
use quote::{quote, ToTokens};↩
use syn::{Attribute, LitStr, Meta, Result};↩
↩
#[derive(Clone)]↩
pub(crate) struct Display {↩
pub(crate) fmt: LitStr,↩
pub(crate) args: TokenStream,↩
}↩
↩
pub(crate) struct VariantDisplay {↩
pub(crate) r#enum: Option<Display>,↩
pub(crate) variant: Display,↩
}↩
↩
impl ToTokens for Display {↩
fn to_tokens(&self, tokens: &mut TokenStream) {↩
let fmt = &self.fmt;↩
let args = &self.args;↩
tokens.extend(quote! {↩
write!(formatter, #fmt #args)↩
});↩
}↩
}↩
↩
impl ToTokens for VariantDisplay {↩
fn to_tokens(&self, tokens: &mut TokenStream) {↩
if let Some(ref r#enum) = self.r#enum {↩
r#enum.to_tokens(tokens);↩
tokens.extend(quote! { ?; write!(formatter, ": ")?; });↩
}↩
self.variant.to_tokens(tokens);↩
}↩
}↩
↩
pub(crate) struct AttrsHelper {↩
ignore_extra_doc_attributes: bool,↩
prefix_enum_doc_attributes: bool,↩
}↩
↩
impl AttrsHelper {↩
pub(crate) fn new(attrs: &[Attribute]) -> Self {↩
let ignore_extra_doc_attributes = attrs↩
.iter()↩
.any(|attr| attr.path().is_ident("ignore_extra_doc_attributes"));↩
let prefix_enum_doc_attributes = attrs↩
.iter()↩
.any(|attr| attr.path().is_ident("prefix_enum_doc_attributes"));↩
↩
Self {↩
ignore_extra_doc_attributes,↩
prefix_enum_doc_attributes,↩
}↩
}↩
↩
pub(crate) fn display(&self, attrs: &[Attribute]) -> Result<Option<Display>> {↩
let displaydoc_attr = attrs.iter().find(|attr| attr.path().is_ident("displaydoc"));↩
↩
if let Some(displaydoc_attr) = displaydoc_attr {↩
let lit = displaydoc_attr↩
.parse_args()↩
.expect("#[displaydoc(\"foo\")] must contain string arguments");↩
let mut display = Display {↩
fmt: lit,↩
args: TokenStream::new(),↩
};↩
↩
display.expand_shorthand();↩
return Ok(Some(display));↩
}↩
↩
let num_doc_attrs = attrs↩
.iter()↩
.filter(|attr| attr.path().is_ident("doc"))↩
.count();↩
↩
if !self.ignore_extra_doc_attributes && num_doc_attrs > 1 {↩
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.");↩
}↩
↩
for attr in attrs {↩
if attr.path().is_ident("doc") {↩
let lit = match &attr.meta {↩
Meta::NameValue(syn::MetaNameValue {↩
value:↩
syn::Expr::Lit(syn::ExprLit {↩
lit: syn::Lit::Str(lit),↩
..↩
}),↩
..↩
}) => lit,↩
_ => unimplemented!(),↩
};↩
↩
// Make an attempt at cleaning up multiline doc comments.↩
let doc_str = lit↩
.value()↩
.lines()↩
.map(|line| line.trim().trim_start_matches('*').trim())↩
.collect::<Vec<&str>>()↩
.join("\n");↩
↩
let lit = LitStr::new(doc_str.trim(), lit.span());↩
↩
let mut display = Display {↩
fmt: lit,↩
args: TokenStream::new(),↩
};↩
↩
display.expand_shorthand();↩
return Ok(Some(display));↩
}↩
}↩
↩
Ok(None)↩
}↩
↩
pub(crate) fn display_with_input(↩
&self,↩
r#enum: &[Attribute],↩
variant: &[Attribute],↩
) -> Result<Option<VariantDisplay>> {↩
let r#enum = if self.prefix_enum_doc_attributes {↩
let result = self↩
.display(r#enum)?↩
.expect("Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.");↩
↩
Some(result)↩
} else {↩
None↩
};↩
↩
Ok(self↩
.display(variant)?↩
.map(|variant| VariantDisplay { r#enum, variant }))↩
}↩
}↩