Skip to content

Commit a52962f

Browse files
authored
Try #3817:
2 parents 3431335 + 37756b1 commit a52962f

File tree

5 files changed

+172
-142
lines changed

5 files changed

+172
-142
lines changed

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
383383
#[doc(hidden)]
384384
#fetch_struct_visibility struct #fetch_struct_name<TSystemParamState, #punctuated_generic_idents> {
385385
state: TSystemParamState,
386-
marker: std::marker::PhantomData<(#punctuated_generic_idents)>
386+
marker: std::marker::PhantomData<fn()->(#punctuated_generic_idents)>
387387
}
388388

389389
unsafe impl<TSystemParamState: #path::system::SystemParamState, #punctuated_generics> #path::system::SystemParamState for #fetch_struct_name<TSystemParamState, #punctuated_generic_idents> {

crates/bevy_ecs/src/system/function_system.rs

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
query::{Access, FilteredAccessSet},
55
system::{
66
check_system_change_tick, ReadOnlySystemParamFetch, System, SystemParam, SystemParamFetch,
7-
SystemParamItem, SystemParamState,
7+
SystemParamState,
88
},
99
world::{World, WorldId},
1010
};
@@ -46,11 +46,6 @@ impl SystemMeta {
4646
pub fn set_non_send(&mut self) {
4747
self.is_send = false;
4848
}
49-
50-
#[inline]
51-
pub(crate) fn check_change_tick(&mut self, change_tick: u32) {
52-
check_system_change_tick(&mut self.last_change_tick, change_tick, self.name.as_ref());
53-
}
5449
}
5550

5651
// TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference
@@ -126,10 +121,6 @@ impl<Param: SystemParam> SystemState<Param> {
126121
self.world_id == world.id()
127122
}
128123

129-
pub(crate) fn new_archetype(&mut self, archetype: &Archetype) {
130-
self.param_state.new_archetype(archetype, &mut self.meta);
131-
}
132-
133124
fn validate_world_and_update_archetypes(&mut self, world: &World) {
134125
assert!(self.matches_world(world), "Encountered a mismatched World. A SystemState cannot be used with Worlds other than the one it was created with.");
135126
let archetypes = world.archetypes();
@@ -168,74 +159,6 @@ impl<Param: SystemParam> SystemState<Param> {
168159
}
169160
}
170161

171-
/// A trait for defining systems with a [`SystemParam`] associated type.
172-
///
173-
/// This facilitates the creation of systems that are generic over some trait
174-
/// and that use that trait's associated types as `SystemParam`s.
175-
pub trait RunSystem: Send + Sync + 'static {
176-
/// The `SystemParam` type passed to the system when it runs.
177-
type Param: SystemParam;
178-
179-
/// Runs the system.
180-
fn run(param: SystemParamItem<Self::Param>);
181-
182-
/// Creates a concrete instance of the system for the specified `World`.
183-
fn system(world: &mut World) -> ParamSystem<Self::Param> {
184-
ParamSystem {
185-
run: Self::run,
186-
state: SystemState::new(world),
187-
}
188-
}
189-
}
190-
191-
pub struct ParamSystem<P: SystemParam> {
192-
state: SystemState<P>,
193-
run: fn(SystemParamItem<P>),
194-
}
195-
196-
impl<P: SystemParam + 'static> System for ParamSystem<P> {
197-
type In = ();
198-
199-
type Out = ();
200-
201-
fn name(&self) -> Cow<'static, str> {
202-
self.state.meta().name.clone()
203-
}
204-
205-
fn new_archetype(&mut self, archetype: &Archetype) {
206-
self.state.new_archetype(archetype);
207-
}
208-
209-
fn component_access(&self) -> &Access<ComponentId> {
210-
self.state.meta().component_access_set.combined_access()
211-
}
212-
213-
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
214-
&self.state.meta().archetype_component_access
215-
}
216-
217-
fn is_send(&self) -> bool {
218-
self.state.meta().is_send()
219-
}
220-
221-
unsafe fn run_unsafe(&mut self, _input: Self::In, world: &World) -> Self::Out {
222-
let param = self.state.get_unchecked_manual(world);
223-
(self.run)(param);
224-
}
225-
226-
fn apply_buffers(&mut self, world: &mut World) {
227-
self.state.apply(world);
228-
}
229-
230-
fn initialize(&mut self, _world: &mut World) {
231-
// already initialized by nature of the SystemState being constructed
232-
}
233-
234-
fn check_change_tick(&mut self, change_tick: u32) {
235-
self.state.meta.check_change_tick(change_tick);
236-
}
237-
}
238-
239162
/// Conversion trait to turn something into a [`System`].
240163
///
241164
/// Use this to get a system from a function. Also note that every system implements this trait as

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,136 @@ pub mod lifetimeless {
13301330
pub type SCommands = crate::system::Commands<'static, 'static>;
13311331
}
13321332

1333+
/// A helper for using system parameters in generic contexts
1334+
///
1335+
/// This type is a [`SystemParam`] adapter which always has
1336+
/// `Self::Fetch::Item == Self` (ignoring lifetimes for brevity),
1337+
/// no matter the argument [`SystemParam`] (`P`) (other than
1338+
/// that `P` must be `'static`)
1339+
///
1340+
/// This makes it useful for having arbitrary [`SystemParam`] type arguments
1341+
/// to function systems, or for generic types using the [`derive@SystemParam`]
1342+
/// derive:
1343+
///
1344+
/// ```
1345+
/// # use bevy_ecs::prelude::*;
1346+
/// use bevy_ecs::system::{SystemParam, StaticSystemParam};
1347+
/// #[derive(SystemParam)]
1348+
/// struct GenericParam<'w,'s, T: SystemParam + 'static> {
1349+
/// field: StaticSystemParam<'w, 's, T>,
1350+
/// }
1351+
/// fn do_thing_generically<T: SystemParam + 'static>(t: StaticSystemParam<T>) {}
1352+
///
1353+
/// fn check_always_is_system<T: SystemParam + 'static>(){
1354+
/// do_thing_generically::<T>.system();
1355+
/// }
1356+
/// ```
1357+
/// Note that in a real case you'd generally want
1358+
/// additional bounds on `P`, for your use of the parameter
1359+
/// to have a reason to be generic.
1360+
///
1361+
/// For example, using this would allow a type to be generic over
1362+
/// whether a resource is accessed mutably or not, with
1363+
/// impls being bounded on [`P: Deref<Target=MyType>`](Deref), and
1364+
/// [`P: DerefMut<Target=MyType>`](DerefMut) depending on whether the
1365+
/// method requires mutable access or not.
1366+
///
1367+
/// The method which doesn't use this type will not compile:
1368+
/// ```compile_fail
1369+
/// # use bevy_ecs::prelude::*;
1370+
/// # use bevy_ecs::system::{SystemParam, StaticSystemParam};
1371+
///
1372+
/// fn do_thing_generically<T: SystemParam + 'static>(t: T) {}
1373+
///
1374+
/// #[derive(SystemParam)]
1375+
/// struct GenericParam<'w,'s, T: SystemParam> {
1376+
/// field: T,
1377+
/// #[system_param(ignore)]
1378+
/// // Use the lifetimes, as the `SystemParam` derive requires them
1379+
/// phantom: core::marker::PhantomData<&'w &'s ()>
1380+
/// }
1381+
/// # fn check_always_is_system<T: SystemParam + 'static>(){
1382+
/// # do_thing_generically::<T>.system();
1383+
/// # }
1384+
/// ```
1385+
///
1386+
pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>);
1387+
1388+
impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> {
1389+
type Target = SystemParamItem<'w, 's, P>;
1390+
1391+
fn deref(&self) -> &Self::Target {
1392+
&self.0
1393+
}
1394+
}
1395+
1396+
impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> {
1397+
fn deref_mut(&mut self) -> &mut Self::Target {
1398+
&mut self.0
1399+
}
1400+
}
1401+
1402+
impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
1403+
/// Get the value of the parameter
1404+
pub fn into_inner(self) -> SystemParamItem<'w, 's, P> {
1405+
self.0
1406+
}
1407+
}
1408+
1409+
/// The [`SystemParamState`] of [`SystemChangeTick`].
1410+
pub struct StaticSystemParamState<S, P>(S, PhantomData<fn() -> P>);
1411+
1412+
// Safe: This doesn't add any more reads, and the delegated fetch confirms it
1413+
unsafe impl<'w, 's, S: ReadOnlySystemParamFetch, P> ReadOnlySystemParamFetch
1414+
for StaticSystemParamState<S, P>
1415+
{
1416+
}
1417+
1418+
impl<'world, 'state, P: SystemParam + 'static> SystemParam
1419+
for StaticSystemParam<'world, 'state, P>
1420+
{
1421+
type Fetch = StaticSystemParamState<P::Fetch, P>;
1422+
}
1423+
1424+
impl<'world, 'state, S: SystemParamFetch<'world, 'state>, P: SystemParam + 'static>
1425+
SystemParamFetch<'world, 'state> for StaticSystemParamState<S, P>
1426+
where
1427+
P: SystemParam<Fetch = S>,
1428+
{
1429+
type Item = StaticSystemParam<'world, 'state, P>;
1430+
1431+
unsafe fn get_param(
1432+
state: &'state mut Self,
1433+
system_meta: &SystemMeta,
1434+
world: &'world World,
1435+
change_tick: u32,
1436+
) -> Self::Item {
1437+
// Safe: We properly delegate SystemParamState
1438+
StaticSystemParam(S::get_param(&mut state.0, system_meta, world, change_tick))
1439+
}
1440+
}
1441+
1442+
unsafe impl<'w, 's, S: SystemParamState, P: SystemParam + 'static> SystemParamState
1443+
for StaticSystemParamState<S, P>
1444+
{
1445+
type Config = S::Config;
1446+
1447+
fn init(world: &mut World, system_meta: &mut SystemMeta, config: Self::Config) -> Self {
1448+
Self(S::init(world, system_meta, config), PhantomData)
1449+
}
1450+
1451+
fn default_config() -> Self::Config {
1452+
S::default_config()
1453+
}
1454+
fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
1455+
self.0.new_archetype(archetype, system_meta)
1456+
}
1457+
1458+
fn apply(&mut self, world: &mut World) {
1459+
self.0.apply(world)
1460+
}
1461+
}
1462+
13331463
#[cfg(test)]
13341464
mod tests {
13351465
use super::SystemParam;

crates/bevy_render/src/render_asset.rs

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy_app::{App, Plugin};
33
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
44
use bevy_ecs::{
55
prelude::*,
6-
system::{lifetimeless::*, RunSystem, SystemParam, SystemParamItem},
6+
system::{StaticSystemParam, SystemParam, SystemParamItem},
77
};
88
use bevy_utils::{HashMap, HashSet};
99
use std::marker::PhantomData;
@@ -55,13 +55,12 @@ impl<A: RenderAsset> Default for RenderAssetPlugin<A> {
5555
impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
5656
fn build(&self, app: &mut App) {
5757
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
58-
let prepare_asset_system = PrepareAssetSystem::<A>::system(&mut render_app.world);
5958
render_app
6059
.init_resource::<ExtractedAssets<A>>()
6160
.init_resource::<RenderAssets<A>>()
6261
.init_resource::<PrepareNextFrameAssets<A>>()
6362
.add_system_to_stage(RenderStage::Extract, extract_render_asset::<A>)
64-
.add_system_to_stage(RenderStage::Prepare, prepare_asset_system);
63+
.add_system_to_stage(RenderStage::Prepare, prepare_assets::<A>);
6564
}
6665
}
6766
}
@@ -122,14 +121,6 @@ fn extract_render_asset<A: RenderAsset>(
122121
})
123122
}
124123

