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::{kind, 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
16pub use instance::*;
17
18use bevy_ecs::component::Mutable;
19use bevy_ecs::{prelude::*, query::QueryFilter};
20
21/// A type which represents the kind of an [`Entity`].
22///
23/// An entity is of kind `T` if it matches [`Query<Entity, <T as Kind>::Filter>`][`Query`].
24///
25/// By default, an entity with a [`Component`] of type `T` is also of kind `T`.
26///
27/// # Examples
28/// ```
29/// # use bevy::prelude::*;
30/// # use moonshine_kind::prelude::*;
31///
32/// #[derive(Component)]
33/// struct Apple;
34///
35/// #[derive(Component)]
36/// struct Orange;
37///
38/// struct Fruit;
39///
40/// impl Kind for Fruit {
41///     type Filter = Or<(With<Apple>, With<Orange>)>;
42/// }
43///
44/// fn fruits(query: Query<Instance<Fruit>>) {
45///     for fruit in query.iter() {
46///         println!("{fruit:?} is a fruit!");
47///     }
48/// }
49///
50/// # bevy_ecs::system::assert_is_system(fruits);
51/// ```
52pub trait Kind: 'static + Send + Sized + Sync {
53    /// The [`QueryFilter`] which defines this kind.
54    type Filter: QueryFilter;
55
56    /// Returns the debug name of this kind.
57    ///
58    /// By default, this is the short type name (without path) of this kind.
59    /// This is mainly used for [`Debug`](std::fmt::Debug) and [`Display`](std::fmt::Display) implementations.
60    fn debug_name() -> String {
61        disqualified::ShortName::of::<Self>().to_string()
62    }
63}
64
65impl<T: Component> Kind for T {
66    type Filter = With<T>;
67}
68
69/// Represents the kind of any [`Entity`].
70///
71/// See [`Instance<Any>`] for more information on usage.
72pub struct Any;
73
74impl Kind for Any {
75    type Filter = ();
76}
77
78/// A trait which allows safe casting from one [`Kind`] to another.
79///
80/// Do not implement this trait directly; instead, use the [`kind`] macro.
81pub unsafe trait CastInto<T: Kind>: Kind {
82    /// Casts the given [`Instance`] of `Self` into an instance of `T`.
83    fn cast_into(instance: Instance<Self>) -> Instance<T>;
84}
85
86unsafe impl<T: Kind> CastInto<T> for T {
87    fn cast_into(instance: Instance<Self>) -> Instance<Self> {
88        instance
89    }
90}
91
92/// A macro to safely implement [`CastInto`] for a pair of related [`Kind`]s.
93///
94/// See [`CastInto`] for more information.
95///
96/// # Usage
97/// ```
98/// # use bevy::prelude::*;
99/// # use moonshine_kind::prelude::*;
100///
101/// struct Fruit;
102///
103/// impl Kind for Fruit {
104///    type Filter = With<Apple>;
105/// }
106///
107/// #[derive(Component)]
108/// struct Apple;
109///
110/// // We can guarantee all entities with an `Apple` component are of kind `Fruit`:
111/// kind!(Apple is Fruit);
112///
113/// fn eat_apple(apple: Instance<Apple>) {
114///    println!("Crunch!");
115///    // SAFE: Because we said so.
116///    eat_fruit(apple.cast_into());
117/// }
118///
119/// fn eat_fruit(fruit: Instance<Fruit>) {
120///    println!("Yum!");
121/// }
122/// ```
123#[macro_export]
124macro_rules! kind {
125    ($T:ident is $U:ty) => {
126        unsafe impl $crate::CastInto<$U> for $T {
127            fn cast_into(instance: $crate::Instance<Self>) -> $crate::Instance<$U> {
128                // SAFE: Because we said so!
129                unsafe { instance.cast_into_unchecked() }
130            }
131        }
132    };
133}
134
135/// Extension trait used to spawn instances via [`Commands`].
136pub trait SpawnInstance {
137    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceCommands<T>`] for it.
138    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
139}
140
141impl SpawnInstance for Commands<'_, '_> {
142    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
143        let entity = self.spawn(instance).id();
144        // SAFE: `entity` is spawned as a valid instance of kind `T`.
145        unsafe { InstanceCommands::from_entity_unchecked(self.entity(entity)) }
146    }
147}
148
149/// Extension trait used to spawn instances via [`World`].
150pub trait SpawnInstanceWorld {
151    /// Spawns a new [`Entity`] which contains the given instance of `T` and returns an [`InstanceWorldMut<T>`] for it.
152    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceWorldMut<T>;
153}
154
155impl SpawnInstanceWorld for World {
156    fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceWorldMut<T> {
157        let mut entity = self.spawn_empty();
158        entity.insert(instance);
159        // SAFE: `entity` is spawned as a valid instance of kind `T`.
160        unsafe { InstanceWorldMut::from_entity_unchecked(entity) }
161    }
162}
163
164/// Extension trait used to insert instances via [`EntityCommands`].
165pub trait InsertInstance {
166    /// Inserts the given instance of `T` into the entity and returns an [`InstanceCommands<T>`] for it.
167    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
168}
169
170impl InsertInstance for EntityCommands<'_> {
171    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
172        self.insert(instance);
173        // SAFE: `entity` is spawned as a valid instance of kind `T`.
174        unsafe { InstanceCommands::from_entity_unchecked(self.reborrow()) }
175    }
176}
177
178/// Extension trait used to insert instances via [`EntityWorldMut`].
179pub trait InsertInstanceWorld {
180    /// Inserts the given instance of `T` into the entity and returns an [`InstanceRef<T>`] for it.
181    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceRef<T>;
182
183    /// Inserts the given instance of `T` into the entity and returns an [`InstanceMut<T>`] for it.
184    ///
185    /// This requires `T` to be [`Mutable`].
186    fn insert_instance_mut<T: Component<Mutability = Mutable>>(
187        &mut self,
188        instance: T,
189    ) -> InstanceMut<T>;
190}
191
192impl InsertInstanceWorld for EntityWorldMut<'_> {
193    fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceRef<T> {
194        self.insert(instance);
195        // SAFE: `entity` is spawned as a valid instance of kind `T`.
196        InstanceRef::from_entity(self.as_readonly()).unwrap()
197    }
198
199    fn insert_instance_mut<T: Component<Mutability = Mutable>>(
200        &mut self,
201        instance: T,
202    ) -> InstanceMut<T> {
203        self.insert(instance);
204        // SAFE: `entity` is spawned as a valid instance of kind `T`.
205        InstanceMut::from_entity(self).unwrap()
206    }
207}
208
209/// Extension trait used to get [`Component`] data from an [`Instance<T>`] via [`World`].
210pub trait ComponentInstance {
211    /// Returns a reference to the given instance.
212    fn instance<T: Component>(&self, instance: Instance<T>) -> Option<&T>;
213
214    /// Returns a mutable reference to the given instance.
215    ///
216    /// This requires `T` to be [`Mutable`].
217    fn instance_mut<T: Component<Mutability = Mutable>>(
218        &mut self,
219        instance: Instance<T>,
220    ) -> Option<Mut<T>>;
221}
222
223impl ComponentInstance for World {
224    fn instance<T: Component>(&self, instance: Instance<T>) -> Option<&T> {
225        self.get::<T>(instance.entity())
226    }
227
228    fn instance_mut<T: Component<Mutability = Mutable>>(
229        &mut self,
230        instance: Instance<T>,
231    ) -> Option<Mut<T>> {
232        self.get_mut::<T>(instance.entity())
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239    use bevy_ecs::system::RunSystemOnce;
240
241    fn count<T: Kind>(query: Query<Instance<T>>) -> usize {
242        query.iter().count()
243    }
244
245    #[test]
246    fn kind_with() {
247        #[derive(Component)]
248        struct Foo;
249
250        let mut world = World::new();
251        world.spawn(Foo);
252        assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
253    }
254
255    #[test]
256    fn kind_without() {
257        #[derive(Component)]
258        struct Foo;
259
260        struct NotFoo;
261
262        impl Kind for NotFoo {
263            type Filter = Without<Foo>;
264        }
265
266        let mut world = World::new();
267        world.spawn(Foo);
268        assert_eq!(world.run_system_once(count::<NotFoo>).unwrap(), 0);
269    }
270
271    #[test]
272    fn kind_multi() {
273        #[derive(Component)]
274        struct Foo;
275
276        #[derive(Component)]
277        struct Bar;
278
279        let mut world = World::new();
280        world.spawn((Foo, Bar));
281        assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
282        assert_eq!(world.run_system_once(count::<Bar>).unwrap(), 1);
283    }
284
285    #[test]
286    fn kind_cast() {
287        #[derive(Component)]
288        struct Foo;
289
290        #[derive(Component)]
291        struct Bar;
292
293        kind!(Foo is Bar);
294
295        let any = Instance::<Any>::PLACEHOLDER;
296        let foo = Instance::<Foo>::PLACEHOLDER;
297        let bar = foo.cast_into::<Bar>();
298        assert!(foo.cast_into_any() == any);
299        assert!(bar.cast_into_any() == any);
300        // assert!(any.cast_into::<Foo>() == foo); // <-- Must not compile!
301        // assert!(bar.cast_into::<Foo>() == foo); // <-- Must not compile!
302        assert!(bar.entity() == foo.entity());
303    }
304}