#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub mod prelude {
pub use super::{GetObject, ObjectHierarchy, ObjectName, ObjectRebind, ObjectTags};
pub use super::{Object, ObjectRef, ObjectWorldRef, Objects, RootObjects};
}
mod hierarchy;
mod name;
mod rebind;
mod tags;
use std::fmt;
use std::ops::Deref;
use bevy_ecs::entity::EntityNotSpawnedError;
use bevy_ecs::prelude::*;
use bevy_ecs::query::{QueryEntityError, QueryFilter, QuerySingleError};
use bevy_ecs::system::SystemParam;
use moonshine_kind::prelude::*;
use moonshine_util::hierarchy::HierarchyQuery;
pub use moonshine_kind::{Any, CastInto, Kind};
pub use moonshine_tag::{Tag, TagFilter, Tags};
pub use hierarchy::*;
pub use name::*;
pub use rebind::*;
pub use tags::*;
#[derive(SystemParam)]
pub struct Objects<'w, 's, T = Any, F = ()>
where
T: Kind,
F: 'static + QueryFilter,
{
pub instance: Query<'w, 's, Instance<T>, F>,
pub hierarchy: HierarchyQuery<'w, 's>,
pub nametags: Query<'w, 's, AnyOf<(&'static Name, &'static Tags)>>,
}
impl<'w, 's, T, F> Objects<'w, 's, T, F>
where
T: Kind,
F: 'static + QueryFilter,
{
pub fn iter(&self) -> impl Iterator<Item = Object<'w, 's, '_, T>> {
self.instance.iter().map(|instance| Object {
instance,
hierarchy: &self.hierarchy,
nametags: &self.nametags,
})
}
pub fn contains(&self, entity: Entity) -> bool {
self.instance.contains(entity)
}
pub fn iter_ref<'a>(
&'a self,
world: &'a World,
) -> impl Iterator<Item = ObjectRef<'w, 's, 'a, T>> {
self.iter()
.map(|object: Object<T>| ObjectRef(world.entity(object.entity()), object))
}
pub fn get(&self, entity: Entity) -> Result<Object<'w, 's, '_, T>, QueryEntityError> {
self.instance.get(entity).map(|instance| Object {
instance,
hierarchy: &self.hierarchy,
nametags: &self.nametags,
})
}
pub fn get_ref<'a>(&'a self, entity: EntityRef<'a>) -> Option<ObjectRef<'w, 's, 'a, T>> {
Some(ObjectRef(entity, self.get(entity.id()).ok()?))
}
pub fn get_single(&self) -> Result<Object<'w, 's, '_, T>, QuerySingleError> {
self.instance.single().map(|instance| Object {
instance,
hierarchy: &self.hierarchy,
nametags: &self.nametags,
})
}
pub fn get_single_ref<'a>(&'a self, entity: EntityRef<'a>) -> Option<ObjectRef<'w, 's, 'a, T>> {
Some(ObjectRef(entity, self.get_single().ok()?))
}
pub fn instance(&self, instance: Instance<T>) -> Object<'w, 's, '_, T> {
self.get(instance.entity()).expect("instance must be valid")
}
pub fn get_instance(
&self,
instance: Instance<T>,
) -> Result<Object<'w, 's, '_, T>, QueryEntityError> {
self.get(instance.entity())
}
}
pub type RootObjects<'w, 's, T = Any, F = ()> = Objects<'w, 's, T, (F, Without<ChildOf>)>;
pub struct Object<'w, 's, 'a, T: Kind = Any> {
instance: Instance<T>,
hierarchy: &'a HierarchyQuery<'w, 's>,
nametags: &'a Query<'w, 's, AnyOf<(&'static Name, &'static Tags)>>,
}
impl<'w, 's, 'a, T: Kind> Object<'w, 's, 'a, T> {
pub unsafe fn from_any_unchecked(object: Object<'w, 's, 'a>) -> Self {
Self {
instance: object.instance.cast_into_unchecked(),
hierarchy: object.hierarchy,
nametags: object.nametags,
}
}
pub fn instance(&self) -> Instance<T> {
self.instance
}
pub fn entity(&self) -> Entity {
self.instance.entity()
}
}
impl<'w, 's, 'a, T: Component> Object<'w, 's, 'a, T> {
pub fn from_any(world: &World, object: Object<'w, 's, 'a>) -> Option<Object<'w, 's, 'a, T>> {
let entity = world.entity(object.entity());
let instance = Instance::<T>::from_entity(entity)?;
Some(unsafe { object.rebind_as(instance) })
}
}
impl<T: Kind> Clone for Object<'_, '_, '_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Kind> Copy for Object<'_, '_, '_, T> {}
impl<T: Kind> From<Object<'_, '_, '_, T>> for Entity {
fn from(object: Object<'_, '_, '_, T>) -> Self {
object.entity()
}
}
impl<T: Kind> From<Object<'_, '_, '_, T>> for Instance<T> {
fn from(object: Object<'_, '_, '_, T>) -> Self {
object.instance()
}
}
impl<T: Kind, U: Kind> PartialEq<Object<'_, '_, '_, U>> for Object<'_, '_, '_, T> {
fn eq(&self, other: &Object<U>) -> bool {
self.instance == other.instance
}
}
impl<T: Kind> Eq for Object<'_, '_, '_, T> {}
impl<T: Kind> PartialEq<Instance<T>> for Object<'_, '_, '_, T> {
fn eq(&self, other: &Instance<T>) -> bool {
self.instance() == *other
}
}
impl<T: Kind> PartialEq<Object<'_, '_, '_, T>> for Instance<T> {
fn eq(&self, other: &Object<T>) -> bool {
*self == other.instance()
}
}
impl<T: Kind> PartialEq<Entity> for Object<'_, '_, '_, T> {
fn eq(&self, other: &Entity) -> bool {
self.entity() == *other
}
}
impl<T: Kind> PartialEq<Object<'_, '_, '_, T>> for Entity {
fn eq(&self, other: &Object<T>) -> bool {
*self == other.entity()
}
}
impl<T: Kind> fmt::Debug for Object<'_, '_, '_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = self.name() {
write!(f, "{}({:?}, \"{}\")", &T::debug_name(), self.entity(), name)
} else {
write!(f, "{}({:?})", &T::debug_name(), self.entity())
}
}
}
impl<T: Kind> fmt::Display for Object<'_, '_, '_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = self.name() {
write!(f, "{}({}, \"{}\")", &T::debug_name(), self.entity(), name)
} else {
write!(f, "{}({})", &T::debug_name(), self.entity())
}
}
}
impl<T: Kind> ContainsInstance<T> for Object<'_, '_, '_, T> {
fn instance(&self) -> Instance<T> {
self.instance
}
}
pub struct ObjectRef<'w, 's, 'a, T: Kind = Any>(EntityRef<'a>, Object<'w, 's, 'a, T>);
impl<'w, 's, 'a, T: Kind> ObjectRef<'w, 's, 'a, T> {
pub unsafe fn from_any_unchecked(base: ObjectRef<'w, 's, 'a>) -> Self {
Self(base.0, Object::from_any_unchecked(base.1))
}
pub fn get<U: Component>(&self) -> Option<&U> {
self.0.get::<U>()
}
pub fn contains<U: Component>(&self) -> bool {
self.0.contains::<U>()
}
pub fn as_entity(&self) -> EntityRef<'a> {
self.0
}
}
impl<T: Kind> Clone for ObjectRef<'_, '_, '_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Kind> Copy for ObjectRef<'_, '_, '_, T> {}
impl<T: Kind> From<ObjectRef<'_, '_, '_, T>> for Entity {
fn from(object: ObjectRef<'_, '_, '_, T>) -> Self {
object.entity()
}
}
impl<T: Kind> From<ObjectRef<'_, '_, '_, T>> for Instance<T> {
fn from(object: ObjectRef<'_, '_, '_, T>) -> Self {
object.instance()
}
}
impl<'w, 's, 'a, T: Kind> From<ObjectRef<'w, 's, 'a, T>> for Object<'w, 's, 'a, T> {
fn from(object: ObjectRef<'w, 's, 'a, T>) -> Self {
object.1
}
}
impl<'w, 's, 'a, T: Kind> From<&ObjectRef<'w, 's, 'a, T>> for Object<'w, 's, 'a, T> {
fn from(object: &ObjectRef<'w, 's, 'a, T>) -> Self {
object.1
}
}
impl<T: Kind> PartialEq for ObjectRef<'_, '_, '_, T> {
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl<T: Kind> Eq for ObjectRef<'_, '_, '_, T> {}
impl<T: Kind> ContainsInstance<T> for ObjectRef<'_, '_, '_, T> {
fn instance(&self) -> Instance<T> {
self.1.instance()
}
}
impl<T: Component> Deref for ObjectRef<'_, '_, '_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0.get::<T>().unwrap()
}
}
impl<T: Kind> fmt::Debug for ObjectRef<'_, '_, '_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = self.name() {
write!(f, "{}({:?}, \"{}\")", &T::debug_name(), self.entity(), name)
} else {
write!(f, "{}({:?})", &T::debug_name(), self.entity())
}
}
}
impl<T: Kind> fmt::Display for ObjectRef<'_, '_, '_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = self.name() {
write!(f, "{}({}, \"{}\")", &T::debug_name(), self.entity(), name)
} else {
write!(f, "{}({})", &T::debug_name(), self.entity())
}
}
}
pub struct ObjectWorldRef<'w, T: Kind = Any> {
instance: Instance<T>,
world: &'w World,
}
impl<'w, T: Kind> ObjectWorldRef<'w, T> {
pub unsafe fn from_any_unchecked(object: ObjectWorldRef<'w>) -> Self {
Self {
instance: object.instance.cast_into_unchecked(),
world: object.world,
}
}
pub fn from_any(object: ObjectWorldRef<'w>) -> Option<Self>
where
T: Component,
{
Some(Self {
instance: Instance::from_entity(object.as_entity())?,
world: object.world,
})
}
pub fn get<U: Component>(&self) -> Option<&U> {
self.world.get::<U>(self.entity())
}
pub fn contains<U: Component>(&self) -> bool {
self.world.entity(self.entity()).contains::<U>()
}
pub fn instance(&self) -> Instance<T> {
self.instance
}
pub fn entity(&self) -> Entity {
self.instance.entity()
}
pub fn as_entity(&self) -> EntityRef<'w> {
self.world.entity(self.entity())
}
}
impl<T: Kind> ContainsInstance<T> for ObjectWorldRef<'_, T> {
fn instance(&self) -> Instance<T> {
self.instance
}
}
impl<T: Kind> Clone for ObjectWorldRef<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Kind> Copy for ObjectWorldRef<'_, T> {}
impl<T: Kind> From<ObjectWorldRef<'_, T>> for Entity {
fn from(object: ObjectWorldRef<'_, T>) -> Self {
object.entity()
}
}
impl<T: Kind> From<ObjectWorldRef<'_, T>> for Instance<T> {
fn from(object: ObjectWorldRef<'_, T>) -> Self {
object.instance()
}
}
impl<T: Kind, U: Kind> PartialEq<ObjectWorldRef<'_, U>> for ObjectWorldRef<'_, T> {
fn eq(&self, other: &ObjectWorldRef<U>) -> bool {
self.instance == other.instance
}
}
impl<T: Kind> Eq for ObjectWorldRef<'_, T> {}
impl<T: Kind> PartialEq<Instance<T>> for ObjectWorldRef<'_, T> {
fn eq(&self, other: &Instance<T>) -> bool {
self.instance() == *other
}
}
impl<T: Kind> PartialEq<ObjectWorldRef<'_, T>> for Instance<T> {
fn eq(&self, other: &ObjectWorldRef<T>) -> bool {
*self == other.instance()
}
}
impl<T: Kind> PartialEq<Entity> for ObjectWorldRef<'_, T> {
fn eq(&self, other: &Entity) -> bool {
self.entity() == *other
}
}
impl<T: Kind> PartialEq<ObjectWorldRef<'_, T>> for Entity {
fn eq(&self, other: &ObjectWorldRef<T>) -> bool {
*self == other.entity()
}
}
impl<T: Kind> fmt::Debug for ObjectWorldRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = self.name() {
write!(f, "{}({:?}, \"{}\")", &T::debug_name(), self.entity(), name)
} else {
write!(f, "{}({:?})", &T::debug_name(), self.entity())
}
}
}
impl<T: Kind> fmt::Display for ObjectWorldRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = self.name() {
write!(f, "{}({}, \"{}\")", &T::debug_name(), self.entity(), name)
} else {
write!(f, "{}({})", &T::debug_name(), self.entity())
}
}
}
impl<T: Component> Deref for ObjectWorldRef<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.world.get::<T>(self.entity()).unwrap()
}
}
pub trait GetObject {
fn object(&'_ self, entity: Entity) -> ObjectWorldRef<'_>;
fn get_object(&'_ self, entity: Entity) -> Result<ObjectWorldRef<'_>, EntityNotSpawnedError>;
}
impl GetObject for World {
fn object(&'_ self, entity: Entity) -> ObjectWorldRef<'_> {
ObjectWorldRef {
instance: self.entity(entity).id().into(),
world: self,
}
}
fn get_object(&'_ self, entity: Entity) -> Result<ObjectWorldRef<'_>, EntityNotSpawnedError> {
Ok(ObjectWorldRef {
instance: self.get_entity(entity)?.id().into(),
world: self,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use bevy::ecs::system::RunSystemOnce;
#[test]
fn find_by_path() {
let mut w = World::new();
let (a, b, c, d) = w
.run_system_once(|mut commands: Commands| {
let a = commands.spawn(Name::new("A")).id();
let b = commands.spawn(Name::new("B")).id();
let c = commands.spawn(Name::new("C")).id();
let d = commands.spawn(Name::new("D")).id();
commands.entity(a).add_children(&[b]);
commands.entity(b).add_children(&[c, d]);
(a, b, c, d)
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("").unwrap();
assert_eq!(a, x);
assert_eq!(x.path(), "A");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path(".").unwrap();
assert_eq!(a, x);
assert_eq!(x.path(), "A");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("B").unwrap();
assert_eq!(b, x);
assert_eq!(x.path(), "A/B");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("B/C").unwrap();
assert_eq!(c, x);
assert_eq!(x.path(), "A/B/C");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("B/D").unwrap();
assert_eq!(d, x);
assert_eq!(x.path(), "A/B/D");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("B/*").unwrap();
assert_eq!(c, x);
assert_eq!(x.path(), "A/B/C");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("*/D").unwrap();
assert_eq!(d, x);
assert_eq!(x.path(), "A/B/D");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(a).unwrap().find_by_path("*/*").unwrap();
assert_eq!(c, x);
assert_eq!(x.path(), "A/B/C");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(b).unwrap().find_by_path("..").unwrap();
assert_eq!(a, x);
assert_eq!(x.path(), "A");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(c).unwrap().find_by_path("..").unwrap();
assert_eq!(b, x);
assert_eq!(x.path(), "A/B");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(c).unwrap().find_by_path("../D").unwrap();
assert_eq!(d, x);
assert_eq!(x.path(), "A/B/D");
})
.unwrap();
w.run_system_once(move |objects: Objects| {
let x = objects.get(c).unwrap().find_by_path("../C").unwrap();
assert_eq!(c, x);
assert_eq!(x.path(), "A/B/C");
})
.unwrap();
}
#[test]
fn object_ref() {
#[derive(Component)]
struct T;
let mut w = World::new();
let entity = w.spawn(T).id();
assert!(w
.run_system_once(move |world: &World, objects: Objects<T>| {
objects
.get_single_ref(world.entity(entity))
.unwrap()
.contains::<T>()
})
.unwrap());
}
#[test]
fn world_object_ref() {
#[derive(Component)]
struct T;
let mut w = World::new();
let entity = w.spawn(T).id();
let object = ObjectWorldRef::<T>::from_any(w.object(entity)).unwrap();
assert_eq!(object, entity);
}
#[test]
fn root_objects() {
#[derive(Component)]
struct T;
let mut w = World::new();
let root = w
.spawn(T)
.with_children(|children| {
children.spawn(T ).with_children(|children| {
children.spawn(T );
children.spawn(T );
});
})
.id();
assert!(w
.run_system_once(move |objects: RootObjects<T>| {
assert_eq!(objects.iter().count(), 1);
assert!(objects.contains(root));
assert!(objects.get_single().is_ok());
true
})
.unwrap());
}
}