125-
/// Specifies all ECS data required by [`PrepareAssetSystem`].
126-
pub type RenderAssetParams<R> = (
127-
SResMut<ExtractedAssets<R>>,
128-
SResMut<RenderAssets<R>>,
129-
SResMut<PrepareNextFrameAssets<R>>,
130-
<R as RenderAsset>::Param,
131-
);
132-
133124
// TODO: consider storing inside system?
134125
/// All assets that should be prepared next frame.
135126
pub struct PrepareNextFrameAssets<A: RenderAsset> {
@@ -146,38 +137,36 @@ impl<A: RenderAsset> Default for PrepareNextFrameAssets<A> {
146137

147138
/// This system prepares all assets of the corresponding [`RenderAsset`] type
148139
/// which where extracted this frame for the GPU.
149-
pub struct PrepareAssetSystem<R: RenderAsset>(PhantomData<R>);
150-
151-
impl<R: RenderAsset> RunSystem for PrepareAssetSystem<R> {
152-
type Param = RenderAssetParams<R>;
153-
154-
fn run(
155-
(mut extracted_assets, mut render_assets, mut prepare_next_frame, mut param): SystemParamItem<Self::Param>,
156-
) {
157-
let mut queued_assets = std::mem::take(&mut prepare_next_frame.assets);
158-
for (handle, extracted_asset) in queued_assets.drain(..) {
159-
match R::prepare_asset(extracted_asset, &mut param) {
160-
Ok(prepared_asset) => {
161-
render_assets.insert(handle, prepared_asset);
162-
}
163-
Err(PrepareAssetError::RetryNextUpdate(extracted_asset)) => {
164-
prepare_next_frame.assets.push((handle, extracted_asset));
165-
}
140+
fn prepare_assets<R: RenderAsset>(
141+
mut extracted_assets: ResMut<ExtractedAssets<R>>,
142+
mut render_assets: ResMut<RenderAssets<R>>,
143+
mut prepare_next_frame: ResMut<PrepareNextFrameAssets<R>>,
144+
param: StaticSystemParam<<R as RenderAsset>::Param>,
145+
) {
146+
let mut param = param.into_inner();
147+
let mut queued_assets = std::mem::take(&mut prepare_next_frame.assets);
148+
for (handle, extracted_asset) in queued_assets.drain(..) {
149+
match R::prepare_asset(extracted_asset, &mut param) {
150+
Ok(prepared_asset) => {
151+
render_assets.insert(handle, prepared_asset);
152+
}
153+
Err(PrepareAssetError::RetryNextUpdate(extracted_asset)) => {
154+
prepare_next_frame.assets.push((handle, extracted_asset));
166155
}
167156
}
157+
}
168158

169-
for removed in std::mem::take(&mut extracted_assets.removed) {
170-
render_assets.remove(&removed);
171-
}
159+
for removed in std::mem::take(&mut extracted_assets.removed) {
160+
render_assets.remove(&removed);
161+
}
172162

173-
for (handle, extracted_asset) in std::mem::take(&mut extracted_assets.extracted) {
174-
match R::prepare_asset(extracted_asset, &mut param) {
175-
Ok(prepared_asset) => {
176-
render_assets.insert(handle, prepared_asset);
177-
}
178-
Err(PrepareAssetError::RetryNextUpdate(extracted_asset)) => {
179-
prepare_next_frame.assets.push((handle, extracted_asset));
180-
}
163+
for (handle, extracted_asset) in std::mem::take(&mut extracted_assets.extracted) {
164+
match R::prepare_asset(extracted_asset, &mut param) {
165+
Ok(prepared_asset) => {
166+
render_assets.insert(handle, prepared_asset);
167+
}
168+
Err(PrepareAssetError::RetryNextUpdate(extracted_asset)) => {
169+
prepare_next_frame.assets.push((handle, extracted_asset));
181170
}
182171
}
183172
}

0 commit comments

Comments
 (0)