bevy_render/
extract_param.rs

1use crate::MainWorld;
2use bevy_ecs::{
3    component::Tick,
4    prelude::*,
5    system::{ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemState},
6    world::unsafe_world_cell::UnsafeWorldCell,
7};
8use std::ops::{Deref, DerefMut};
9
10/// A helper for accessing [`MainWorld`] content using a system parameter.
11///
12/// A [`SystemParam`] adapter which applies the contained `SystemParam` to the [`World`]
13/// contained in [`MainWorld`]. This parameter only works for systems run
14/// during the [`ExtractSchedule`](crate::ExtractSchedule).
15///
16/// This requires that the contained [`SystemParam`] does not mutate the world, as it
17/// uses a read-only reference to [`MainWorld`] internally.
18///
19/// ## Context
20///
21/// [`ExtractSchedule`] is used to extract (move) data from the simulation world ([`MainWorld`]) to the
22/// render world. The render world drives rendering each frame (generally to a `Window`).
23/// This design is used to allow performing calculations related to rendering a prior frame at the same
24/// time as the next frame is simulated, which increases throughput (FPS).
25///
26/// [`Extract`] is used to get data from the main world during [`ExtractSchedule`].
27///
28/// ## Examples
29///
30/// ```
31/// use bevy_ecs::prelude::*;
32/// use bevy_render::Extract;
33/// # #[derive(Component)]
34/// # struct Cloud;
35/// fn extract_clouds(mut commands: Commands, clouds: Extract<Query<Entity, With<Cloud>>>) {
36///     for cloud in &clouds {
37///         commands.get_or_spawn(cloud).insert(Cloud);
38///     }
39/// }
40/// ```
41///
42/// [`ExtractSchedule`]: crate::ExtractSchedule
43/// [Window]: bevy_window::Window
44pub struct Extract<'w, 's, P>
45where
46    P: ReadOnlySystemParam + 'static,
47{
48    item: SystemParamItem<'w, 's, P>,
49}
50
51#[doc(hidden)]
52pub struct ExtractState<P: SystemParam + 'static> {
53    state: SystemState<P>,
54    main_world_state: <Res<'static, MainWorld> as SystemParam>::State,
55}
56
57// SAFETY: The only `World` access (`Res<MainWorld>`) is read-only.
58unsafe impl<P> ReadOnlySystemParam for Extract<'_, '_, P> where P: ReadOnlySystemParam {}
59
60// SAFETY: The only `World` access is properly registered by `Res<MainWorld>::init_state`.
61// This call will also ensure that there are no conflicts with prior params.
62unsafe impl<P> SystemParam for Extract<'_, '_, P>
63where
64    P: ReadOnlySystemParam,
65{
66    type State = ExtractState<P>;
67    type Item<'w, 's> = Extract<'w, 's, P>;
68
69    fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
70        let mut main_world = world.resource_mut::<MainWorld>();
71        ExtractState {
72            state: SystemState::new(&mut main_world),
73            main_world_state: Res::<MainWorld>::init_state(world, system_meta),
74        }
75    }
76
77    unsafe fn get_param<'w, 's>(
78        state: &'s mut Self::State,
79        system_meta: &SystemMeta,
80        world: UnsafeWorldCell<'w>,
81        change_tick: Tick,
82    ) -> Self::Item<'w, 's> {
83        // SAFETY:
84        // - The caller ensures that `world` is the same one that `init_state` was called with.
85        // - The caller ensures that no other `SystemParam`s will conflict with the accesses we have registered.
86        let main_world = unsafe {
87            Res::<MainWorld>::get_param(
88                &mut state.main_world_state,
89                system_meta,
90                world,
91                change_tick,
92            )
93        };
94        let item = state.state.get(main_world.into_inner());
95        Extract { item }
96    }
97}
98
99impl<'w, 's, P> Deref for Extract<'w, 's, P>
100where
101    P: ReadOnlySystemParam,
102{
103    type Target = SystemParamItem<'w, 's, P>;
104
105    #[inline]
106    fn deref(&self) -> &Self::Target {
107        &self.item
108    }
109}
110
111impl<'w, 's, P> DerefMut for Extract<'w, 's, P>
112where
113    P: ReadOnlySystemParam,
114{
115    #[inline]
116    fn deref_mut(&mut self) -> &mut Self::Target {
117        &mut self.item
118    }
119}
120
121impl<'a, 'w, 's, P> IntoIterator for &'a Extract<'w, 's, P>
122where
123    P: ReadOnlySystemParam,
124    &'a SystemParamItem<'w, 's, P>: IntoIterator,
125{
126    type Item = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::Item;
127    type IntoIter = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::IntoIter;
128
129    fn into_iter(self) -> Self::IntoIter {
130        (&self.item).into_iter()
131    }
132}