Skip to content

Conversation

@ecoskey
Copy link
Contributor

@ecoskey ecoskey commented Dec 4, 2025

Objective

Allow reborrowing for QueryData types. The end goal here is to work towards a fast System::run_iter api, avoiding the overhead of get_param with each iteration. Funnily enough the only system param that actually needs this is Single, but it seems worthwhile to have anyways

Next steps:

  1. ReborrowSystemParam
  2. SystemIter

Solution

  • Add ReborrowQueryData, an optional subtrait (though almost all QueryData types should implement this in practice)
/// A [`QueryData`] that's able to be reborrowed, converting a reference into
/// an owned struct with a shorter lifetime.
pub trait ReborrowQueryData: QueryData {
    /// Returns a `QueryData` item with a smaller lifetime.
    fn reborrow<'wlong: 'short, 'slong: 'short, 'short>(
        item: &'short mut Self::Item<'wlong, 'slong>,
    ) -> Self::Item<'short, 'short>;
}

@ecoskey ecoskey added A-ECS Entities, components, systems, and events D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged C-Feature A new feature, making something new possible S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Dec 4, 2025
@ecoskey ecoskey force-pushed the feature/query_reborrow branch 2 times, most recently from 6becb1e to 6f0ab87 Compare December 6, 2025 21:52
@ecoskey ecoskey force-pushed the feature/query_reborrow branch from 6f0ab87 to 2538b79 Compare December 9, 2025 02:11
Copy link
Contributor

@NicoZweifel NicoZweifel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty neat! This makes total sense to me in terms of utility functions and the like. I suggested a test that tests exactly this use case.

Other than that there are only a few minor things:

  • For the EntityRef types, we can dereference and use the Copy implementations instead of manually creating the struct again, which is a bit more maintainable.

  • The implemention of Ref<> can also be slightly simplified since ComponentTicksRef implements Clone.

  • I noticed a few missing square brackets in the doc comments.


fn assert_is_reborrow_query_data<Q: ReborrowQueryData>() {}
assert_is_reborrow_query_data::<ReborrowData>();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}
#[test]
fn test_reborrow_allows_reuse() {
#[derive(Component)]
struct A(f32);
fn increment(mut component: Mut<A>) {
component.0 += 1.;
}
let mut world = World::new();
world.spawn(A(0.));
let mut query = world.query::<&mut A>();
let mut component = query.single_mut(&mut world).unwrap();
increment(component.reborrow());
component.0 += 1.;
assert_eq!(component.0, 2.0);
}

Comment on lines +290 to +291
/// Returns an `EntityRef<>` with a smaller lifetime.
/// This is useful if you have `&EntityRef`, but you need an `EntityRef`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns an `EntityRef<>` with a smaller lifetime.
/// This is useful if you have `&EntityRef`, but you need an `EntityRef`.
/// Returns an [`EntityRef<>`] with a smaller lifetime.
/// This is useful if you have &[`EntityRef`], but you need an [`EntityRef`].

Comment on lines +193 to +194
/// Returns an `EntityRefExcept<>` with a smaller lifetime.
/// This is useful if you have `&EntityRefExcept`, but you need an `EntityRefExcept`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns an `EntityRefExcept<>` with a smaller lifetime.
/// This is useful if you have `&EntityRefExcept`, but you need an `EntityRefExcept`.
/// Returns an [`EntityRefExcept<>`] with a smaller lifetime.
/// This is useful if you have &[`EntityRefExcept`], but you need an [`EntityRefExcept`].

Comment on lines +212 to +213
/// Returns an `FilteredEntityRef<>` with a smaller lifetime.
/// This is useful if you have `&FilteredEntityRef`, but you need an `FilteredEntityRef`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns an `FilteredEntityRef<>` with a smaller lifetime.
/// This is useful if you have `&FilteredEntityRef`, but you need an `FilteredEntityRef`.
/// Returns an [`FilteredEntityRef<>`] with a smaller lifetime.
/// This is useful if you have &[`FilteredEntityRef`], but you need an [`FilteredEntityRef`].

Comment on lines +364 to +365
/// Returns a `Mut<>` with a smaller lifetime.
/// This is useful if you have `&Ref<T>`, but you need a `Ref<T>`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns a `Mut<>` with a smaller lifetime.
/// This is useful if you have `&Ref<T>`, but you need a `Ref<T>`.
/// Returns a [`Mut<>`] with a smaller lifetime.
/// This is useful if you have &[`Ref<T>`], but you need a [`Ref<T>`].

/// A [`QueryData`] that's able to be reborrowed, converting a reference into
/// an owned struct with a shorter lifetime.
pub trait ReborrowQueryData: QueryData {
/// Returns a `QueryData` item with a smaller lifetime.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns a `QueryData` item with a smaller lifetime.
/// Returns a [`QueryData`] item with a smaller lifetime.

Comment on lines +196 to +200
EntityRefExcept {
entity: self.entity,
access: self.access,
phantom: PhantomData,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
EntityRefExcept {
entity: self.entity,
access: self.access,
phantom: PhantomData,
}
*self

/// Returns an `EntityRef<>` with a smaller lifetime.
/// This is useful if you have `&EntityRef`, but you need an `EntityRef`.
pub fn reborrow(&self) -> EntityRef<'_> {
EntityRef { cell: self.cell }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
EntityRef { cell: self.cell }
*self

Comment on lines +215 to +218
FilteredEntityRef {
entity: self.entity,
access: self.access,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FilteredEntityRef {
entity: self.entity,
access: self.access,
}
*self

Comment on lines +367 to +376
Ref {
value: self.value,
ticks: ComponentTicksRef {
added: self.ticks.added,
changed: self.ticks.changed,
changed_by: self.ticks.changed_by,
last_run: self.ticks.last_run,
this_run: self.ticks.this_run,
},
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Ref {
value: self.value,
ticks: ComponentTicksRef {
added: self.ticks.added,
changed: self.ticks.changed,
changed_by: self.ticks.changed_by,
last_run: self.ticks.last_run,
this_run: self.ticks.this_run,
},
}
Ref {
ticks: self.ticks.clone(),
..*self
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants