Skip to content

Resource hooks & immutable resources#24164

Merged
alice-i-cecile merged 21 commits intobevyengine:mainfrom
SpecificProtagonist:push-wrllsyktsrlt
May 8, 2026
Merged

Resource hooks & immutable resources#24164
alice-i-cecile merged 21 commits intobevyengine:mainfrom
SpecificProtagonist:push-wrllsyktsrlt

Conversation

@SpecificProtagonist
Copy link
Copy Markdown
Contributor

@SpecificProtagonist SpecificProtagonist commented May 7, 2026

Objective

Enables the resource derive macro to specify the attributes for

Also fixes resource_scope overwriting change ticks and a few related doc comments.

Showcase

#[derive(Resource)]
#[component(immutable)]
#[component(on_insert = update_level, on_discard = update_level)]
struct Level(i32);

@SpecificProtagonist SpecificProtagonist added A-ECS Entities, components, systems, and events S-Needs-Review Needs reviewer attention (from anyone!) to move forward D-Macros Code that generates Rust code labels May 7, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in ECS May 7, 2026
@alice-i-cecile alice-i-cecile added this to the 0.19 milestone May 7, 2026
@alice-i-cecile alice-i-cecile added the M-Release-Note Work that should be called out in the blog due to impact label May 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note.

Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes.

@alice-i-cecile
Copy link
Copy Markdown
Member

Drop this pr in the resources as entities release notes please!

Copy link
Copy Markdown
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

Needs a test please <3

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 7, 2026
@SpecificProtagonist SpecificProtagonist changed the title Resource hooks Resource hooks & immutable resources May 7, 2026
@SpecificProtagonist SpecificProtagonist added 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 May 7, 2026
@alice-i-cecile alice-i-cecile added the D-Straightforward Simple bug fixes and API improvements, docs, test and examples label May 7, 2026
Comment thread crates/bevy_ecs/src/resource.rs
Copy link
Copy Markdown
Contributor

@urben1680 urben1680 left a comment

Choose a reason for hiding this comment

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

You should go through every API that offers mutable references to resources and add a <Mutability = Mutable> bound to them, I think that is missing. Like World::get_resource_mut. Untyped methods like World::get_resource_mut_by_id should fail if the resource is immutable.

Copy link
Copy Markdown
Contributor

@Trashtalk217 Trashtalk217 left a comment

Choose a reason for hiding this comment

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

ResMut shouldn't work on immutable resources. Is that implemented?

Comment thread _release-content/release-notes/resources_as_components.md
/// or a function call that returns a function that can be turned into
/// a `ComponentHook`, e.g. `get_closure("Hi!")`.
/// `function` can be elided if the path is `Self::on_add`, `Self::on_insert` etc.
#[proc_macro_derive(Resource, attributes(component))]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When I originally envisioned this, I called it #[resource(...)]. It doesn't really matter, but it might be easier to understand.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I do not have a strong opinion on this, happy to change it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Me neither :)

@alice-i-cecile
Copy link
Copy Markdown
Member

This looks good now; is there anything else you'd like to do beyond getting CI passing?

@urben1680
Copy link
Copy Markdown
Contributor

urben1680 commented May 7, 2026

Please don't forget to address my note: #24164 (review)

If you can mutate immutable resources via World/DeferredWorld/EntityWorldMut methods (and maybe others?) that would be bad.

@SpecificProtagonist
Copy link
Copy Markdown
Contributor Author

Please don't forget to address my note

The dynamic methods refuse to return a MutUntyped with immutable component. The typed ones (incl. system param) can give you a ResMut, but it doesn't have any mutation methods for immutable resources. There are some fixed I still need to make:

This looks good now; is there anything else you'd like to do beyond getting CI passing?

  • FilteredResourcesMut::get_mut_by_id_unchecked needs to refuse immutable components.
  • typed methods granting ResMut should not silently fail on immutable components

@urben1680
Copy link
Copy Markdown
Contributor

urben1680 commented May 7, 2026

The typed ones (incl. system param) can give you a ResMut, but it doesn't have any mutation methods for immutable resources.

Seems not to be true, or you miss that I talk about World/DeferredWorld/EntityWorldMut methods, not system params / query data.

World::resource_mut returns a Mut<T> for mutable resources and panics for immutable ones currently I think. World::get_resource_mut returns None for immutable resources.
But For both I would actually prefer a bound on the generic type because that is how it is for fetching mutable references of components. For example World::get_mut.

@SpecificProtagonist SpecificProtagonist added 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 May 7, 2026
@chescock
Copy link
Copy Markdown
Contributor

chescock commented May 7, 2026

ResMut shouldn't work on immutable resources. Is that implemented?

You cannot get a ResMut for an immutable resource (edit: found one place that still allows it: FilteredResourcesMut when used with a dynamic id).
I do want to also statically enforce this. Should mutability be required by

  • ResMut, or
  • all ResMut methods that allow mutation?

The standard library tends to go for the later (see e.g. HashMap).

Hmm. Let's do the latter to make generic code easier.

One disadvantage of allowing ResMut<ImmutableResource> to exist is that it creates an actual &mut ImmutableResource. Prohibiting &muts opens up some interesting possibilities, such as declaring that it's valid to obtain an &ImmutableResource from an UnsafeWorldCell without tracking access.

@alice-i-cecile
Copy link
Copy Markdown
Member

We could do both even. No strong feelings here, but I would like to get this merged in a timely fashion.

@alice-i-cecile alice-i-cecile requested a review from chescock May 8, 2026 03:23
Copy link
Copy Markdown
Contributor

@urben1680 urben1680 left a comment

Choose a reason for hiding this comment

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

I think there are a handful of APIs that need <Mutability = Mutable> bounds:

I wonder if try_resource_scope does need to do extra care for immutable resources to ensure that the insert and change tick are equal.

@SpecificProtagonist
Copy link
Copy Markdown
Contributor Author

SpecificProtagonist commented May 8, 2026

We could do both even.

I'm not sure what you mean?

World::get_resource_or_init World::get_resource_or_insert_with

Thanks!

I wonder if try_resource_scope does need to do extra care for immutable resources to ensure that the insert and change tick are equal.

Resource scope doesn't care much about component mutability. But on main, the resource scope always set both added and changed to the value that changed had beforehand, making both wrong. Since I've had to touch that function anyways, I fixed it and added a test.

But For both I would actually prefer a bound on the generic type because that is how it is for fetching mutable references of components.

Note that a difference between ResMut and Mut is that the former knows whether the resource is mutable, the later doesn't. But no strong opinions from me here.

But I've added a commit that switches ResMut to require Mutability = Mutable.

Comment thread crates/bevy_ecs/src/world/mod.rs Outdated
@SpecificProtagonist SpecificProtagonist added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 8, 2026
@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 8, 2026
Merged via the queue into bevyengine:main with commit ae2fcc0 May 8, 2026
40 checks passed
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in ECS May 8, 2026
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 D-Macros Code that generates Rust code M-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Immutable resources Support hooks on resource types

5 participants