1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use crate::Spanning;
pub fn doc_string(
attrs: &[syn::Attribute],
) -> syn::Result<Option<Spanning<String>>> {
let mut span = None;
let mut out = String::new();
for a in super::attrs::filter_by_name("doc", attrs) {
if let syn::Meta::NameValue(item) = &a.meta {
if let syn::Expr::Lit(expr) = &item.value {
if let syn::Lit::Str(lit) = &expr.lit {
if span.is_none() {
span = Some(lit.span());
}
let s = lit.value();
let s = s.strip_prefix(' ').unwrap_or(&s).trim_end();
if s.ends_with('\\') {
out.push_str(s.trim_end_matches('\\'));
out.push(' ');
} else {
out.push_str(s);
out.push('\n');
}
} else {
return Err(syn::Error::new_spanned(
&expr.lit,
"`#[doc]` attribute can contain string literals only",
));
}
} else {
return Err(syn::Error::new_spanned(
&item.value,
"`#[doc]` attribute should be in `#[doc = value] format`",
));
}
}
}
if !out.is_empty() {
out.truncate(out.trim_end().len());
}
Ok(span.map(|s| Spanning::new(out, s)))
}
pub fn doc(attrs: &[syn::Attribute]) -> syn::Result<Option<syn::LitStr>> {
doc_string(attrs).map(|opt| opt.map(Into::into))
}