Skip to content

Commit 0aeee84

Browse files
committed
ReborrowSystemParam
fix all impls
1 parent 6becb1e commit 0aeee84

File tree

13 files changed

+525
-47
lines changed

13 files changed

+525
-47
lines changed

crates/bevy_ecs/macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ proc-macro = true
1111
[dependencies]
1212
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.18.0-dev" }
1313

14-
syn = { version = "2.0.108", features = ["full", "extra-traits"] }
14+
syn = { version = "2.0.108", features = ["full", "extra-traits", "visit-mut"] }
1515
quote = "1.0"
1616
proc-macro2 = "1.0"
1717
[lints]

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use proc_macro::TokenStream;
2020
use proc_macro2::{Ident, Span};
2121
use quote::{format_ident, quote, ToTokens};
2222
use syn::{
23-
parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, ConstParam, Data,
24-
DeriveInput, GenericParam, TypeParam,
23+
parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, visit_mut::VisitMut,
24+
ConstParam, Data, DeriveInput, GenericParam, TypeParam,
2525
};
2626

2727
enum BundleFieldKind {
@@ -229,6 +229,16 @@ pub fn derive_map_entities(input: TokenStream) -> TokenStream {
229229
})
230230
}
231231

232+
struct LifetimeEraser {
233+
erased_ident: Ident,
234+
}
235+
236+
impl VisitMut for LifetimeEraser {
237+
fn visit_lifetime_mut(&mut self, i: &mut syn::Lifetime) {
238+
i.ident = self.erased_ident.clone();
239+
}
240+
}
241+
232242
/// Implement `SystemParam` to use a struct as a parameter in a system
233243
#[proc_macro_derive(SystemParam, attributes(system_param))]
234244
pub fn derive_system_param(input: TokenStream) -> TokenStream {
@@ -240,6 +250,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
240250
Err(e) => e.into_compile_error().into(),
241251
}
242252
}
253+
243254
fn derive_system_param_impl(
244255
token_stream: TokenStream,
245256
ast: DeriveInput,
@@ -253,6 +264,17 @@ fn derive_system_param_impl(
253264
.collect::<Vec<_>>();
254265
let field_members = fields.members().collect::<Vec<_>>();
255266
let field_types = fields.iter().map(|f| &f.ty).collect::<Vec<_>>();
267+
let shadowed_lifetime_field_types = fields
268+
.iter()
269+
.map(|f| {
270+
let mut ty = f.ty.clone();
271+
let mut eraser = LifetimeEraser {
272+
erased_ident: format_ident!("static"),
273+
};
274+
syn::visit_mut::visit_type_mut(&mut eraser, &mut ty);
275+
ty
276+
})
277+
.collect::<Vec<_>>();
256278

257279
let field_validation_names = fields.members().map(|m| format!("::{}", quote! { #m }));
258280
let mut field_validation_messages = Vec::with_capacity(fields.len());
@@ -356,6 +378,18 @@ fn derive_system_param_impl(
356378
.push(syn::parse_quote!(#field_type: #path::system::ReadOnlySystemParam));
357379
}
358380

381+
// Create a where clause for the `ReborrowSystemParam` impl.
382+
// Ensure that each field implements `ReborrowSystemParam`.
383+
let mut reborrow_generics = generics.clone();
384+
let reborrow_where_clause = reborrow_generics.make_where_clause();
385+
for (shadowed_lifetime_field_type, field_type) in
386+
shadowed_lifetime_field_types.iter().zip(&field_types)
387+
{
388+
reborrow_where_clause
389+
.predicates
390+
.push(syn::parse_quote!(for<'w, 's> #shadowed_lifetime_field_type: #path::system::ReborrowSystemParam<Item<'w, 's> = #field_type>));
391+
}
392+
359393
let fields_alias =
360394
ensure_no_collision(format_ident!("__StructFieldsAlias"), token_stream.clone());
361395

@@ -482,6 +516,19 @@ fn derive_system_param_impl(
482516
// Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World`
483517
unsafe impl<'w, 's, #punctuated_generics> #path::system::ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause {}
484518

519+
impl<#punctuated_generics> #path::system::ReborrowSystemParam for #struct_name <#(#shadowed_lifetimes,)* #punctuated_generic_idents> #reborrow_where_clause {
520+
fn reborrow<'wlong: 'short, 'slong: 'short, 'short>(
521+
item: &'short mut Self::Item<'wlong, 'slong>,
522+
) -> Self::Item<'short, 'short> {
523+
#(
524+
let #field_locals = <#shadowed_lifetime_field_types as #path::system::ReborrowSystemParam>::reborrow(&mut item.#field_members);
525+
)*
526+
#struct_name {
527+
#(#field_members: #field_locals,)*
528+
}
529+
}
530+
}
531+
485532
#builder_impl
486533
};
487534

crates/bevy_ecs/src/change_detection/params.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,21 @@ impl<'w, T: Resource> Res<'w, T> {
123123
pub fn into_inner(self) -> &'w T {
124124
self.value
125125
}
126+
127+
/// Returns a `Res<>` with a smaller lifetime.
128+
/// This is useful if you have `&Res`, but you need a `Res`.
129+
pub fn reborrow(&self) -> Res<'_, T> {
130+
Res {
131+
value: self.value,
132+
ticks: ComponentTicksRef {
133+
added: self.ticks.added,
134+
changed: self.ticks.changed,
135+
changed_by: self.ticks.changed_by,
136+
last_run: self.ticks.last_run,
137+
this_run: self.ticks.this_run,
138+
},
139+
}
140+
}
126141
}
127142

128143
impl<'w, T: Resource> From<ResMut<'w, T>> for Res<'w, T> {
@@ -243,6 +258,23 @@ impl<'w, T> From<NonSendMut<'w, T>> for NonSend<'w, T> {
243258
}
244259
}
245260

261+
impl<'w, T> NonSend<'w, T> {
262+
/// Returns a `NonSend<>` with a smaller lifetime.
263+
/// This is useful if you have `&NonSend<T>`, but you need a `NonSend<T>`.
264+
pub fn reborrow(&mut self) -> NonSend<'_, T> {
265+
NonSend {
266+
value: self.value,
267+
ticks: ComponentTicksRef {
268+
added: self.ticks.added,
269+
changed: self.ticks.changed,
270+
changed_by: self.ticks.changed_by,
271+
last_run: self.ticks.last_run,
272+
this_run: self.ticks.this_run,
273+
},
274+
}
275+
}
276+
}
277+
246278
/// Unique borrow of a non-[`Send`] resource.
247279
///
248280
/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the

