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}