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
103impl SpawnInstance for Commands<'_, '_> {
104    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
105        let entity = self.spawn(instance).id();
106        // SAFE: `entity` is spawned as a valid instance of kind `T`.
107        unsafe { InstanceCommands::from_entity_unchecked(self.entity(entity)) }
108    }
109}
110
111/// Extension trait used to spawn instances via [`World`].
112pub trait SpawnInstanceWorld {
113    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceRef<T>`] for it.
114    fn spawn_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T>;
115
116    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceMut<T>`] for it.
117    fn spawn_instance_mut<T: Component<Mutability = Mutable>>(
118        &'_ mut self,
119        instance: T,
120    ) -> InstanceMut<'_, T>;
121}
122
123impl SpawnInstanceWorld for World {
124    fn spawn_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T> {
125        let mut entity = self.spawn_empty();
126        entity.insert(instance);
127        // SAFE: `entity` is spawned as a valid instance of kind `T`.
128        unsafe { InstanceRef::from_entity_unchecked(entity.into_readonly()) }
129    }
130
131    fn spawn_instance_mut<T: Component<Mutability = Mutable>>(
132        &'_ mut self,
133        instance: T,
134    ) -> InstanceMut<'_, T> {
135        let mut entity = self.spawn_empty();
136        entity.insert(instance);
137        // SAFE: `entity` is spawned as a valid instance of kind `T`.
138        unsafe { InstanceMut::from_entity_unchecked(entity.into_mutable()) }
139    }
140}
141
142/// Extension trait used to insert instances via [`EntityCommands`].
143pub trait InsertInstance {
144    /// Inserts the given instance of `T` into the entity and returns an [`InstanceCommands<T>`] for it.
145    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
146}
147
148impl InsertInstance for EntityCommands<'_> {
149    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
150        self.insert(instance);
151        // SAFE: `entity` is spawned as a valid instance of kind `T`.
152        unsafe { InstanceCommands::from_entity_unchecked(self.reborrow()) }
153    }
154}
155
156/// Extension trait used to insert instances via [`EntityWorldMut`].
157pub trait InsertInstanceWorld {
158    /// Inserts the given instance of `T` into the entity and returns an [`InstanceRef<T>`] for it.
159    fn insert_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T>;
160
161    /// Inserts the given instance of `T` into the entity and returns an [`InstanceMut<T>`] for it.
162    ///
163    /// This requires `T` to be [`Mutable`].
164    fn insert_instance_mut<T: Component<Mutability = Mutable>>(
165        &'_ mut self,
166        instance: T,
167    ) -> InstanceMut<'_, T>;
168}
169
170impl InsertInstanceWorld for EntityWorldMut<'_> {
171    fn insert_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T> {
172        self.insert(instance);
173        InstanceRef::from_entity(self.as_readonly()).unwrap()
174    }
175
176    fn insert_instance_mut<T: Component<Mutability = Mutable>>(
177        &'_ mut self,
178        instance: T,
179    ) -> InstanceMut<'_, T> {
180        self.insert(instance);
181        InstanceMut::from_entity(self.as_mutable()).unwrap()
182    }
183}
184
185/// Extension trait used to get [`Component`] data from an [`Instance<T>`] via [`World`].
186pub trait ComponentInstance {
187    /// Returns a reference to the given instance.
188    ///
189    /// # Panics
190    ///
191    /// If the given `instance` is not a valid entity of kind `T`.
192    fn instance<T: Component>(&'_ self, instance: Instance<T>) -> InstanceRef<'_, T> {
193        self.get_instance(instance.entity()).unwrap()
194    }
195
196    /// Returns a reference to the given instance, if it is of [`Kind`] `T`.
197    fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>>;
198
199    /// Returns a mutable reference to the given instance.
200    ///
201    /// This requires `T` to be [`Mutable`].
202    ///
203    /// # Panics
204    ///
205    /// If the given `instance` is not a valid entity of kind `T`.
206    fn instance_mut<T: Component<Mutability = Mutable>>(
207        &'_ mut self,
208        instance: Instance<T>,
209    ) -> InstanceMut<'_, T> {
210        self.get_instance_mut(instance.entity()).unwrap()
211    }
212
213    /// Returns a mutable reference to the given instance, if it is of [`Kind`] `T`.
214    ///
215    /// This requires `T` to be [`Mutable`].
216    fn get_instance_mut<T: Component<Mutability = Mutable>>(
217        &'_ mut self,
218        entity: Entity,
219    ) -> Option<InstanceMut<'_, T>>;
220}
221
222impl ComponentInstance for World {
223    fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>> {
224        InstanceRef::from_entity(self.get_entity(entity).ok()?)
225    }
226
227    fn get_instance_mut<T: Component<Mutability = Mutable>>(
228        &'_ mut self,
229        entity: Entity,
230    ) -> Option<InstanceMut<'_, T>> {
231        InstanceMut::from_entity(self.get_entity_mut(entity).ok()?.into_mutable())
232    }
233}
234
235impl ComponentInstance for DeferredWorld<'_> {
236    fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>> {
237        InstanceRef::from_entity(self.get_entity(entity).ok()?)
238    }
239
240    fn get_instance_mut<T: Component<Mutability = Mutable>>(
241        &'_ mut self,
242        entity: Entity,
243    ) -> Option<InstanceMut<'_, T>> {
244        InstanceMut::from_entity(self.get_entity_mut(entity).ok()?)
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251    use bevy_ecs::system::RunSystemOnce;
252
253    fn count<T: Kind>(query: Query<Instance<T>>) -> usize {
254        query.iter().count()
255    }
256
257    #[test]
258    fn kind_with() {
259        #[derive(Component)]
260        struct Foo;
261
262        let mut world = World::new();
263        world.spawn(Foo);
264        assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
265    }
266
267    #[test]
268    fn kind_without() {
269        #[derive(Component)]
270        struct Foo;
271
272        struct NotFoo;
273
274        impl Kind for NotFoo {
275            type Filter = Without<Foo>;
276        }
277
278        let mut world = World::new();
279        world.spawn(Foo);
280        assert_eq!(world.run_system_once(count::<NotFoo>).unwrap(), 0);
281    }
282
283    #[test]
284    fn kind_multi() {
285        #[derive(Component)]
286        struct Foo;
287
288        #[derive(Component)]
289        struct Bar;
290
291        let mut world = World::new();
292        world.spawn((Foo, Bar));
293        assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
294        assert_eq!(world.run_system_once(count::<Bar>).unwrap(), 1);
295    }
296
297    #[test]
298    fn kind_cast() {
299        #[derive(Component)]
300        struct Foo;
301
302        #[derive(Component)]
303        struct Bar;
304
305        impl CastInto<Bar> for Foo {}
306
307        let any = Instance::<Any>::PLACEHOLDER;
308        let foo = Instance::<Foo>::PLACEHOLDER;
309        let bar = foo.cast_into::<Bar>();
310        assert!(foo.cast_into_any() == any);
311        assert!(bar.cast_into_any() == any);
312        // assert!(foo.cast_into() == any); // TODO: Can we make this compile?
313        // assert!(any.cast_into::<Foo>() == foo); // <-- Must not compile!
314        // assert!(bar.cast_into::<Foo>() == foo); // <-- Must not compile!
315        assert!(bar.entity() == foo.entity());
316    }
317}