
# Objective Resolves #6197 Make it so that doc comments can be retrieved via reflection. ## Solution Adds the new `documentation` feature to `bevy_reflect` (disabled by default). When enabled, documentation can be found using `TypeInfo::doc` for reflected types: ```rust /// Some struct. /// /// # Example /// /// ```ignore /// let some_struct = SomeStruct; /// ``` #[derive(Reflect)] struct SomeStruct; let info = <SomeStruct as Typed>::type_info(); assert_eq!( Some(" Some struct.\n\n # Example\n\n ```ignore\n let some_struct = SomeStruct;\n ```"), info.docs() ); ``` ### Notes for Reviewers The bulk of the files simply added the same 16 lines of code (with slightly different documentation). Most of the real changes occur in the `bevy_reflect_derive` files as well as in the added tests. --- ## Changelog * Added `documentation` feature to `bevy_reflect` * Added `TypeInfo::docs` method (and similar methods for all info types)
187 lines
6.6 KiB
Rust
187 lines
6.6 KiB
Rust
//! This crate contains macros used by Bevy's `Reflect` API.
|
|
//!
|
|
//! The main export of this crate is the derive macro for [`Reflect`]. This allows
|
|
//! types to easily implement `Reflect` along with other `bevy_reflect` traits,
|
|
//! such as `Struct`, `GetTypeRegistration`, and more— all with a single derive!
|
|
//!
|
|
//! Some other noteworthy exports include the derive macros for [`FromReflect`] and
|
|
//! [`TypeUuid`], as well as the [`reflect_trait`] attribute macro.
|
|
//!
|
|
//! [`Reflect`]: crate::derive_reflect
|
|
//! [`FromReflect`]: crate::derive_from_reflect
|
|
//! [`TypeUuid`]: crate::derive_type_uuid
|
|
//! [`reflect_trait`]: macro@reflect_trait
|
|
|
|
extern crate proc_macro;
|
|
|
|
mod container_attributes;
|
|
mod derive_data;
|
|
#[cfg(feature = "documentation")]
|
|
mod documentation;
|
|
mod enum_utility;
|
|
mod field_attributes;
|
|
mod from_reflect;
|
|
mod impls;
|
|
mod reflect_value;
|
|
mod registration;
|
|
mod trait_reflection;
|
|
mod type_uuid;
|
|
mod utility;
|
|
|
|
use crate::derive_data::{ReflectDerive, ReflectMeta, ReflectStruct};
|
|
use proc_macro::TokenStream;
|
|
use quote::quote;
|
|
use reflect_value::ReflectValueDef;
|
|
use syn::spanned::Spanned;
|
|
use syn::{parse_macro_input, DeriveInput};
|
|
|
|
pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
|
|
pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
|
|
|
|
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value, module))]
|
|
pub fn derive_reflect(input: TokenStream) -> TokenStream {
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
|
|
let derive_data = match ReflectDerive::from_input(&ast) {
|
|
Ok(data) => data,
|
|
Err(err) => return err.into_compile_error().into(),
|
|
};
|
|
|
|
match derive_data {
|
|
ReflectDerive::Struct(struct_data) | ReflectDerive::UnitStruct(struct_data) => {
|
|
impls::impl_struct(&struct_data)
|
|
}
|
|
ReflectDerive::TupleStruct(struct_data) => impls::impl_tuple_struct(&struct_data),
|
|
ReflectDerive::Enum(meta) => impls::impl_enum(&meta),
|
|
ReflectDerive::Value(meta) => impls::impl_value(&meta),
|
|
}
|
|
}
|
|
|
|
/// Derives the `FromReflect` trait.
|
|
///
|
|
/// This macro supports the following field attributes:
|
|
/// * `#[reflect(ignore)]`: Ignores the field. This requires the field to implement [`Default`].
|
|
/// * `#[reflect(default)]`: If the field's value cannot be read, uses its [`Default`] implementation.
|
|
/// * `#[reflect(default = "some_func")]`: If the field's value cannot be read, uses the function with the given name.
|
|
///
|
|
#[proc_macro_derive(FromReflect, attributes(reflect))]
|
|
pub fn derive_from_reflect(input: TokenStream) -> TokenStream {
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
|
|
let derive_data = match ReflectDerive::from_input(&ast) {
|
|
Ok(data) => data,
|
|
Err(err) => return err.into_compile_error().into(),
|
|
};
|
|
|
|
match derive_data {
|
|
ReflectDerive::Struct(struct_data) | ReflectDerive::UnitStruct(struct_data) => {
|
|
from_reflect::impl_struct(&struct_data)
|
|
}
|
|
ReflectDerive::TupleStruct(struct_data) => from_reflect::impl_tuple_struct(&struct_data),
|
|
ReflectDerive::Enum(meta) => from_reflect::impl_enum(&meta),
|
|
ReflectDerive::Value(meta) => from_reflect::impl_value(&meta),
|
|
}
|
|
}
|
|
|
|
// From https://github.com/randomPoison/type-uuid
|
|
#[proc_macro_derive(TypeUuid, attributes(uuid))]
|
|
pub fn derive_type_uuid(input: TokenStream) -> TokenStream {
|
|
type_uuid::type_uuid_derive(input)
|
|
}
|
|
|
|
#[proc_macro_attribute]
|
|
pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
|
|
trait_reflection::reflect_trait(&args, input)
|
|
}
|
|
|
|
#[proc_macro]
|
|
pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
|
|
let def = parse_macro_input!(input as ReflectValueDef);
|
|
let meta = ReflectMeta::new(
|
|
&def.type_name,
|
|
&def.generics,
|
|
def.traits.unwrap_or_default(),
|
|
);
|
|
|
|
#[cfg(feature = "documentation")]
|
|
let meta = meta.with_docs(documentation::Documentation::from_attributes(&def.attrs));
|
|
|
|
impls::impl_value(&meta)
|
|
}
|
|
|
|
/// A replacement for `#[derive(Reflect)]` to be used with foreign types which
|
|
/// the definitions of cannot be altered.
|
|
///
|
|
/// This macro is an alternative to [`impl_reflect_value!`] and [`impl_from_reflect_value!`]
|
|
/// which implement foreign types as Value types. Note that there is no `impl_from_reflect_struct`,
|
|
/// as this macro will do the job of both. This macro implements them as `Struct` types,
|
|
/// which have greater functionality. The type being reflected must be in scope, as you cannot
|
|
/// qualify it in the macro as e.g. `bevy::prelude::Vec3`.
|
|
///
|
|
/// It may be necessary to add `#[reflect(Default)]` for some types, specifically non-constructible
|
|
/// foreign types. Without `Default` reflected for such types, you will usually get an arcane
|
|
/// error message and fail to compile. If the type does not implement `Default`, it may not
|
|
/// be possible to reflect without extending the macro.
|
|
///
|
|
/// # Example
|
|
/// Implementing `Reflect` for `bevy::prelude::Vec3` as a struct type:
|
|
/// ```ignore
|
|
/// use bevy::prelude::Vec3;
|
|
///
|
|
/// impl_reflect_struct!(
|
|
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
|
|
/// struct Vec3 {
|
|
/// x: f32,
|
|
/// y: f32,
|
|
/// z: f32
|
|
/// }
|
|
/// );
|
|
/// ```
|
|
#[proc_macro]
|
|
pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
let derive_data = match ReflectDerive::from_input(&ast) {
|
|
Ok(data) => data,
|
|
Err(err) => return err.into_compile_error().into(),
|
|
};
|
|
|
|
match derive_data {
|
|
ReflectDerive::Struct(struct_data) => {
|
|
let impl_struct: proc_macro2::TokenStream = impls::impl_struct(&struct_data).into();
|
|
let impl_from_struct: proc_macro2::TokenStream =
|
|
from_reflect::impl_struct(&struct_data).into();
|
|
|
|
TokenStream::from(quote! {
|
|
#impl_struct
|
|
|
|
#impl_from_struct
|
|
})
|
|
}
|
|
ReflectDerive::TupleStruct(..) => syn::Error::new(
|
|
ast.span(),
|
|
"impl_reflect_struct does not support tuple structs",
|
|
)
|
|
.into_compile_error()
|
|
.into(),
|
|
ReflectDerive::UnitStruct(..) => syn::Error::new(
|
|
ast.span(),
|
|
"impl_reflect_struct does not support unit structs",
|
|
)
|
|
.into_compile_error()
|
|
.into(),
|
|
_ => syn::Error::new(ast.span(), "impl_reflect_struct only supports structs")
|
|
.into_compile_error()
|
|
.into(),
|
|
}
|
|
}
|
|
|
|
#[proc_macro]
|
|
pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
|
|
let def = parse_macro_input!(input as ReflectValueDef);
|
|
from_reflect::impl_value(&ReflectMeta::new(
|
|
&def.type_name,
|
|
&def.generics,
|
|
def.traits.unwrap_or_default(),
|
|
))
|
|
}
|