hecs_schedule/
subworld.rs

1use atomic_refcell::AtomicRef;
2use std::{any::type_name, marker::PhantomData, ops::Deref};
3
4use crate::{access::*, borrow::ComponentBorrow, Error, Result};
5
6use crate::{GenericWorld, QueryOne};
7use hecs::{Component, Entity, Query, QueryBorrow, World};
8
9/// Type alias for a subworld referencing the world by an [atomic_refcell::AtomicRef]. Most
10/// common for schedules
11pub type SubWorld<'a, T> = SubWorldRaw<AtomicRef<'a, World>, T>;
12/// Type alias for a subworld referencing the world by a [std::cell::Ref]
13pub type SubWorldRefCell<'a, T> = SubWorldRaw<std::cell::Ref<'a, World>, T>;
14/// Type alias for a subworld referencing the world by a reference
15pub type SubWorldRef<'a, T> = SubWorldRaw<&'a World, T>;
16
17/// An empty subworld, can not access any components
18pub type EmptyWorld<'a> = SubWorldRef<'a, ()>;
19
20/// Represents a borrow of the world which can only access a subset of
21/// components (unless [`AllAccess`] is used).
22///
23/// This type allows for any reference kind, such as `&World`,
24/// [AtomicRef](atomic_refcell::AtomicRef),
25/// [Ref](std::cell::Ref), etc.
26///
27/// Type alises are provided for the most common usages, with [SubWorld] being
28/// the one used by [Schedule](crate::Schedule).
29pub struct SubWorldRaw<A, T> {
30    pub(crate) world: A,
31    marker: PhantomData<T>,
32}
33
34impl<A, T> SubWorldRaw<A, T> {
35    /// Splits the world into a subworld. No borrow checking is performed so may
36    /// fail during query unless guarded otherwise.
37    pub fn new(world: A) -> Self {
38        Self {
39            world,
40            marker: PhantomData,
41        }
42    }
43}
44
45impl<A, T: ComponentBorrow> SubWorldRaw<A, T> {
46    /// Returns true if the subworld can access the borrow of T
47    pub fn has<U: IntoAccess>(&self) -> bool {
48        T::has::<U>()
49    }
50
51    /// Returns true if the world satisfies the whole query
52    pub fn has_all<U: Subset>(&self) -> bool {
53        U::is_subset::<T>()
54    }
55}
56
57impl<'w, A: 'w + Deref<Target = World>, T: ComponentBorrow> SubWorldRaw<A, T> {
58    /// Query the subworld.
59    /// # Panics
60    /// Panics if the query items are not a compatible subset of the subworld.
61    pub fn query<Q: Query + Subset>(&self) -> QueryBorrow<'_, Q> {
62        self.try_query()
63            .expect("Failed to execute query on subworld")
64    }
65
66    /// Query the subworld for a single entity.
67    /// Wraps the hecs::NoSuchEntity error and provides the entity id
68    pub fn query_one<Q: Query + Subset>(&'w self, entity: Entity) -> Result<QueryOne<'w, Q>> {
69        if !self.has_all::<Q>() {
70            return Err(Error::IncompatibleSubworld {
71                subworld: type_name::<T>(),
72                query: type_name::<Q>(),
73            });
74        }
75
76        let query = self
77            .world
78            .query_one(entity)
79            .map_err(|_| Error::NoSuchEntity(entity))?;
80
81        Ok(QueryOne::new(entity, query))
82    }
83
84    /// Get a single component from the world.
85    ///
86    /// Wraps the hecs::NoSuchEntity error and provides the entity id
87    pub fn get<C: Component>(&self, entity: Entity) -> Result<hecs::Ref<C>> {
88        if !self.has::<&C>() {
89            return Err(Error::IncompatibleSubworld {
90                subworld: type_name::<T>(),
91                query: type_name::<&C>(),
92            });
93        }
94
95        match self.world.get::<&C>(entity) {
96            Ok(val) => Ok(val),
97            Err(hecs::ComponentError::NoSuchEntity) => Err(Error::NoSuchEntity(entity)),
98            Err(hecs::ComponentError::MissingComponent(name)) => {
99                Err(Error::MissingComponent(entity, name))
100            }
101        }
102    }
103
104    /// Get a single component from the world.
105    ///
106    /// Wraps the hecs::NoSuchEntity error and provides the entity id
107    pub fn get_mut<C: Component>(&self, entity: Entity) -> Result<hecs::RefMut<C>> {
108        if !self.has::<&C>() {
109            return Err(Error::IncompatibleSubworld {
110                subworld: type_name::<T>(),
111                query: type_name::<&C>(),
112            });
113        }
114
115        match self.world.get::<&mut C>(entity) {
116            Ok(val) => Ok(val),
117            Err(hecs::ComponentError::NoSuchEntity) => Err(Error::NoSuchEntity(entity)),
118            Err(hecs::ComponentError::MissingComponent(name)) => {
119                Err(Error::MissingComponent(entity, name))
120            }
121        }
122    }
123
124    /// Reserve multiple entities concurrently
125    pub fn reserve_entities(&self, count: u32) -> impl Iterator<Item = Entity> + '_ {
126        self.world.reserve_entities(count)
127    }
128
129    /// Query the subworld.
130    /// # Panics
131    /// Panics if the query items are not a compatible subset of the subworld.
132    pub fn query_par<Q: Query + Subset>(&self) -> QueryBorrow<'_, Q> {
133        self.try_query()
134            .expect("Failed to execute query on subworld")
135    }
136}