Skip to main content

moonshine_kind/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4/// Prelude module to import all necessary traits and types for [`Kind`] semantics.
5pub mod prelude {
6    pub use crate::{CastInto, Kind};
7    pub use crate::{
8        ComponentInstance, InsertInstance, InsertInstanceWorld, SpawnInstance, SpawnInstanceWorld,
9    };
10    pub use crate::{ContainsInstance, Instance, InstanceMut, InstanceRef};
11    pub use crate::{GetInstanceCommands, InstanceCommands};
12}
13
14mod instance;
15
16use bevy_ecs::world::DeferredWorld;
17use bevy_reflect::Reflect;
18pub use instance::*;
19
20use bevy_ecs::component::Mutable;
21use bevy_ecs::{prelude::*, query::QueryFilter};
22
23/// A type which represents the kind of an [`Entity`].
24///
25/// An entity is of kind `T` if it matches [`Query<Entity, <T as Kind>::Filter>`][`Query`].
26///
27/// By default, an entity with a [`Component`] of type `T` is also of kind `T`.
28///
29/// # Examples
30/// ```
31/// # use bevy::prelude::*;
32/// # use moonshine_kind::prelude::*;
33///
34/// #[derive(Component)]
35/// struct Apple;
36///
37/// #[derive(Component)]
38/// struct Orange;
39///
40/// struct Fruit;
41///
42/// impl Kind for Fruit {
43///     type Filter = Or<(With<Apple>, With<Orange>)>;
44/// }
45///
46/// fn fruits(query: Query<Instance<Fruit>>) {
47///     for fruit in query.iter() {
48///         println!("{fruit:?} is a fruit!");
49///     }
50/// }
51///
52/// # bevy_ecs::system::assert_is_system(fruits);
53/// ```
54pub trait Kind: 'static + Send + Sized + Sync {
55    /// The [`QueryFilter`] which defines this kind.
56    type Filter: QueryFilter;
57
58    /// Returns the debug name of this kind.
59    ///
60    /// By default, this is the short type name (without path) of this kind.
61    /// This is mainly used for [`Debug`](std::fmt::Debug) and [`Display`](std::fmt::Display) implementations.
62    fn debug_name() -> String {
63        disqualified::ShortName::of::<Self>().to_string()
64    }
65}
66
67impl<T: Component> Kind for T {
68    type Filter = With<T>;
69}
70
71/// Represents the kind of any [`Entity`].
72///
73/// See [`Instance<Any>`] for more information on usage.
74#[derive(Debug, Reflect)]
75pub struct Any;
76
77impl Kind for Any {
78    type Filter = ();
79}
80
81/// A trait which allows safe casting from one [`Kind`] to another.
82pub trait CastInto<T: Kind>: Kind {
83    #[doc(hidden)]
84    unsafe fn cast(instance: Instance<Self>) -> Instance<T> {
85        // SAFE: Because we said so.
86        // TODO: Can we use required components to enforce this?
87        Instance::from_entity_unchecked(instance.entity())
88    }
89}
90
91impl<T: Kind> CastInto<T> for T {
92    unsafe fn cast(instance: Instance<Self>) -> Instance<T> {
93        Instance::from_entity_unchecked(instance.entity())
94    }
95}
96
97/// Extension trait used to spawn instances via [`Commands`].
98pub trait SpawnInstance {
99    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceCommands<T>`] for it.
100    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
101
102    /// Spawns a new [`Entity`] and returns an [`InstanceCommands<T>`] for it.
103    ///
104    /// # Safety
105    ///
106    /// This function assumes the given bundle produces an entity of kind T.
107    unsafe fn spawn_instance_unchecked<T: Kind>(
108        &mut self,
109        bundle: impl Bundle,
110    ) -> InstanceCommands<'_, T>;
111}
112
113impl SpawnInstance for Commands<'_, '_> {
114    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
115        let entity = self.spawn(instance);
116        // SAFE: `entity` is spawned as a valid instance of kind `T`.
117        unsafe { InstanceCommands::from_entity_unchecked(entity) }
118    }
119
120    unsafe fn spawn_instance_unchecked<T: Kind>(
121        &mut self,
122        bundle: impl Bundle,
123    ) -> InstanceCommands<'_, T> {
124        let entity = self.spawn(bundle);
125        // SAFE: In the User, we trust.
126        unsafe { InstanceCommands::from_entity_unchecked(entity) }
127    }
128}
129
130/// Extension trait used to spawn instances via [`World`].
131pub trait SpawnInstanceWorld {
132    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceRef<T>`] for it.
133    fn spawn_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T>;
134
135    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceMut<T>`] for it.
136    fn spawn_instance_mut<T: Component<Mutability = Mutable>>(
137        &'_ mut self,
138        instance: T,
139    ) -> InstanceMut<'_, T>;
140}
141
142impl SpawnInstanceWorld for World {
143    fn spawn_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T> {
144        let mut entity = self.spawn_empty();
145        entity.insert(instance);
146        // SAFE: `entity` is spawned as a valid instance of kind `T`.
147        unsafe { InstanceRef::from_entity_unchecked(entity.into_readonly()) }
148    }
149
150    fn spawn_instance_mut<T: Component<Mutability = Mutable>>(
151        &'_ mut self,
152        instance: T,
153    ) -> InstanceMut<'_, T> {
154        let mut entity = self.spawn_empty();
155        entity.insert(instance);
156        // SAFE: `entity` is spawned as a valid instance of kind `T`.
157        unsafe { InstanceMut::from_entity_unchecked(entity.into_mutable()) }
158    }
159}
160
161/// Extension trait used to insert instances via [`EntityCommands`].
162pub trait InsertInstance {
163    /// Inserts the given instance of `T` into the entity and returns an [`InstanceCommands<T>`] for it.
164    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
165}
166
167impl InsertInstance for EntityCommands<'_> {
168    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
169        self.insert(instance);
170        // SAFE: `entity` is spawned as a valid instance of kind `T`.
171        unsafe { InstanceCommands::from_entity_unchecked(self.reborrow()) }
172    }
173}
174
175/// Extension trait used to insert instances via [`EntityWorldMut`].
176pub trait InsertInstanceWorld {
177    /// Inserts the given instance of `T` into the entity and returns an [`InstanceRef<T>`] for it.
178    fn insert_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T>;
179
180    /// Inserts the given instance of `T` into the entity and returns an [`InstanceMut<T>`] for it.
181    ///
182    /// This requires `T` to be [`Mutable`].
183    fn insert_instance_mut<T: Component<Mutability = Mutable>>(
184        &'_ mut self,
185        instance: T,
186    ) -> InstanceMut<'_, T>;
187}
188
189impl InsertInstanceWorld for EntityWorldMut<'_> {
190    fn insert_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T> {
191        self.insert(instance);
192        InstanceRef::from_entity(self.as_readonly()).unwrap()
193    }
194
195    fn insert_instance_mut<T: Component<Mutability = Mutable>>(
196        &'_ mut self,
197        instance: T,
198    ) -> InstanceMut<'_, T> {
199        self.insert(instance);
200        InstanceMut::from_entity(self.as_mutable()).unwrap()
201    }
202}
203
204/// Extension trait used to get [`Component`] data from an [`Instance<T>`] via [`World`].
205pub trait ComponentInstance {
206    /// Returns a reference to the given instance.
207    ///
208    /// # Panics
209    ///
210    /// If the given `instance` is not a valid entity of kind `T`.
211    fn instance<T: Component>(&'_ self, instance: Instance<T>) -> InstanceRef<'_, T> {
212        self.get_instance(instance.entity()).unwrap()
213    }
214
215    /// Returns a reference to the given instance, if it is of [`Kind`] `T`.
216    fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>>;
217
218    /// Returns a mutable reference to the given instance.
219    ///
220    /// This requires `T` to be [`Mutable`].
221    ///
222    /// # Panics
223    ///
224    /// If the given `instance` is not a valid entity of kind `T`.
225    fn instance_mut<T: Component<Mutability = Mutable>>(
226        &'_ mut self,
227        instance: Instance<T>,
228    ) -> InstanceMut<'_, T> {
229        self.get_instance_mut(instance.entity()).unwrap()
230    }
231
232    /// Returns a mutable reference to the given instance, if it is of [`Kind`] `T`.
233    ///
234    /// This requires `T` to be [`Mutable`].
235    fn get_instance_mut<T: Component<Mutability = Mutable>>(
236        &'_ mut self,
237        entity: Entity,
238    ) -> Option<InstanceMut<'_, T>>;
239}
240
241impl ComponentInstance for World {
242    fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>> {
243        InstanceRef::from_entity(self.get_entity(entity).ok()?)
244    }
245
246    fn get_instance_mut<T: Component<Mutability = Mutable>>(
247        &'_ mut self,
248        entity: Entity,
249    ) -> Option<InstanceMut<'_, T>> {
250        InstanceMut::from_entity(self.get_entity_mut(entity).ok()?.into_mutable())
251    }
252}
253
254impl ComponentInstance for DeferredWorld<'_> {
255    fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>> {
256        InstanceRef::from_entity(self.get_entity(entity).ok()?)
257    }
258
259    fn get_instance_mut<T: Component<Mutability = Mutable>>(
260        &'_ mut self,
261        entity: Entity,
262    ) -> Option<InstanceMut<'_, T>> {
263        InstanceMut::from_entity(self.get_entity_mut(entity).ok()?)
264    }
265}
266
267#[cfg(test)]
268mod tests {
269    use super::*;
270    use bevy_ecs::system::RunSystemOnce;
271
272    fn count<T: Kind>(query: Query<Instance<T>>) -> usize {
273        query.iter().count()
274    }
275
276    #[test]
277    fn kind_with() {
278        #[derive(Component)]
279        struct Foo;
280
281        let mut world = World::new();
282        world.spawn(Foo);
283        assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
284    }
285
286    #[test]
287    fn kind_without() {
288        use bevy_ecs::resource::IsResource;
289        #[derive(Component)]
290        struct Foo;
291
292        struct NotFoo;
293
294        impl Kind for NotFoo {
295            // `IsResource` check is needed as of Bevy 0.19 to exclude engine entities
296            type Filter = (Without<Foo>, Without<IsResource>);
297        }
298
299        let mut world = World::new();
300        world.spawn(Foo);
301        assert_eq!(world.run_system_once(count::<NotFoo>).unwrap(), 0);
302    }
303
304    #[test]
305    fn kind_multi() {
306        #[derive(Component)]
307        struct Foo;
308
309        #[derive(Component)]
310        struct Bar;
311
312        let mut world = World::new();
313        world.spawn((Foo, Bar));
314        assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
315        assert_eq!(world.run_system_once(count::<Bar>).unwrap(), 1);
316    }
317
318    #[test]
319    fn kind_cast() {
320        #[derive(Component)]
321        struct Foo;
322
323        #[derive(Component)]
324        struct Bar;
325
326        impl CastInto<Bar> for Foo {}
327
328        let any = Instance::<Any>::PLACEHOLDER;
329        let foo = Instance::<Foo>::PLACEHOLDER;
330        let bar = foo.cast_into::<Bar>();
331        assert!(foo.cast_into_any() == any);
332        assert!(bar.cast_into_any() == any);
333        // assert!(foo.cast_into() == any); // TODO: Can we make this compile?
334        // assert!(any.cast_into::<Foo>() == foo); // <-- Must not compile!
335        // assert!(bar.cast_into::<Foo>() == foo); // <-- Must not compile!
336        assert!(bar.entity() == foo.entity());
337    }
338}