Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/derive/src/documentation.rs
6599 views
1
//! Contains code related to documentation reflection (requires the `documentation` feature).
2
3
use bevy_macro_utils::fq_std::FQOption;
4
use proc_macro2::TokenStream;
5
use quote::{quote, ToTokens};
6
use syn::{Attribute, Expr, ExprLit, Lit, Meta};
7
8
/// A struct used to represent a type's documentation, if any.
9
///
10
/// When converted to a [`TokenStream`], this will output an `Option<String>`
11
/// containing the collection of doc comments.
12
#[derive(Default, Clone)]
13
pub(crate) struct Documentation {
14
docs: Vec<String>,
15
}
16
17
impl Documentation {
18
/// Create a new [`Documentation`] from a type's attributes.
19
///
20
/// This will collect all `#[doc = "..."]` attributes, including the ones generated via `///` and `//!`.
21
pub fn from_attributes<'a>(attributes: impl IntoIterator<Item = &'a Attribute>) -> Self {
22
let docs = attributes
23
.into_iter()
24
.filter_map(|attr| match &attr.meta {
25
Meta::NameValue(pair) if pair.path.is_ident("doc") => {
26
if let Expr::Lit(ExprLit {
27
lit: Lit::Str(lit), ..
28
}) = &pair.value
29
{
30
Some(lit.value())
31
} else {
32
None
33
}
34
}
35
_ => None,
36
})
37
.collect();
38
39
Self { docs }
40
}
41
42
/// The full docstring, if any.
43
pub fn doc_string(&self) -> Option<String> {
44
if self.docs.is_empty() {
45
return None;
46
}
47
48
let len = self.docs.len();
49
Some(
50
self.docs
51
.iter()
52
.enumerate()
53
.map(|(index, doc)| {
54
if index < len - 1 {
55
format!("{doc}\n")
56
} else {
57
doc.to_owned()
58
}
59
})
60
.collect(),
61
)
62
}
63
64
/// Is the collection empty?
65
pub fn is_empty(&self) -> bool {
66
self.docs.is_empty()
67
}
68
69
/// Push a new docstring to the collection
70
pub fn push(&mut self, doc: String) {
71
self.docs.push(doc);
72
}
73
}
74
75
impl ToTokens for Documentation {
76
fn to_tokens(&self, tokens: &mut TokenStream) {
77
if let Some(doc) = self.doc_string() {
78
quote!(#FQOption::Some(#doc)).to_tokens(tokens);
79
} else {
80
quote!(#FQOption::None).to_tokens(tokens);
81
}
82
}
83
}
84
85