Skip to content

Commit a070748

Browse files
committed
implement and require derive(Component)
1 parent 6301b72 commit a070748

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+486
-276
lines changed

crates/bevy_app/src/app_builder.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use crate::{
44
CoreStage, PluginGroup, PluginGroupBuilder, StartupStage,
55
};
66
use bevy_ecs::{
7-
component::{Component, ComponentDescriptor},
7+
component::ComponentDescriptor,
88
event::Events,
99
schedule::{
1010
RunOnce, Schedule, Stage, StageLabel, State, SystemDescriptor, SystemSet, SystemStage,
1111
},
12-
system::{IntoExclusiveSystem, IntoSystem},
12+
system::{IntoExclusiveSystem, IntoSystem, Resource},
1313
world::{FromWorld, World},
1414
};
1515
use bevy_utils::tracing::debug;
@@ -252,7 +252,7 @@ impl AppBuilder {
252252
/// adding [State::get_driver] to additional stages you need it in.
253253
pub fn add_state<T>(&mut self, initial: T) -> &mut Self
254254
where
255-
T: Component + Debug + Clone + Eq + Hash,
255+
T: Resource + Debug + Clone + Eq + Hash,
256256
{
257257
self.add_state_to_stage(CoreStage::Update, initial)
258258
}
@@ -264,7 +264,7 @@ impl AppBuilder {
264264
/// stages you need it in.
265265
pub fn add_state_to_stage<T>(&mut self, stage: impl StageLabel, initial: T) -> &mut Self
266266
where
267-
T: Component + Debug + Clone + Eq + Hash,
267+
T: Resource + Debug + Clone + Eq + Hash,
268268
{
269269
self.insert_resource(State::new(initial))
270270
.add_system_set_to_stage(stage, State::<T>::get_driver())
@@ -292,7 +292,7 @@ impl AppBuilder {
292292
/// and inserting a `Events::<T>::update_system` system into `CoreStage::First`.
293293
pub fn add_event<T>(&mut self) -> &mut Self
294294
where
295-
T: Component,
295+
T: Resource,
296296
{
297297
self.insert_resource(Events::<T>::default())
298298
.add_system_to_stage(CoreStage::First, Events::<T>::update_system.system())
@@ -318,7 +318,7 @@ impl AppBuilder {
318318
/// ```
319319
pub fn insert_resource<T>(&mut self, resource: T) -> &mut Self
320320
where
321-
T: Component,
321+
T: Resource,
322322
{
323323
self.app.world.insert_resource(resource);
324324
self

crates/bevy_asset/src/handle.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
path::{AssetPath, AssetPathId},
1010
Asset, Assets,
1111
};
12-
use bevy_ecs::reflect::ReflectComponent;
12+
use bevy_ecs::{component::Component, reflect::ReflectComponent};
1313
use bevy_reflect::{Reflect, ReflectDeserialize};
1414
use bevy_utils::Uuid;
1515
use crossbeam_channel::{Receiver, Sender};
@@ -58,7 +58,7 @@ impl HandleId {
5858
///
5959
/// Handles contain a unique id that corresponds to a specific asset in the [Assets](crate::Assets)
6060
/// collection.
61-
#[derive(Reflect)]
61+
#[derive(Component, Reflect)]
6262
#[reflect(Component)]
6363
pub struct Handle<T>
6464
where

crates/bevy_asset/src/loader.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ use crate::{
33
RefChangeChannel,
44
};
55
use anyhow::Result;
6-
use bevy_ecs::{
7-
component::Component,
8-
system::{Res, ResMut},
9-
};
6+
use bevy_ecs::system::{Res, ResMut};
107
use bevy_reflect::{TypeUuid, TypeUuidDynamic};
118
use bevy_tasks::TaskPool;
129
use bevy_utils::{BoxedFuture, HashMap};
@@ -146,20 +143,20 @@ impl<'a> LoadContext<'a> {
146143

147144
/// The result of loading an asset of type `T`
148145
#[derive(Debug)]
149-
pub struct AssetResult<T: Component> {
146+
pub struct AssetResult<T> {
150147
pub asset: Box<T>,
151148
pub id: HandleId,
152149
pub version: usize,
153150
}
154151

155152
/// A channel to send and receive [AssetResult]s
156153
#[derive(Debug)]
157-
pub struct AssetLifecycleChannel<T: Component> {
154+
pub struct AssetLifecycleChannel<T> {
158155
pub sender: Sender<AssetLifecycleEvent<T>>,
159156
pub receiver: Receiver<AssetLifecycleEvent<T>>,
160157
}
161158

162-
pub enum AssetLifecycleEvent<T: Component> {
159+
pub enum AssetLifecycleEvent<T> {
163160
Create(AssetResult<T>),
164161
Free(HandleId),
165162
}
@@ -193,7 +190,7 @@ impl<T: AssetDynamic> AssetLifecycle for AssetLifecycleChannel<T> {
193190
}
194191
}
195192

196-
impl<T: Component> Default for AssetLifecycleChannel<T> {
193+
impl<T> Default for AssetLifecycleChannel<T> {
197194
fn default() -> Self {
198195
let (sender, receiver) = crossbeam_channel::unbounded();
199196
AssetLifecycleChannel { sender, receiver }

crates/bevy_core/src/label.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bevy_ecs::{
2+
component::Component,
23
entity::Entity,
34
query::Changed,
45
reflect::ReflectComponent,
@@ -13,7 +14,7 @@ use std::{
1314
};
1415

1516
/// A collection of labels
16-
#[derive(Default, Reflect)]
17+
#[derive(Component, Default, Reflect)]
1718
#[reflect(Component)]
1819
pub struct Labels {
1920
labels: HashSet<Cow<'static, str>>,

crates/bevy_core/src/name.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_ecs::reflect::ReflectComponent;
1+
use bevy_ecs::{component::Component, reflect::ReflectComponent};
22
use bevy_reflect::Reflect;
33
use bevy_utils::AHasher;
44
use std::{
@@ -8,7 +8,7 @@ use std::{
88
};
99

1010
/// Component used to identify an entity. Stores a hash for faster comparisons
11-
#[derive(Debug, Clone, Reflect)]
11+
#[derive(Component, Debug, Clone, Reflect)]
1212
#[reflect(Component)]
1313
pub struct Name {
1414
hash: u64, // TODO: Shouldn't be serialized

crates/bevy_core/src/time/stopwatch.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_ecs::reflect::ReflectComponent;
1+
use bevy_ecs::{component::Component, reflect::ReflectComponent};
22
use bevy_reflect::Reflect;
33
use bevy_utils::Duration;
44

@@ -23,7 +23,7 @@ use bevy_utils::Duration;
2323
/// assert!(stopwatch.paused());
2424
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
2525
/// ```
26-
#[derive(Clone, Debug, Default, Reflect)]
26+
#[derive(Component, Clone, Debug, Default, Reflect)]
2727
#[reflect(Component)]
2828
pub struct Stopwatch {
2929
elapsed: Duration,

crates/bevy_core/src/time/timer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::Stopwatch;
2-
use bevy_ecs::reflect::ReflectComponent;
2+
use bevy_ecs::{component::Component, reflect::ReflectComponent};
33
use bevy_reflect::Reflect;
44
use bevy_utils::Duration;
55

@@ -10,7 +10,7 @@ use bevy_utils::Duration;
1010
/// exceeded, and can still be reset at any given point.
1111
///
1212
/// Paused timers will not have elapsed time increased.
13-
#[derive(Clone, Debug, Default, Reflect)]
13+
#[derive(Component, Clone, Debug, Default, Reflect)]
1414
#[reflect(Component)]
1515
pub struct Timer {
1616
stopwatch: Stopwatch,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use proc_macro::TokenStream;
2+
use quote::quote;
3+
use syn::{parse_macro_input, parse_quote, DeriveInput, Path};
4+
5+
pub fn derive_component(input: TokenStream) -> TokenStream {
6+
let mut ast = parse_macro_input!(input as DeriveInput);
7+
let bevy_ecs_path: Path = crate::bevy_ecs_path();
8+
9+
ast.generics
10+
.make_where_clause()
11+
.predicates
12+
.push(parse_quote! { Self: Send + Sync + 'static });
13+
14+
let struct_name = &ast.ident;
15+
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
16+
17+
TokenStream::from(quote! {
18+
impl #impl_generics #bevy_ecs_path::component::Component for #struct_name #type_generics #where_clause {}
19+
})
20+
}

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
extern crate proc_macro;
22

3+
mod component;
4+
35
use bevy_macro_utils::BevyManifest;
46
use proc_macro::TokenStream;
57
use proc_macro2::{Span, TokenStream as TokenStream2};
@@ -470,6 +472,11 @@ fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
470472
}
471473
}
472474

473-
fn bevy_ecs_path() -> syn::Path {
475+
pub(crate) fn bevy_ecs_path() -> syn::Path {
474476
BevyManifest::default().get_path("bevy_ecs")
475477
}
478+
479+
#[proc_macro_derive(Component)]
480+
pub fn derive_component(input: TokenStream) -> TokenStream {
481+
component::derive_component(input)
482+
}

crates/bevy_ecs/src/change_detection.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::component::{Component, ComponentTicks};
1+
use crate::{component::ComponentTicks, system::Resource};
22
use bevy_reflect::Reflect;
33
use std::ops::{Deref, DerefMut};
44

@@ -141,14 +141,14 @@ pub(crate) struct Ticks<'a> {
141141
/// Panics when used as a [`SystemParameter`](crate::system::SystemParam) if the resource does not exist.
142142
///
143143
/// Use `Option<ResMut<T>>` instead if the resource might not always exist.
144-
pub struct ResMut<'a, T: Component> {
144+
pub struct ResMut<'a, T: Resource> {
145145
pub(crate) value: &'a mut T,
146146
pub(crate) ticks: Ticks<'a>,
147147
}
148148

149-
change_detection_impl!(ResMut<'a, T>, T, Component);
150-
impl_into_inner!(ResMut<'a, T>, T, Component);
151-
impl_debug!(ResMut<'a, T>, Component);
149+
change_detection_impl!(ResMut<'a, T>, T, Resource);
150+
impl_into_inner!(ResMut<'a, T>, T, Resource);
151+
impl_debug!(ResMut<'a, T>, Resource);
152152

153153
/// Unique mutable borrow of an entity's component
154154
pub struct Mut<'a, T> {

crates/bevy_ecs/src/component/mod.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ mod type_info;
22

33
pub use type_info::*;
44

5-
use crate::storage::SparseSetIndex;
5+
use crate::{storage::SparseSetIndex, system::Resource};
6+
pub use bevy_ecs_macros::Component;
67
use std::{
78
alloc::Layout,
89
any::{Any, TypeId},
@@ -13,7 +14,7 @@ use thiserror::Error;
1314
/// A component is data associated with an [`Entity`](crate::entity::Entity). Each entity can have
1415
/// multiple different types of components, but only one of them per type.
1516
///
16-
/// Any type that is `Send + Sync + 'static` automatically implements `Component`.
17+
/// Any type that is `Send + Sync + 'static` can implement `Component` using `#[derive(Component)]`.
1718
///
1819
/// Components are added with new entities using [`Commands::spawn`](crate::system::Commands::spawn),
1920
/// or to existing entities with [`EntityCommands::insert`](crate::system::EntityCommands::insert),
@@ -24,7 +25,26 @@ use thiserror::Error;
2425
///
2526
/// Components can be grouped together into a [`Bundle`](crate::bundle::Bundle).
2627
pub trait Component: Send + Sync + 'static {}
27-
impl<T: Send + Sync + 'static> Component for T {}
28+
29+
// ECS dependencies cannot derive Component, so we must implement it manually for relevant structs.
30+
impl<T> Component for bevy_tasks::Task<T> where Self: Send + Sync + 'static {}
31+
32+
// For our own convinience, let's implement Component for primitives in tests.
33+
// It will eventually be removed, once tests are not using them anymore.
34+
// Consider those impls deprecated.
35+
#[cfg(test)]
36+
mod private_test_component_impls {
37+
use super::Component;
38+
impl Component for &'static str {}
39+
impl Component for usize {}
40+
impl Component for i32 {}
41+
impl Component for u32 {}
42+
impl Component for u64 {}
43+
impl Component for f32 {}
44+
impl Component for f64 {}
45+
impl Component for u8 {}
46+
impl Component for bool {}
47+
}
2848

2949
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
3050
pub enum StorageType {
@@ -262,7 +282,7 @@ impl Components {
262282
}
263283

264284
#[inline]
265-
pub fn get_or_insert_resource_id<T: Component>(&mut self) -> ComponentId {
285+
pub fn get_or_insert_resource_id<T: Resource>(&mut self) -> ComponentId {
266286
self.get_or_insert_resource_with(TypeId::of::<T>(), TypeInfo::of::<T>)
267287
}
268288

crates/bevy_ecs/src/event.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
use crate as bevy_ecs;
2-
use crate::{
3-
component::Component,
4-
system::{Local, Res, ResMut, SystemParam},
5-
};
1+
use crate::system::{Local, Res, ResMut, SystemParam};
2+
use crate::{self as bevy_ecs, system::Resource};
63
use bevy_utils::tracing::trace;
74
use std::{
85
fmt::{self},
@@ -151,18 +148,18 @@ fn map_instance_event<T>(event_instance: &EventInstance<T>) -> &T {
151148

152149
/// Reads events of type `T` in order and tracks which events have already been read.
153150
#[derive(SystemParam)]
154-
pub struct EventReader<'a, T: Component> {
151+
pub struct EventReader<'a, T: Resource> {
155152
last_event_count: Local<'a, (usize, PhantomData<T>)>,
156153
events: Res<'a, Events<T>>,
157154
}
158155

159156
/// Sends events of type `T`.
160157
#[derive(SystemParam)]
161-
pub struct EventWriter<'a, T: Component> {
158+
pub struct EventWriter<'a, T: Resource> {
162159
events: ResMut<'a, Events<T>>,
163160
}
164161

165-
impl<'a, T: Component> EventWriter<'a, T> {
162+
impl<'a, T: Resource> EventWriter<'a, T> {
166163
pub fn send(&mut self, event: T) {
167164
self.events.send(event);
168165
}
@@ -252,7 +249,7 @@ fn internal_event_reader<'a, T>(
252249
}
253250
}
254251

255-
impl<'a, T: Component> EventReader<'a, T> {
252+
impl<'a, T: Resource> EventReader<'a, T> {
256253
/// Iterates over the events this EventReader has not seen yet. This updates the EventReader's
257254
/// event counter, which means subsequent event reads will not include events that happened
258255
/// before now.
@@ -269,7 +266,7 @@ impl<'a, T: Component> EventReader<'a, T> {
269266
}
270267
}
271268

272-
impl<T: Component> Events<T> {
269+
impl<T: Resource> Events<T> {
273270
/// "Sends" an `event` by writing it to the current event buffer. [EventReader]s can then read
274271
/// the event.
275272
pub fn send(&mut self, event: T) {

crates/bevy_ecs/src/lib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub mod prelude {
2020
pub use crate::{
2121
bundle::Bundle,
2222
change_detection::DetectChanges,
23+
component::Component,
2324
entity::Entity,
2425
event::{EventReader, EventWriter},
2526
query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without},
@@ -58,12 +59,14 @@ mod tests {
5859
},
5960
};
6061

61-
#[derive(Debug, PartialEq, Eq)]
62+
#[derive(Component, Debug, PartialEq, Eq)]
6263
struct A(usize);
64+
#[derive(Component)]
6365
struct B(usize);
66+
#[derive(Component)]
6467
struct C;
6568

66-
#[derive(Clone, Debug)]
69+
#[derive(Component, Clone, Debug)]
6770
struct DropCk(Arc<AtomicUsize>);
6871
impl DropCk {
6972
fn new_pair() -> (Self, Arc<AtomicUsize>) {
@@ -760,7 +763,7 @@ mod tests {
760763
let e1 = world.spawn().insert_bundle((A(0), B(0))).id();
761764
let e2 = world.spawn().insert_bundle((A(0), B(0))).id();
762765
let e3 = world.spawn().insert_bundle((A(0), B(0))).id();
763-
world.spawn().insert_bundle((A(0), B));
766+
world.spawn().insert_bundle((A(0), B(0)));
764767

765768
world.clear_trackers();
766769

@@ -788,7 +791,7 @@ mod tests {
788791
assert_eq!(get_filtered::<Changed<A>>(&mut world), vec![e3, e1], "changed entities list should not change (although the order will due to archetype moves)");
789792

790793
// spawning a new A entity should not change existing changed state
791-
world.entity_mut(e1).insert_bundle((A(0), B));
794+
world.entity_mut(e1).insert_bundle((A(0), B(0)));
792795
assert_eq!(
793796
get_filtered::<Changed<A>>(&mut world),
794797
vec![e3, e1],

0 commit comments

Comments
 (0)