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