utoipa_gen/
doc_comment.rs1use std::ops::Deref;
2
3use proc_macro2::Ident;
4use syn::{Attribute, Expr, Lit, Meta};
5
6const DOC_ATTRIBUTE_TYPE: &str = "doc";
7
8#[cfg_attr(feature = "debug", derive(Debug))]
10pub(crate) struct CommentAttributes(pub(crate) Vec<String>);
11
12impl CommentAttributes {
13 pub(crate) fn from_attributes(attributes: &[Attribute]) -> Self {
16 Self(Self::as_string_vec(
17 attributes.iter().filter(Self::is_doc_attribute),
18 ))
19 }
20
21 fn is_doc_attribute(attribute: &&Attribute) -> bool {
22 match Self::get_attribute_ident(attribute) {
23 Some(attribute) => attribute == DOC_ATTRIBUTE_TYPE,
24 None => false,
25 }
26 }
27
28 fn get_attribute_ident(attribute: &Attribute) -> Option<&Ident> {
29 attribute.path().get_ident()
30 }
31
32 fn as_string_vec<'a, I: Iterator<Item = &'a Attribute>>(attributes: I) -> Vec<String> {
33 attributes
34 .into_iter()
35 .filter_map(Self::parse_doc_comment)
36 .collect()
37 }
38
39 fn parse_doc_comment(attribute: &Attribute) -> Option<String> {
40 match &attribute.meta {
41 Meta::NameValue(name_value) => {
42 if let Expr::Lit(ref doc_comment) = name_value.value {
43 if let Lit::Str(ref comment) = doc_comment.lit {
44 Some(comment.value().trim().to_string())
45 } else {
46 None
47 }
48 } else {
49 None
50 }
51 }
52 _ => None,
54 }
55 }
56
57 pub(crate) fn as_formatted_string(&self) -> String {
59 self.join("\n")
60 }
61}
62
63impl Deref for CommentAttributes {
64 type Target = Vec<String>;
65
66 fn deref(&self) -> &Self::Target {
67 &self.0
68 }
69}