#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub mod prelude {
pub use crate::{CastInto, Kind};
pub use crate::{
ComponentInstance, InsertInstance, InsertInstanceWorld, SpawnInstance, SpawnInstanceWorld,
};
pub use crate::{ContainsInstance, Instance, InstanceMut, InstanceRef};
pub use crate::{GetInstanceCommands, InstanceCommands};
}
mod instance;
use bevy_ecs::world::DeferredWorld;
use bevy_reflect::Reflect;
pub use instance::*;
use bevy_ecs::component::Mutable;
use bevy_ecs::{prelude::*, query::QueryFilter};
pub trait Kind: 'static + Send + Sized + Sync {
type Filter: QueryFilter;
fn debug_name() -> String {
disqualified::ShortName::of::<Self>().to_string()
}
}
impl<T: Component> Kind for T {
type Filter = With<T>;
}
#[derive(Debug, Reflect)]
pub struct Any;
impl Kind for Any {
type Filter = ();
}
pub trait CastInto<T: Kind>: Kind {
#[doc(hidden)]
unsafe fn cast(instance: Instance<Self>) -> Instance<T> {
Instance::from_entity_unchecked(instance.entity())
}
}
impl<T: Kind> CastInto<T> for T {
unsafe fn cast(instance: Instance<Self>) -> Instance<T> {
Instance::from_entity_unchecked(instance.entity())
}
}
pub trait SpawnInstance {
fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
unsafe fn spawn_instance_unchecked<T: Kind>(
&mut self,
bundle: impl Bundle,
) -> InstanceCommands<'_, T>;
}
impl SpawnInstance for Commands<'_, '_> {
fn spawn_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
let entity = self.spawn(instance);
unsafe { InstanceCommands::from_entity_unchecked(entity) }
}
unsafe fn spawn_instance_unchecked<T: Kind>(
&mut self,
bundle: impl Bundle,
) -> InstanceCommands<'_, T> {
let entity = self.spawn(bundle);
unsafe { InstanceCommands::from_entity_unchecked(entity) }
}
}
pub trait SpawnInstanceWorld {
fn spawn_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T>;
fn spawn_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
instance: T,
) -> InstanceMut<'_, T>;
}
impl SpawnInstanceWorld for World {
fn spawn_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T> {
let mut entity = self.spawn_empty();
entity.insert(instance);
unsafe { InstanceRef::from_entity_unchecked(entity.into_readonly()) }
}
fn spawn_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
instance: T,
) -> InstanceMut<'_, T> {
let mut entity = self.spawn_empty();
entity.insert(instance);
unsafe { InstanceMut::from_entity_unchecked(entity.into_mutable()) }
}
}
pub trait InsertInstance {
fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T>;
}
impl InsertInstance for EntityCommands<'_> {
fn insert_instance<T: Component>(&mut self, instance: T) -> InstanceCommands<'_, T> {
self.insert(instance);
unsafe { InstanceCommands::from_entity_unchecked(self.reborrow()) }
}
}
pub trait InsertInstanceWorld {
fn insert_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T>;
fn insert_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
instance: T,
) -> InstanceMut<'_, T>;
}
impl InsertInstanceWorld for EntityWorldMut<'_> {
fn insert_instance<T: Component>(&'_ mut self, instance: T) -> InstanceRef<'_, T> {
self.insert(instance);
InstanceRef::from_entity(self.as_readonly()).unwrap()
}
fn insert_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
instance: T,
) -> InstanceMut<'_, T> {
self.insert(instance);
InstanceMut::from_entity(self.as_mutable()).unwrap()
}
}
pub trait ComponentInstance {
fn instance<T: Component>(&'_ self, instance: Instance<T>) -> InstanceRef<'_, T> {
self.get_instance(instance.entity()).unwrap()
}
fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>>;
fn instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
instance: Instance<T>,
) -> InstanceMut<'_, T> {
self.get_instance_mut(instance.entity()).unwrap()
}
fn get_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
entity: Entity,
) -> Option<InstanceMut<'_, T>>;
}
impl ComponentInstance for World {
fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>> {
InstanceRef::from_entity(self.get_entity(entity).ok()?)
}
fn get_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
entity: Entity,
) -> Option<InstanceMut<'_, T>> {
InstanceMut::from_entity(self.get_entity_mut(entity).ok()?.into_mutable())
}
}
impl ComponentInstance for DeferredWorld<'_> {
fn get_instance<T: Component>(&'_ self, entity: Entity) -> Option<InstanceRef<'_, T>> {
InstanceRef::from_entity(self.get_entity(entity).ok()?)
}
fn get_instance_mut<T: Component<Mutability = Mutable>>(
&'_ mut self,
entity: Entity,
) -> Option<InstanceMut<'_, T>> {
InstanceMut::from_entity(self.get_entity_mut(entity).ok()?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use bevy_ecs::system::RunSystemOnce;
fn count<T: Kind>(query: Query<Instance<T>>) -> usize {
query.iter().count()
}
#[test]
fn kind_with() {
#[derive(Component)]
struct Foo;
let mut world = World::new();
world.spawn(Foo);
assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
}
#[test]
fn kind_without() {
use bevy_ecs::resource::IsResource;
#[derive(Component)]
struct Foo;
struct NotFoo;
impl Kind for NotFoo {
type Filter = (Without<Foo>, Without<IsResource>);
}
let mut world = World::new();
world.spawn(Foo);
assert_eq!(world.run_system_once(count::<NotFoo>).unwrap(), 0);
}
#[test]
fn kind_multi() {
#[derive(Component)]
struct Foo;
#[derive(Component)]
struct Bar;
let mut world = World::new();
world.spawn((Foo, Bar));
assert_eq!(world.run_system_once(count::<Foo>).unwrap(), 1);
assert_eq!(world.run_system_once(count::<Bar>).unwrap(), 1);
}
#[test]
fn kind_cast() {
#[derive(Component)]
struct Foo;
#[derive(Component)]
struct Bar;
impl CastInto<Bar> for Foo {}
let any = Instance::<Any>::PLACEHOLDER;
let foo = Instance::<Foo>::PLACEHOLDER;
let bar = foo.cast_into::<Bar>();
assert!(foo.cast_into_any() == any);
assert!(bar.cast_into_any() == any);
assert!(bar.entity() == foo.entity());
}
}