moonshine_util/component.rs
1//! Utilities related to [`Component`] management.
2
3use std::marker::PhantomData;
4
5use bevy_ecs::component::Mutable;
6use bevy_ecs::lifecycle::HookContext;
7use bevy_ecs::prelude::*;
8use bevy_ecs::world::DeferredWorld;
9
10use crate::Static;
11
12/// Any [`Component`] which can be merged with itself.
13///
14/// See [`Merge<T>`] for detailed usage and examples.
15pub trait MergeComponent: Component<Mutability = Mutable> {
16 /// Merges the contents of `other` into this [`Component`].
17 fn merge(&mut self, other: Self);
18}
19
20/// An [`EntityCommand`] which is used to add components.
21///
22/// # Usage
23/// It is impossible to have duplicate components on an [`Entity`] in Bevy.
24/// However, in some cases, multiple instances of some components can be "merged" into one.
25///
26/// If a component implements [`MergeComponent`], you can use this command to merge multiple instances
27/// of the component into one.
28///
29/// ```rust
30/// use bevy::prelude::*;
31/// use moonshine_util::prelude::*;
32///
33/// #[derive(Component, Default)]
34/// struct N(usize);
35///
36/// impl MergeComponent for N {
37/// fn merge(&mut self, other: Self) {
38/// self.0 += other.0;
39/// }
40/// }
41///
42/// let mut world = World::new();
43/// let entity = world.spawn_empty().id();
44/// world.commands().entity(entity).queue(Merge(N(1)));
45/// world.commands().entity(entity).queue(Merge(N(2)));
46/// world.flush();
47/// let &N(value) = world.get(entity).unwrap();
48/// assert_eq!(value, 3);
49/// ```
50///
51/// This command may also be used as a [`Component`] itself. This can be used in a [`Bundle`] or as a
52/// requirement to merge components.
53///
54/// ```rust
55/// use bevy::prelude::*;
56/// use moonshine_util::prelude::*;
57///
58/// #[derive(Component, Default)]
59/// struct N(usize);
60///
61/// impl MergeComponent for N {
62/// fn merge(&mut self, other: Self) {
63/// self.0 += other.0;
64/// }
65/// }
66///
67/// let mut world = World::new();
68/// let entity = world.spawn((N(1), Merge(N(2))));
69/// let &N(value) = entity.get().unwrap();
70/// assert_eq!(value, 3);
71/// ```
72///
73/// Because [`Merge<T>`] is a component itself, it can be used as a component requirement.
74/// However, because of the component uniqueness rule, multiple [`Merge<T>`] instances may not exist on the same entity.
75/// To work around this, you can use [`MergeFrom`] and [`MergeWith`].
76#[derive(Component)]
77#[component(on_insert = Self::on_insert)]
78pub struct Merge<T: MergeComponent>(pub T);
79
80impl<T: MergeComponent> Merge<T> {
81 /// Ergonomic alias for [`MergeWith::new`].
82 pub fn with<F: Static + FnOnce() -> T>(f: F) -> MergeWith<T, impl Static + FnOnce() -> T> {
83 MergeWith::new(f)
84 }
85
86 fn on_insert(mut world: DeferredWorld, ctx: HookContext) {
87 world
88 .commands()
89 .entity(ctx.entity)
90 .queue(|mut entity: EntityWorldMut| {
91 entity.take::<Self>().unwrap().apply(entity);
92 });
93 }
94}
95
96impl<T: MergeComponent> From<T> for Merge<T> {
97 fn from(value: T) -> Self {
98 Self(value)
99 }
100}
101
102impl<T: MergeComponent> EntityCommand for Merge<T> {
103 fn apply(self, mut entity: EntityWorldMut) {
104 let Self(source) = self;
105 if let Some(mut target) = entity.get_mut::<T>() {
106 target.merge(source);
107 } else {
108 entity.insert(source);
109 }
110 }
111}
112
113/// A [`Component`] which is used to merge components as requirements.
114///
115/// # Usage
116/// Because [`Merge<T>`] is a component itself, it can be used as a component requirement.
117/// This type may instead be used to work around this restriction:
118///
119/// ```rust
120/// use bevy::prelude::*;
121/// use moonshine_util::prelude::*;
122///
123/// #[derive(Component, Default)]
124/// struct N(usize);
125///
126/// impl MergeComponent for N {
127/// fn merge(&mut self, other: Self) {
128/// self.0 += other.0;
129/// }
130/// }
131///
132/// #[derive(Component, Default)]
133/// #[require(MergeFrom<Self, N> = N(1))]
134/// struct A;
135///
136/// #[derive(Component, Default)]
137/// #[require(A, MergeFrom<Self, N> = N(2))]
138/// struct B;
139///
140/// let mut world = World::new();
141/// let entity = world.spawn(B);
142/// let &N(value) = entity.get().unwrap();
143/// assert_eq!(value, 3);
144/// ```
145#[derive(Component)]
146#[component(on_insert = Self::on_insert)]
147pub struct MergeFrom<M: Static, T: MergeComponent>(Merge<T>, PhantomData<M>);
148
149impl<M: Static, T: MergeComponent> MergeFrom<M, T> {
150 fn on_insert(mut world: DeferredWorld, ctx: HookContext) {
151 world
152 .commands()
153 .entity(ctx.entity)
154 .queue(|mut entity: EntityWorldMut| {
155 let Self(inner, ..) = entity.take::<Self>().unwrap();
156 inner.apply(entity);
157 });
158 }
159}
160
161impl<M: Static, T: MergeComponent> From<T> for MergeFrom<M, T> {
162 fn from(value: T) -> Self {
163 Self(Merge(value), PhantomData)
164 }
165}
166/// A [`Component`] which is used to merge components as requirements.
167///
168/// # Usage
169/// Because [`Merge<T>`] is a component itself, it can be used as a component requirement.
170/// This type may instead be used to work around this restriction:
171///
172/// ```rust
173/// use bevy::prelude::*;
174/// use moonshine_util::prelude::*;
175///
176/// #[derive(Component, Default)]
177/// struct N(usize);
178///
179/// impl MergeComponent for N {
180/// fn merge(&mut self, other: Self) {
181/// self.0 += other.0;
182/// }
183/// }
184///
185/// let mut world = World::new();
186/// let entity = world.spawn((Merge::with(|| N(1)), Merge::with(|| N(2))));
187/// let &N(value) = entity.get().unwrap();
188/// assert_eq!(value, 3);
189/// ```
190#[derive(Component)]
191#[component(on_insert = Self::on_insert)]
192pub struct MergeWith<T: MergeComponent, F: Static + FnOnce() -> T>(F, PhantomData<T>);
193
194impl<F: Static + FnOnce() -> T, T: MergeComponent> MergeWith<T, F> {
195 /// Creates a new [`MergeWith`] [`Component`] for the given [`FnOnce`].
196 ///
197 /// See [`Merge::with`] for a more ergonomic constructor.
198 pub fn new(f: F) -> Self {
199 Self(f, PhantomData)
200 }
201
202 fn on_insert(mut world: DeferredWorld, ctx: HookContext) {
203 world
204 .commands()
205 .entity(ctx.entity)
206 .queue(|mut entity: EntityWorldMut| {
207 let Self(f, ..) = entity.take::<Self>().unwrap();
208 Merge(f()).apply(entity);
209 });
210 }
211}
212
213impl<F: Static + FnOnce() -> T, T: MergeComponent> From<F> for MergeWith<T, F> {
214 fn from(f: F) -> Self {
215 Self::new(f)
216 }
217}
218
219/// A convenient macro for defining a pair of [`Relationship`] and [`RelationshipTarget`] component.
220///
221/// ```rust
222/// use bevy::prelude::*;
223/// use moonshine_util::prelude::*;
224///
225/// relationship! {
226/// #[derive(Default)]
227/// pub Friends(Vec<Entity>) -> { pub FriendOf(pub Entity) }
228/// }
229///
230/// let mut w = World::new();
231/// let a = w.spawn_empty().id();
232/// let b = w.spawn(FriendOf(a)).id();
233///
234/// assert!(w
235/// .get::<Friends>(a)
236/// .is_some_and(|Friends(friends)| friends[0] == b));
237/// ```
238///
239/// [`Relationship`]: bevy_ecs::relationship::Relationship
240/// [`RelationshipTarget`]: bevy_ecs::relationship::RelationshipTarget
241#[macro_export]
242macro_rules! relationship {
243 {
244 $(#[$target_attr:meta])*
245 $target_vis:vis $target:ident($(#[$target_inner_attr:meta])* $target_inner_vis:vis $target_inner:ty)
246 -> {
247 $(#[$source_attr:meta])*
248 $source_vis:vis $source:ident($(#[$source_inner_attr:meta])* $source_inner_vis:vis $source_inner:ty)
249 }
250 } => {
251 relationship! {
252 $(#[$target_attr])* $target_vis $target($target_inner_vis $target_inner) -> [] {
253 $(#[$source_attr])* $source_vis $source($source_inner_vis $source_inner)
254 }
255 }
256 };
257
258 {
259 $(#[$target_attr:meta])*
260 $target_vis:vis $target:ident($(#[$target_inner_attr:meta])* $target_inner_vis:vis $target_inner:ty)
261 -> [$($options:expr),*] {
262 $(#[$source_attr:meta])*
263 $source_vis:vis $source:ident($(#[$source_inner_attr:meta])* $source_inner_vis:vis $source_inner:ty)
264 }
265 } => {
266 $(#[$target_attr])*
267 #[derive(Component)]
268 #[relationship_target(relationship = $source, $($options),*)]
269 $target_vis struct $target($(#[$target_inner_attr])* $target_inner_vis $target_inner);
270
271 $(#[$source_attr])*
272 #[derive(Component)]
273 #[relationship(relationship_target = $target)]
274 $source_vis struct $source($(#[$source_inner_attr])* $source_inner_vis $source_inner);
275 };
276}
277
278#[test]
279fn test_merge_component() {
280 #[derive(Component, Default)]
281 struct N(usize);
282
283 impl MergeComponent for N {
284 fn merge(&mut self, other: Self) {
285 self.0 += other.0;
286 }
287 }
288
289 #[derive(Component, Default)]
290 #[require(MergeFrom<Self, N> = N(1))]
291 struct A;
292
293 #[derive(Component, Default)]
294 #[require(A, MergeFrom<Self, N> = N(2))]
295 struct B;
296
297 #[derive(Component, Default)]
298 #[require(A, B)]
299 struct C;
300
301 let mut w = World::new();
302 let e = w.spawn(C);
303 let &N(v) = e.get().unwrap();
304
305 assert_eq!(v, 3);
306}
307
308#[test]
309fn test_relationship_linked_spawn() {
310 relationship! {
311 pub Owner(Vec<Entity>) -> [linked_spawn] {
312 pub OwnedBy(pub Entity)
313 }
314 }
315
316 let mut w = World::new();
317 let a = w.spawn_empty().id();
318 let b = w.spawn(OwnedBy(a)).id();
319 assert_eq!(w.get::<Owner>(a).unwrap().0[0], b);
320 assert!(w.entities().contains(b));
321
322 w.entity_mut(a).despawn();
323 assert!(!w.entities().contains(b));
324}