Skip to content

Commit

Permalink
Merge pull request #107 from CryZe/doc-comment-display
Browse files Browse the repository at this point in the history
Implement Doc Comments as Default Display Implementations
  • Loading branch information
shepmaster authored Jul 8, 2019
2 parents 63a2377 + e0d1094 commit d311b5b
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 7 deletions.
57 changes: 50 additions & 7 deletions snafu-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct VariantInfo {
backtrace_delegate: Option<Field>,
user_fields: Vec<Field>,
display_format: Option<UserInput>,
doc_comment: String,
visibility: Option<UserInput>,
}

Expand Down Expand Up @@ -157,13 +158,31 @@ fn parse_snafu_enum(

let mut display_format = None;
let mut visibility = None;
let mut doc_comment = String::new();
let mut reached_end_of_doc_comment = false;

for attr in attributes_from_syn(variant.attrs)? {
match attr {
SnafuAttribute::Display(d) => display_format = Some(d),
SnafuAttribute::Visibility(v) => visibility = Some(v),
SnafuAttribute::Source(..) => { /* Report this isn't valid here? */ }
SnafuAttribute::Backtrace(..) => { /* Report this isn't valid here? */ }
SnafuAttribute::DocComment(doc_comment_line) => {
// We join all the doc comment attributes with a space,
// but end once the summary of the doc comment is
// complete, which is indicated by an empty line.
if !reached_end_of_doc_comment {
let trimmed = doc_comment_line.trim();
if trimmed.is_empty() {
reached_end_of_doc_comment = true;
} else {
if !doc_comment.is_empty() {
doc_comment.push_str(" ");
}
doc_comment.push_str(trimmed);
}
}
}
}
}

Expand Down Expand Up @@ -214,6 +233,7 @@ fn parse_snafu_enum(
},
SnafuAttribute::Visibility(_) => { /* Report this isn't valid here? */ }
SnafuAttribute::Display(_) => { /* Report this isn't valid here? */ }
SnafuAttribute::DocComment(_) => { /* Just a regular doc comment. */ }
}
}

Expand Down Expand Up @@ -259,6 +279,7 @@ fn parse_snafu_enum(
backtrace_delegate,
user_fields,
display_format,
doc_comment,
visibility,
})
})
Expand Down Expand Up @@ -297,6 +318,7 @@ fn parse_snafu_struct(
}
}
SnafuAttribute::Backtrace(..) => { /* Report this isn't valid here? */ }
SnafuAttribute::DocComment(_) => { /* Just a regular doc comment. */ }
}
}

Expand Down Expand Up @@ -498,6 +520,7 @@ enum SnafuAttribute {
Visibility(UserInput),
Source(Vec<Source>),
Backtrace(Backtrace),
DocComment(String),
}

impl SnafuAttribute {
Expand Down Expand Up @@ -569,19 +592,35 @@ impl syn::parse::Parse for SnafuAttributeBody {
}
}

struct DocComment(SnafuAttribute);

impl syn::parse::Parse for DocComment {
fn parse(input: syn::parse::ParseStream) -> SynResult<Self> {
use syn::token::Eq;
use syn::LitStr;

let _: Eq = input.parse()?;
let doc: LitStr = input.parse()?;

Ok(DocComment(SnafuAttribute::DocComment(doc.value())))
}
}

fn attributes_from_syn(attrs: Vec<syn::Attribute>) -> MultiSynResult<Vec<SnafuAttribute>> {
use syn::parse2;

let mut ours = Vec::new();
let mut errs = Vec::new();

let parsed_attrs = attrs
.into_iter()
.filter(|attr| attr.path.is_ident("snafu"))
.map(|attr| {
let body: SnafuAttributeBody = parse2(attr.tts)?;
Ok(body.0)
});
let parsed_attrs = attrs.into_iter().flat_map(|attr| {
if attr.path.is_ident("snafu") {
Some(parse2::<SnafuAttributeBody>(attr.tts).map(|body| body.0))
} else if attr.path.is_ident("doc") {
Some(parse2::<DocComment>(attr.tts).map(|comment| vec![comment.0]))
} else {
None
}
});

for attr in parsed_attrs {
match attr {
Expand Down Expand Up @@ -868,11 +907,15 @@ impl<'a> DisplayImpl<'a> {
ref source_field,
ref backtrace_field,
ref display_format,
ref doc_comment,
..
} = *variant;

let format = match (display_format, source_field) {
(&Some(ref v), _) => quote! { #v },
(&None, _) if !doc_comment.is_empty() => {
quote! { #doc_comment }
}
(&None, &Some(ref f)) => {
let field_name = &f.name;
quote! { concat!(stringify!(#variant_name), ": {}"), #field_name }
Expand Down
40 changes: 40 additions & 0 deletions tests/doc_comment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
extern crate snafu;

use snafu::Snafu;

#[derive(Debug, Snafu)]
enum Error {
/// No user available.
/// You may need to specify one.
///
/// Here is a more detailed description.
MissingUser,
/// This is just a doc comment.
#[snafu(display("This is {}", stronger))]
Stronger { stronger: &'static str },
}

#[test]
fn implements_error() {
fn check<T: std::error::Error>() {}
check::<Error>();
}

#[test]
fn uses_doc_comment() {
assert_eq!(
Error::MissingUser.to_string(),
"No user available. You may need to specify one.",
);
}

#[test]
fn display_is_stronger_than_doc_comment() {
assert_eq!(
Error::Stronger {
stronger: "always stronger!"
}
.to_string(),
"This is always stronger!",
);
}

0 comments on commit d311b5b

Please sign in to comment.