1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub 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
21pub trait Kind: 'static + Send + Sized + Sync {
53 type Filter: QueryFilter;
55
56 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
69pub struct Any;
73
74impl Kind for Any {
75 type Filter = ();
76}
77
78pub unsafe trait CastInto<T: Kind>: Kind {
82 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#[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 unsafe { instance.cast_into_unchecked() }
130 }
131 }
132 };
133}
134
135pub trait SpawnInstance {
137 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 unsafe { InstanceCommands::from_entity_unchecked(self.entity(entity)) }
146 }
147}
148
149pub trait SpawnInstanceWorld {
151 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 unsafe { InstanceWorldMut::from_entity_unchecked(entity) }
161 }
162}
163
164pub trait InsertInstance {
166 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 unsafe { InstanceCommands::from_entity_unchecked(self.reborrow()) }
175 }
176}
177
178pub trait InsertInstanceWorld {
180 fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceRef<T>;
182
183 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 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 InstanceMut::from_entity(self).unwrap()
206 }
207}
208
209pub trait ComponentInstance {
211 fn instance<T: Component>(&self, instance: Instance<T>) -> Option<&T>;
213
214 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!(bar.entity() == foo.entity());
303 }
304}