crates/bevy_ecs/src/change_detection/traits.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,12 +449,16 @@ macro_rules! impl_methods {
449449
self.value
450450
}
451451

452-
/// Returns a `Mut<>` with a smaller lifetime.
452+
/// Returns a `
453+
#[doc = stringify!($name)]
454+
/// <>` with a smaller lifetime.
453455
/// This is useful if you have `&mut
454456
#[doc = stringify!($name)]
455-
/// <T>`, but you need a `Mut<T>`.
456-
pub fn reborrow(&mut self) -> Mut<'_, $target> {
457-
Mut {
457+
/// <T>`, but you need a `
458+
#[doc = stringify!($name)]
459+
/// <T>`.
460+
pub fn reborrow(&mut self) -> $name<'_, $target> {
461+
$name {
458462
value: self.value,
459463
ticks: ComponentTicksMut {
460464
added: self.ticks.added,

crates/bevy_ecs/src/lifecycle.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use crate::{
6060
query::FilteredAccessSet,
6161
relationship::RelationshipHookMode,
6262
storage::SparseSet,
63-
system::{Local, ReadOnlySystemParam, SystemMeta, SystemParam},
63+
system::{Local, ReadOnlySystemParam, ReborrowSystemParam, SystemMeta, SystemParam},
6464
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
6565
};
6666

@@ -641,3 +641,11 @@ unsafe impl<'a> SystemParam for &'a RemovedComponentMessages {
641641
world.removed_components()
642642
}
643643
}
644+
645+
impl<'a> ReborrowSystemParam for &'a RemovedComponentMessages {
646+
fn reborrow<'wlong: 'short, 'slong: 'short, 'short>(
647+
item: &'short mut Self::Item<'wlong, 'slong>,
648+
) -> Self::Item<'short, 'short> {
649+
*item
650+
}
651+
}

crates/bevy_ecs/src/system/commands/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use crate::{
3030
resource::Resource,
3131
schedule::ScheduleLabel,
3232
system::{
33-
Deferred, IntoObserverSystem, IntoSystem, RegisteredSystem, SystemId, SystemInput,
34-
SystemParamValidationError,
33+
Deferred, IntoObserverSystem, IntoSystem, ReborrowSystemParam, RegisteredSystem, SystemId,
34+
SystemInput, SystemParamValidationError,
3535
},
3636
world::{
3737
command_queue::RawCommandQueue, unsafe_world_cell::UnsafeWorldCell, CommandQueue,
@@ -216,6 +216,14 @@ const _: () = {
216216
&'w Entities: bevy_ecs::system::ReadOnlySystemParam,
217217
{
218218
}
219+
220+
impl<'w, 's> ReborrowSystemParam for Commands<'w, 's> {
221+
fn reborrow<'wlong: 'short, 'slong: 'short, 'short>(
222+
item: &'short mut Self::Item<'wlong, 'slong>,
223+
) -> Self::Item<'short, 'short> {
224+
item.reborrow()
225+
}
226+
}
219227
};
220228

221229
enum InternalQueue<'s> {

crates/bevy_ecs/src/system/query.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{
88
DebugCheckedUnwrap, NopWorldQuery, QueryCombinationIter, QueryData, QueryEntityError,
99
QueryFilter, QueryIter, QueryManyIter, QueryManyUniqueIter, QueryParIter, QueryParManyIter,
1010
QueryParManyUniqueIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyQueryData,
11+
ReborrowQueryData,
1112
},
1213
world::unsafe_world_cell::UnsafeWorldCell,
1314
};
@@ -2674,6 +2675,18 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Single<'w, 's, D, F> {
26742675
pub fn into_inner(self) -> D::Item<'w, 's> {
26752676
self.item
26762677
}
2678+
2679+
/// Returns a `Single<>` with a smaller lifetime.
2680+
/// This is useful if you have `&Single`, but you need an `Single`.
2681+
pub fn reborrow(&mut self) -> Single<'_, '_, D, F>
2682+
where
2683+
D: ReborrowQueryData,
2684+
{
2685+
Single {
2686+
item: D::reborrow(&mut self.item),
2687+
_filter: PhantomData,
2688+
}
2689+
}
26772690
}
26782691

26792692
/// [System parameter] that works very much like [`Query`] except it always contains at least one matching entity.
@@ -2710,6 +2723,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Populated<'w, 's, D, F> {
27102723
pub fn into_inner(self) -> Query<'w, 's, D, F> {
27112724
self.0
27122725
}
2726+
2727+
/// Returns a `Populated<>` with a smaller lifetime.
2728+
/// This is useful if you have `&Populated`, but you need a `Populated`.
2729+
pub fn reborrow(&mut self) -> Populated<'_, '_, D, F> {
2730+
Populated(self.0.reborrow())
2731+
}
27132732
}
27142733

27152734
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Populated<'w, 's, D, F> {

crates/bevy_ecs/src/system/system_name.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use crate::{
22
change_detection::Tick,
33
prelude::World,
44
query::FilteredAccessSet,
5-
system::{ExclusiveSystemParam, ReadOnlySystemParam, SystemMeta, SystemParam},
5+
system::{
6+
ExclusiveSystemParam, ReadOnlySystemParam, ReborrowSystemParam, SystemMeta, SystemParam,
7+
},
68
world::unsafe_world_cell::UnsafeWorldCell,
79
};
810
use bevy_utils::prelude::DebugName;
@@ -34,7 +36,7 @@ use derive_more::derive::{Display, Into};
3436
/// logger.log("Hello");
3537
/// }
3638
/// ```
37-
#[derive(Debug, Into, Display)]
39+
#[derive(Debug, Into, Display, Clone)]
3840
pub struct SystemName(DebugName);
3941

4042
impl SystemName {
@@ -70,6 +72,14 @@ unsafe impl SystemParam for SystemName {
7072
}
7173
}
7274

75+
impl ReborrowSystemParam for SystemName {
76+
fn reborrow<'wlong: 'short, 'slong: 'short, 'short>(
77+
item: &'short mut Self::Item<'wlong, 'slong>,
78+
) -> Self::Item<'short, 'short> {
79+
item.clone()
80+
}
81+
}
82+
7383
// SAFETY: Only reads internal system state
7484
unsafe impl ReadOnlySystemParam for SystemName {}
7585

0 commit comments

Comments
 (0)