wde_renderer/core/
extract_macros.rs

1//! Macros for extracting data from the main world to the render world.
2//! Provides the [`ExtractWorld`] system parameter, which allows accessing data from the main world in the render world.
3
4use bevy::{
5    ecs::{
6        change_detection::Tick,
7        system::{ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemState},
8        world::unsafe_world_cell::UnsafeWorldCell
9    },
10    prelude::*
11};
12use std::ops::{Deref, DerefMut};
13
14use super::MainWorld;
15
16/// A helper for accessing MainWorld content using a system parameter.
17/// [`ExtractWorld`] is used to get data from the main world during [`crate::core::Extract`].
18/// Note that the system parameter `P` must implement `ReadOnlySystemParam`, as the main world is only accessible for reading in this context.
19///
20/// ## Example
21/// ```
22/// fn extract(mut commands: Commands, clouds: ExtractWorld<Query<Entity, With<Cloud>>>) {
23///     /* (...) */
24/// }
25/// ```
26pub struct ExtractWorld<'w, 's, P>
27where
28    P: ReadOnlySystemParam + 'static
29{
30    item: SystemParamItem<'w, 's, P>
31}
32pub struct ExtractState<P: SystemParam + 'static> {
33    state: SystemState<P>,
34    main_world_state: <Res<'static, MainWorld> as SystemParam>::State
35}
36// SAFETY: The only `World` access (`Res<MainWorld>`) is read-only.
37unsafe impl<P> ReadOnlySystemParam for ExtractWorld<'_, '_, P> where P: ReadOnlySystemParam {}
38// SAFETY: The only `World` access is properly registered by `Res<MainWorld>::init_state`.
39// This call will also ensure that there are no conflicts with prior params.
40unsafe impl<P> SystemParam for ExtractWorld<'_, '_, P>
41where
42    P: ReadOnlySystemParam
43{
44    type State = ExtractState<P>;
45    type Item<'w, 's> = ExtractWorld<'w, 's, P>;
46
47    fn init_access(
48        state: &Self::State,
49        system_meta: &mut SystemMeta,
50        component_access_set: &mut bevy::ecs::query::FilteredAccessSet,
51        world: &mut World
52    ) {
53        // Register access for `Res<MainWorld>`.
54        Res::<MainWorld>::init_access(
55            &state.main_world_state,
56            system_meta,
57            component_access_set,
58            world
59        );
60    }
61
62    fn init_state(world: &mut World) -> Self::State {
63        let mut main_world = world.resource_mut::<MainWorld>();
64        ExtractState {
65            state: SystemState::new(&mut main_world),
66            main_world_state: Res::<MainWorld>::init_state(world)
67        }
68    }
69
70    unsafe fn get_param<'w, 's>(
71        state: &'s mut Self::State,
72        system_meta: &SystemMeta,
73        world: UnsafeWorldCell<'w>,
74        change_tick: Tick
75    ) -> Self::Item<'w, 's> {
76        // SAFETY:
77        // - The caller ensures that `world` is the same one that `init_state` was called with.
78        // - The caller ensures that no other `SystemParam`s will conflict with the accesses we have registered.
79        let main_world = unsafe {
80            Res::<MainWorld>::get_param(
81                &mut state.main_world_state,
82                system_meta,
83                world,
84                change_tick
85            )
86        };
87        let item = state.state.get(main_world.into_inner());
88        ExtractWorld { item }
89    }
90}
91impl<'w, 's, P> Deref for ExtractWorld<'w, 's, P>
92where
93    P: ReadOnlySystemParam
94{
95    type Target = SystemParamItem<'w, 's, P>;
96    #[inline]
97    fn deref(&self) -> &Self::Target {
98        &self.item
99    }
100}
101impl<P> DerefMut for ExtractWorld<'_, '_, P>
102where
103    P: ReadOnlySystemParam
104{
105    #[inline]
106    fn deref_mut(&mut self) -> &mut Self::Target {
107        &mut self.item
108    }
109}
110impl<'a, 'w, 's, P> IntoIterator for &'a ExtractWorld<'w, 's, P>
111where
112    P: ReadOnlySystemParam,
113    &'a SystemParamItem<'w, 's, P>: IntoIterator
114{
115    type Item = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::Item;
116    type IntoIter = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::IntoIter;
117    fn into_iter(self) -> Self::IntoIter {
118        (&self.item).into_iter()
119    }
120}