From d92fc1e4563d402f97a02f797b1e9c2558e72f86 Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Tue, 3 Dec 2024 20:45:20 +0100 Subject: [PATCH] Move required components doc to type doc (#16575) # Objective Make documentation of a component's required components more visible by moving it to the type's docs ## Solution Change `#[require]` from a derive macro helper to an attribute macro. Disadvantages: - this silences any unused code warnings on the component, as it is used by the macro! - need to import `require` if not using the ecs prelude (I have not included this in the migration guilde as Rust tooling already suggests the fix) --- ## Showcase ![Documentation of Camera](https://github.com/user-attachments/assets/3329511b-747a-4c8d-a43e-57f7c9c71a3c) --------- Co-authored-by: Alice Cecile Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> --- .../bevy_core_pipeline/src/motion_blur/mod.rs | 5 ++- crates/bevy_core_pipeline/src/taa/mod.rs | 2 +- crates/bevy_ecs/macros/src/component.rs | 37 ++++++++++++------- crates/bevy_ecs/macros/src/lib.rs | 10 ++++- crates/bevy_ecs/src/component.rs | 2 + crates/bevy_ecs/src/lib.rs | 5 +-- crates/bevy_ecs/src/system/commands/mod.rs | 2 +- crates/bevy_input/src/gamepad.rs | 1 + crates/bevy_pbr/src/light_probe/mod.rs | 2 +- crates/bevy_pbr/src/meshlet/mod.rs | 2 +- crates/bevy_pbr/src/ssao/mod.rs | 2 +- crates/bevy_pbr/src/ssr/mod.rs | 2 +- crates/bevy_pbr/src/volumetric_fog/mod.rs | 4 +- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/mesh/components.rs | 2 +- crates/bevy_scene/src/components.rs | 2 +- crates/bevy_sprite/src/sprite.rs | 5 ++- crates/bevy_text/src/text2d.rs | 2 +- .../src/components/transform.rs | 2 +- crates/bevy_ui/src/ui_material.rs | 5 ++- crates/bevy_ui/src/widget/button.rs | 5 ++- crates/bevy_ui/src/widget/text.rs | 2 +- 22 files changed, 68 insertions(+), 35 deletions(-) diff --git a/crates/bevy_core_pipeline/src/motion_blur/mod.rs b/crates/bevy_core_pipeline/src/motion_blur/mod.rs index 2195e296f5..c6eb8524ca 100644 --- a/crates/bevy_core_pipeline/src/motion_blur/mod.rs +++ b/crates/bevy_core_pipeline/src/motion_blur/mod.rs @@ -11,7 +11,10 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, Handle}; use bevy_ecs::{ - bundle::Bundle, component::Component, query::With, reflect::ReflectComponent, + bundle::Bundle, + component::{require, Component}, + query::With, + reflect::ReflectComponent, schedule::IntoSystemConfigs, }; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index e9f8f1ac3d..67422b4a72 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -10,7 +10,7 @@ use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, Handle}; use bevy_core::FrameCount; use bevy_ecs::{ - prelude::{Bundle, Component, Entity, ReflectComponent}, + prelude::{require, Bundle, Component, Entity, ReflectComponent}, query::{QueryItem, With}, schedule::IntoSystemConfigs, system::{Commands, Query, Res, ResMut, Resource}, diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index cb53dfe0a7..9a205b91e7 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -1,4 +1,4 @@ -use proc_macro::TokenStream; +use proc_macro::{TokenStream, TokenTree}; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens}; use std::collections::HashSet; @@ -127,22 +127,9 @@ pub fn derive_component(input: TokenStream) -> TokenStream { let struct_name = &ast.ident; let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); - let required_component_docs = attrs.requires.map(|r| { - let paths = r - .iter() - .map(|r| format!("[`{}`]", r.path.to_token_stream())) - .collect::>() - .join(", "); - let doc = format!("Required Components: {paths}. \n\n A component's Required Components are inserted whenever it is inserted. Note that this will also insert the required components _of_ the required components, recursively, in depth-first order."); - quote! { - #[doc = #doc] - } - }); - // This puts `register_required` before `register_recursive_requires` to ensure that the constructors of _all_ top // level components are initialized first, giving them precedence over recursively defined constructors for the same component type TokenStream::from(quote! { - #required_component_docs impl #impl_generics #bevy_ecs_path::component::Component for #struct_name #type_generics #where_clause { const STORAGE_TYPE: #bevy_ecs_path::component::StorageType = #storage; fn register_required_components( @@ -173,6 +160,28 @@ pub fn derive_component(input: TokenStream) -> TokenStream { }) } +pub fn document_required_components(attr: TokenStream, item: TokenStream) -> TokenStream { + let paths = parse_macro_input!(attr with Punctuated::::parse_terminated) + .iter() + .map(|r| format!("[`{}`]", r.path.to_token_stream())) + .collect::>() + .join(", "); + + // Insert information about required components after any existing doc comments + let mut out = TokenStream::new(); + let mut end_of_attributes_reached = false; + for tt in item { + if !end_of_attributes_reached & matches!(tt, TokenTree::Ident(_)) { + end_of_attributes_reached = true; + let doc: TokenStream = format!("#[doc = \"\n\n# Required Components\n{paths} \n\n A component's required components are inserted whenever it is inserted. Note that this will also insert the required components _of_ the required components, recursively, in depth-first order.\"]").parse().unwrap(); + out.extend(doc); + } + out.extend(Some(tt)); + } + + out +} + pub const COMPONENT: &str = "component"; pub const STORAGE: &str = "storage"; pub const REQUIRE: &str = "require"; diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 10f7940754..c3a256fef8 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -721,11 +721,19 @@ pub fn derive_resource(input: TokenStream) -> TokenStream { component::derive_resource(input) } -#[proc_macro_derive(Component, attributes(component, require))] +#[proc_macro_derive(Component, attributes(component))] pub fn derive_component(input: TokenStream) -> TokenStream { component::derive_component(input) } +/// Allows specifying a component's required components. +/// +/// See `Component` docs for usage. +#[proc_macro_attribute] +pub fn require(attr: TokenStream, item: TokenStream) -> TokenStream { + component::document_required_components(attr, item) +} + #[proc_macro_derive(States)] pub fn derive_states(input: TokenStream) -> TokenStream { states::derive_states(input) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index acffd5b3d1..5bdaeb024a 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -29,6 +29,8 @@ use core::{ }; use derive_more::derive::{Display, Error}; +pub use bevy_ecs_macros::require; + /// A data type that can be used to store data for an [entity]. /// /// `Component` is a [derivable trait]: this means that a data type can implement it by applying a `#[derive(Component)]` attribute to it. diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 09845d1446..fbf4645a19 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -46,7 +46,7 @@ pub mod prelude { pub use crate::{ bundle::Bundle, change_detection::{DetectChanges, DetectChangesMut, Mut, Ref}, - component::Component, + component::{require, Component}, entity::{Entity, EntityMapper}, event::{Event, EventMutator, EventReader, EventWriter, Events}, observer::{CloneEntityWithObserversExt, Observer, Trigger}, @@ -82,11 +82,10 @@ pub mod prelude { #[cfg(test)] mod tests { use crate as bevy_ecs; - use crate::component::{RequiredComponents, RequiredComponentsError}; use crate::{ bundle::Bundle, change_detection::Ref, - component::{Component, ComponentId}, + component::{require, Component, ComponentId, RequiredComponents, RequiredComponentsError}, entity::Entity, prelude::Or, query::{Added, Changed, FilteredAccess, QueryFilter, With, Without}, diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index a6612d01a3..aa5523b0bd 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -2256,7 +2256,7 @@ fn observe( mod tests { use crate::{ self as bevy_ecs, - component::Component, + component::{require, Component}, system::{Commands, Resource}, world::{CommandQueue, FromWorld, World}, }; diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 5493103a61..7c13da902f 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -7,6 +7,7 @@ use bevy_ecs::{ component::Component, entity::Entity, event::{Event, EventReader, EventWriter}, + prelude::require, system::{Commands, Query}, }; use bevy_math::Vec2; diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index cab462c280..5391d75c86 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -5,7 +5,7 @@ use bevy_asset::{load_internal_asset, AssetId, Handle}; use bevy_core_pipeline::core_3d::Camera3d; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - component::Component, + component::{require, Component}, entity::Entity, query::With, reflect::ReflectComponent, diff --git a/crates/bevy_pbr/src/meshlet/mod.rs b/crates/bevy_pbr/src/meshlet/mod.rs index c85ee80453..d5c837f2d3 100644 --- a/crates/bevy_pbr/src/meshlet/mod.rs +++ b/crates/bevy_pbr/src/meshlet/mod.rs @@ -68,7 +68,7 @@ use bevy_core_pipeline::{ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ bundle::Bundle, - component::Component, + component::{require, Component}, entity::Entity, prelude::With, query::Has, diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 366ac91e22..fd47511da5 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -9,7 +9,7 @@ use bevy_core_pipeline::{ prepass::{DepthPrepass, NormalPrepass, ViewPrepassTextures}, }; use bevy_ecs::{ - prelude::{Bundle, Component, Entity}, + prelude::{require, Bundle, Component, Entity}, query::{Has, QueryItem, With}, reflect::ReflectComponent, schedule::IntoSystemConfigs, diff --git a/crates/bevy_pbr/src/ssr/mod.rs b/crates/bevy_pbr/src/ssr/mod.rs index 935e5f5b8f..69a32acd75 100644 --- a/crates/bevy_pbr/src/ssr/mod.rs +++ b/crates/bevy_pbr/src/ssr/mod.rs @@ -15,7 +15,7 @@ use bevy_core_pipeline::{ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ bundle::Bundle, - component::Component, + component::{require, Component}, entity::Entity, query::{Has, QueryItem, With}, reflect::ReflectComponent, diff --git a/crates/bevy_pbr/src/volumetric_fog/mod.rs b/crates/bevy_pbr/src/volumetric_fog/mod.rs index 5291276495..0d998b2a06 100644 --- a/crates/bevy_pbr/src/volumetric_fog/mod.rs +++ b/crates/bevy_pbr/src/volumetric_fog/mod.rs @@ -39,7 +39,9 @@ use bevy_core_pipeline::core_3d::{ prepare_core_3d_depth_textures, }; use bevy_ecs::{ - bundle::Bundle, component::Component, reflect::ReflectComponent, + bundle::Bundle, + component::{require, Component}, + reflect::ReflectComponent, schedule::IntoSystemConfigs as _, }; use bevy_image::Image; diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 689734c4fb..8badda2a1b 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -22,7 +22,7 @@ use bevy_ecs::{ component::{Component, ComponentId}, entity::Entity, event::EventReader, - prelude::With, + prelude::{require, With}, query::Has, reflect::ReflectComponent, system::{Commands, Query, Res, ResMut, Resource}, diff --git a/crates/bevy_render/src/mesh/components.rs b/crates/bevy_render/src/mesh/components.rs index 2e712c8054..d95953358b 100644 --- a/crates/bevy_render/src/mesh/components.rs +++ b/crates/bevy_render/src/mesh/components.rs @@ -1,7 +1,7 @@ use crate::{mesh::Mesh, view::Visibility}; use bevy_asset::{AssetId, Handle}; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_ecs::{component::Component, prelude::require, reflect::ReflectComponent}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_transform::components::Transform; use derive_more::derive::From; diff --git a/crates/bevy_scene/src/components.rs b/crates/bevy_scene/src/components.rs index c1d70776e3..cf729662f7 100644 --- a/crates/bevy_scene/src/components.rs +++ b/crates/bevy_scene/src/components.rs @@ -1,6 +1,6 @@ use bevy_asset::Handle; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::component::Component; +use bevy_ecs::component::{require, Component}; use bevy_reflect::Reflect; use bevy_transform::components::Transform; use derive_more::derive::From; diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 5305d023b4..967877d2d7 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -1,6 +1,9 @@ use bevy_asset::{Assets, Handle}; use bevy_color::Color; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_ecs::{ + component::{require, Component}, + reflect::ReflectComponent, +}; use bevy_image::Image; use bevy_math::{Rect, UVec2, Vec2}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 03dd84d073..f0e1a9fa44 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -7,9 +7,9 @@ use crate::{ use bevy_asset::Assets; use bevy_color::LinearRgba; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::component::Component; use bevy_ecs::{ change_detection::{DetectChanges, Ref}, + component::{require, Component}, entity::Entity, prelude::{ReflectComponent, With}, query::{Changed, Without}, diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 9522d3de37..1fcc87c272 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -3,7 +3,7 @@ use bevy_math::{Affine3A, Dir3, Isometry3d, Mat3, Mat4, Quat, Vec3}; use core::ops::Mul; #[cfg(feature = "bevy-support")] use { - bevy_ecs::{component::Component, reflect::ReflectComponent}, + bevy_ecs::{component::Component, prelude::require, reflect::ReflectComponent}, bevy_reflect::prelude::*, }; diff --git a/crates/bevy_ui/src/ui_material.rs b/crates/bevy_ui/src/ui_material.rs index 741bddfa29..c6e70a69cd 100644 --- a/crates/bevy_ui/src/ui_material.rs +++ b/crates/bevy_ui/src/ui_material.rs @@ -1,7 +1,10 @@ use crate::Node; use bevy_asset::{Asset, AssetId, Handle}; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_ecs::{ + component::{require, Component}, + reflect::ReflectComponent, +}; use bevy_reflect::{prelude::ReflectDefault, Reflect}; use bevy_render::{ extract_component::ExtractComponent, diff --git a/crates/bevy_ui/src/widget/button.rs b/crates/bevy_ui/src/widget/button.rs index 82ca41b021..8445a4ad62 100644 --- a/crates/bevy_ui/src/widget/button.rs +++ b/crates/bevy_ui/src/widget/button.rs @@ -1,5 +1,8 @@ use crate::{FocusPolicy, Interaction, Node}; -use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; +use bevy_ecs::{ + prelude::{require, Component}, + reflect::ReflectComponent, +}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; /// Marker struct for buttons diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 9d13270aaa..1b365c07e6 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -8,7 +8,7 @@ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ change_detection::DetectChanges, entity::{Entity, EntityHashMap}, - prelude::Component, + prelude::{require, Component}, query::With, reflect::ReflectComponent, system::{Local, Query, Res, ResMut},