legion/internals/
subworld.rs

1//! Contains types related to the [`SubWorld`] which can split a world by component type access.
2
3use std::borrow::Cow;
4
5use bit_set::BitSet;
6
7use super::{
8    entity::Entity,
9    entry::{EntryMut, EntryRef},
10    permissions::Permissions,
11    query::{
12        filter::EntityFilter,
13        view::{IntoView, View},
14        Query,
15    },
16    storage::{archetype::ArchetypeIndex, component::ComponentTypeId},
17    world::{EntityAccessError, EntityStore, StorageAccessor, World, WorldId},
18};
19
20/// Describes which archetypes are available for access.
21pub enum ArchetypeAccess {
22    /// All archetypes.
23    All,
24    /// Some archetypes.
25    Some(BitSet),
26}
27
28impl ArchetypeAccess {
29    /// Determines if the given archetypes are disjoint from those allowed by this archetype access,
30    pub fn is_disjoint(&self, other: &ArchetypeAccess) -> bool {
31        match self {
32            Self::All => false,
33            Self::Some(mine) => {
34                match other {
35                    Self::All => false,
36                    Self::Some(theirs) => mine.is_disjoint(theirs),
37                }
38            }
39        }
40    }
41
42    /// Returns a bitset of allowed archetype indexes if this access is `Some`.
43    pub fn bitset(&self) -> Option<&BitSet> {
44        match self {
45            Self::All => None,
46            Self::Some(bitset) => Some(bitset),
47        }
48    }
49}
50
51/// Describes which components are available for access.
52#[derive(Clone, Debug)]
53pub enum ComponentAccess<'a> {
54    /// All component types are allowed.
55    All,
56    /// Some component types are allowed.
57    Allow(Cow<'a, Permissions<ComponentTypeId>>),
58    /// Some component types are disallowed.
59    Disallow(Cow<'a, Permissions<ComponentTypeId>>),
60}
61
62impl<'a> ComponentAccess<'a> {
63    /// Returns `true` if the given component is accessible for reads.
64    pub fn allows_read(&self, component: ComponentTypeId) -> bool {
65        match self {
66            Self::All => true,
67            Self::Allow(components) => components.reads().contains(&component),
68            Self::Disallow(components) => !components.reads().contains(&component),
69        }
70    }
71
72    /// Returns `true` if the given component is accessible for writes.
73    pub fn allows_write(&self, component: ComponentTypeId) -> bool {
74        match self {
75            Self::All => true,
76            Self::Allow(components) => components.writes().contains(&component),
77            Self::Disallow(components) => !components.writes().contains(&component),
78        }
79    }
80
81    /// Splits this permission set into two; the left access only allows the permissions given, while the right
82    /// allows only what is left from this set after subtracting said permissions.
83    pub(crate) fn split(&mut self, access: Permissions<ComponentTypeId>) -> (Self, Self) {
84        fn append_incompatible(
85            denied: &mut Permissions<ComponentTypeId>,
86            to_deny: &Permissions<ComponentTypeId>,
87        ) {
88            // reads are now denied writes
89            for read in to_deny.reads() {
90                denied.push_write(*read);
91            }
92
93            // writes are now entirely denied
94            for write in to_deny.writes() {
95                denied.push(*write);
96            }
97        }
98
99        fn incompatible(
100            permissions: &Permissions<ComponentTypeId>,
101        ) -> Permissions<ComponentTypeId> {
102            let mut denied = Permissions::new();
103            // if the current permission allows reads, then everything else must deny writes
104            for read in permissions.reads_only() {
105                denied.push_write(*read);
106            }
107
108            // if the current permission allows writes, then everything else must deny all
109            for write in permissions.writes() {
110                denied.push(*write);
111            }
112
113            denied
114        }
115
116        match self {
117            Self::All => {
118                let denied = incompatible(&access);
119                (
120                    Self::Allow(Cow::Owned(access)),
121                    Self::Disallow(Cow::Owned(denied)),
122                )
123            }
124            Self::Allow(allowed) => {
125                if !allowed.is_superset(&access) {
126                    panic!("view accesses components unavailable in this world: world allows only {}, view requires {}", allowed, access);
127                }
128
129                let mut allowed = allowed.clone();
130                allowed.to_mut().subtract(&access);
131
132                (Self::Allow(Cow::Owned(access)), Self::Allow(allowed))
133            }
134            Self::Disallow(denied) => {
135                if !denied.is_disjoint(&access) {
136                    panic!("view accesses components unavailable in this world: world disallows {}, view requires {}", denied, access);
137                }
138
139                let mut denied = denied.clone();
140                append_incompatible(denied.to_mut(), &access);
141
142                (Self::Allow(Cow::Owned(access)), Self::Disallow(denied))
143            }
144        }
145    }
146}
147
148/// Provides access to a subset of the entities of a `World`.
149///
150/// To access a component mutably in a world, such as inside a [query](crate::query) or via an
151/// [`EntryMut`], you need to borrow the entire world mutably. This prevents you from accessing
152/// any other data in the world at the same time.
153///
154/// In some cases, we can work around this by splitting the world. We can split a world around the
155/// component types requested by a [`View`]. This will create two subworlds, the left one allowing
156/// access only to the components (and mutability) declared by the view, while the right subworld
157/// will allow access to everything _but_ those components.
158///
159/// Subworlds can be recustively further split.
160#[derive(Clone)]
161pub struct SubWorld<'a> {
162    world: &'a World,
163    components: ComponentAccess<'a>,
164    archetypes: Option<&'a BitSet>,
165}
166
167impl<'a> SubWorld<'a> {
168    /// Constructs a new SubWorld.
169    ///
170    /// # Safety
171    /// Queries assume that this type has been constructed correctly. Ensure that sub-worlds represent
172    /// disjoint portions of a world and that the world is not used while any of its sub-worlds are alive.
173    pub unsafe fn new_unchecked(
174        world: &'a World,
175        components: ComponentAccess<'a>,
176        archetypes: Option<&'a BitSet>,
177    ) -> Self {
178        Self {
179            world,
180            components,
181            archetypes,
182        }
183    }
184
185    /// Splits the world into two. The left world allows access only to the data declared by the view;
186    /// the right world allows access to all else.
187    ///
188    /// # Examples
189    ///
190    /// ```
191    /// # use legion::*;
192    /// # struct Position;
193    /// # let mut world = World::default();
194    /// let (left, right) = world.split::<&mut Position>();
195    /// ```
196    ///
197    /// With the above, 'left' contains a sub-world with access _only_ to `&Position` and `&mut Position`,
198    /// and `right` contains a sub-world with access to everything _but_ `&Position` and `&mut Position`.
199    ///
200    /// ```
201    /// # use legion::*;
202    /// # struct Position;
203    /// # let mut world = World::default();
204    /// let (left, right) = world.split::<&Position>();
205    /// ```
206    ///
207    /// In this second example, `left` is provided access _only_ to `&Position`. `right` is granted permission
208    /// to everything _but_ `&mut Position`.
209    pub fn split<'b, T: IntoView>(&'b mut self) -> (SubWorld<'b>, SubWorld<'b>)
210    where
211        'a: 'b,
212    {
213        let permissions = T::View::requires_permissions();
214        let (left, right) = self.components.split(permissions);
215
216        (
217            SubWorld {
218                world: self.world,
219                components: left,
220                archetypes: self.archetypes,
221            },
222            SubWorld {
223                world: self.world,
224                components: right,
225                archetypes: self.archetypes,
226            },
227        )
228    }
229
230    /// Splits the world into two. The left world allows access only to the data declared by the query's view;
231    /// the right world allows access to all else.
232    pub fn split_for_query<'q, V: IntoView, F: EntityFilter>(
233        &mut self,
234        _: &'q Query<V, F>,
235    ) -> (SubWorld, SubWorld) {
236        self.split::<V>()
237    }
238
239    fn validate_archetype_access(&self, ArchetypeIndex(arch_index): ArchetypeIndex) -> bool {
240        if let Some(archetypes) = self.archetypes {
241            archetypes.contains(arch_index as usize)
242        } else {
243            true
244        }
245    }
246}
247
248impl<'a> EntityStore for SubWorld<'a> {
249    fn get_component_storage<V: for<'b> View<'b>>(
250        &self,
251    ) -> Result<StorageAccessor, EntityAccessError> {
252        if V::validate_access(&self.components) {
253            Ok(self
254                .world
255                .get_component_storage::<V>()
256                .unwrap()
257                .with_allowed_archetypes(self.archetypes))
258        } else {
259            Err(EntityAccessError::AccessDenied)
260        }
261    }
262
263    fn entry_ref(&self, entity: Entity) -> Result<EntryRef, EntityAccessError> {
264        let entry = self.world.entry_ref(entity)?;
265
266        if !self.validate_archetype_access(entry.location().archetype()) {
267            return Err(EntityAccessError::AccessDenied);
268        }
269
270        Ok(EntryRef {
271            allowed_components: self.components.clone(),
272            ..entry
273        })
274    }
275
276    fn entry_mut(&mut self, entity: Entity) -> Result<EntryMut, EntityAccessError> {
277        // safety: protected by &mut self and subworld access validation
278        let entry = unsafe { self.world.entry_unchecked(entity)? };
279
280        if !self.validate_archetype_access(entry.location().archetype()) {
281            return Err(EntityAccessError::AccessDenied);
282        }
283
284        Ok(EntryMut {
285            allowed_components: self.components.clone(),
286            ..entry
287        })
288    }
289
290    fn id(&self) -> WorldId {
291        self.world.id()
292    }
293}
294
295impl<'a> From<&'a mut World> for SubWorld<'a> {
296    fn from(world: &'a mut World) -> Self {
297        Self {
298            world,
299            components: ComponentAccess::All,
300            archetypes: None,
301        }
302    }
303}
304
305#[cfg(test)]
306mod tests {
307    use crate::{
308        internals::{
309            query::view::{read::Read, write::Write},
310            world::{EntityStore, World},
311        },
312        world::ComponentError,
313    };
314
315    #[test]
316    fn split_write_permissions() {
317        let mut world = World::default();
318        let entity = world.push((1usize, false));
319
320        let (mut left, mut right) = world.split::<Write<usize>>();
321
322        let mut left_entry = left.entry_mut(entity).unwrap();
323        let mut right_entry = right.entry_mut(entity).unwrap();
324
325        assert!(left_entry.get_component::<usize>().is_ok());
326        assert!(left_entry.get_component_mut::<usize>().is_ok());
327
328        assert!(matches!(
329            left_entry.get_component::<bool>(),
330            Err(ComponentError::Denied { .. })
331        ));
332        assert!(matches!(
333            left_entry.get_component_mut::<bool>(),
334            Err(ComponentError::Denied { .. })
335        ));
336
337        assert!(right_entry.get_component::<bool>().is_ok());
338        assert!(right_entry.get_component_mut::<bool>().is_ok());
339
340        assert!(matches!(
341            right_entry.get_component::<usize>(),
342            Err(ComponentError::Denied { .. })
343        ));
344        assert!(matches!(
345            right_entry.get_component_mut::<usize>(),
346            Err(ComponentError::Denied { .. })
347        ));
348    }
349
350    #[test]
351    fn split_read_permissions() {
352        let mut world = World::default();
353        let entity = world.push((1usize, false));
354
355        let (mut left, mut right) = world.split::<Read<usize>>();
356
357        let mut left_entry = left.entry_mut(entity).unwrap();
358        let mut right_entry = right.entry_mut(entity).unwrap();
359
360        assert!(left_entry.get_component::<usize>().is_ok());
361        assert!(matches!(
362            left_entry.get_component_mut::<usize>(),
363            Err(ComponentError::Denied { .. })
364        ));
365
366        assert!(matches!(
367            left_entry.get_component::<bool>(),
368            Err(ComponentError::Denied { .. })
369        ));
370        assert!(matches!(
371            left_entry.get_component_mut::<bool>(),
372            Err(ComponentError::Denied { .. })
373        ));
374
375        assert!(right_entry.get_component::<bool>().is_ok());
376        assert!(right_entry.get_component_mut::<bool>().is_ok());
377
378        assert!(right_entry.get_component::<usize>().is_ok());
379        assert!(matches!(
380            right_entry.get_component_mut::<usize>(),
381            Err(ComponentError::Denied { .. })
382        ));
383    }
384
385    #[test]
386    fn complex_split() {
387        struct A;
388        struct B;
389        struct C;
390
391        let mut world = World::default();
392        let entity = world.push((A, B, C));
393
394        let (mut left, mut right) = world.split::<(Read<A>, Write<B>)>();
395
396        let mut left_entry = left.entry_mut(entity).unwrap();
397        let mut right_entry = right.entry_mut(entity).unwrap();
398
399        // left should read but not write A
400        assert!(left_entry.get_component::<A>().is_ok());
401        assert!(matches!(
402            left_entry.get_component_mut::<A>(),
403            Err(ComponentError::Denied { .. })
404        ));
405
406        // left should read and write B
407        assert!(left_entry.get_component::<B>().is_ok());
408        assert!(left_entry.get_component_mut::<B>().is_ok());
409
410        // left should not be able to read or write C
411        assert!(matches!(
412            left_entry.get_component::<C>(),
413            Err(ComponentError::Denied { .. })
414        ));
415        assert!(matches!(
416            left_entry.get_component_mut::<C>(),
417            Err(ComponentError::Denied { .. })
418        ));
419
420        // right should be able to read but not write A
421        assert!(right_entry.get_component::<A>().is_ok());
422        assert!(matches!(
423            right_entry.get_component_mut::<A>(),
424            Err(ComponentError::Denied { .. })
425        ));
426
427        // right should not be able to read or write B
428        assert!(matches!(
429            right_entry.get_component::<B>(),
430            Err(ComponentError::Denied { .. })
431        ));
432        assert!(matches!(
433            right_entry.get_component_mut::<B>(),
434            Err(ComponentError::Denied { .. })
435        ));
436
437        // right should read and write C
438        assert!(right_entry.get_component::<C>().is_ok());
439        assert!(right_entry.get_component_mut::<C>().is_ok());
440    }
441}