Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Resource trait opt-in, requiring #[derive(Resource)] #5007

Closed
wants to merge 10 commits into from

Conversation

alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jun 13, 2022

Objective

Follow-up to #2254. The Resource trait currently has a blanket implementation for all types that meet its bounds.

While ergonomic, this results in several drawbacks:

  • it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
  • it is challenging to discover if a type is intended to be used as a resource
  • we cannot later add customization options (see the RFC for the equivalent choice for Component).
  • dependencies can use the same Rust type as a resource in invisibly conflicting ways
  • raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
  • we cannot capture a definitive list of possible resources to display to users in an editor

Notes to reviewers

  1. Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
  2. I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
  3. I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with Add more granular features to bevy_ecs #4981.

Changelog

Resource is no longer automatically implemented for all matching types. Instead, use the new #[derive(Resource)] macro.

Migration Guide

Add #[derive(Resource)] to all types you are using as a resource.

If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving Deref and DerefMut to improve ergonomics.

@alice-i-cecile alice-i-cecile marked this pull request as draft June 13, 2022 21:57
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide X-Controversial There is active debate or serious implications around merging this PR labels Jun 13, 2022
@alice-i-cecile
Copy link
Member Author

alice-i-cecile commented Jun 14, 2022

@bevyengine/rendering-team the only remaining types to be updated are a bunch of reimported WGPU types / type aliased types (check CI for a list of failures). Would you like me to newtype those?

@alice-i-cecile alice-i-cecile added this to the Bevy 0.8 milestone Jun 14, 2022
@superdump
Copy link
Contributor

@bevyengine/rendering-team the only remaining types to be updated are a bunch of reimported WGPU types / type aliased types (check CI for a list of failures). Would you like me to newtype those?

Ohno. We have to newtype a bunch of stuff? Sadness. :/ I guess if we have to then sure.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

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

I can't remember what my first comments were.

But I don't think I found anything blocking.

@@ -40,7 +40,7 @@ fn main() {
}

// This struct will be used as a Resource keeping track of the total amount of spawned entities
Copy link
Member

Choose a reason for hiding this comment

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

Since it has a derive Resource, this first sentence is superfluous

However I'm happy leaving this, for a doc consistency pass at some point in the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep; IMO this will be easier to do in a follow-up PR, where we can search our dev docs site for "resource" and make a call.

@@ -480,6 +480,11 @@ pub(crate) fn bevy_ecs_path() -> syn::Path {
BevyManifest::default().get_path("bevy_ecs")
}

#[proc_macro_derive(Resource)]
pub fn derive_resource(input: TokenStream) -> TokenStream {
component::derive_resource(input)
Copy link
Member

Choose a reason for hiding this comment

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

Should this live in the component module?

I guess it's fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

My argument here is that it should change in concert with the derive Component macro, so should live together.

I was thinking about renaming the module, but struggled to find a clear enough blanket name.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think both components and resources can be viewed as storage.

@@ -154,3 +156,6 @@ impl<C: Component + MapEntities> FromType<C> for ReflectMapEntities {
}
}
}

// We cannot implement this in bevy_reflect, or we would create a cyclic dependendency
impl Resource for TypeRegistryArc {}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not very happy with this.

I'd rather we created a wrapper resource.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, I'm on board with this. This was the simple non-breaking solution so I wanted reviewer feedback.

@@ -639,12 +647,12 @@ impl<'w, 's> SystemParamFetch<'w, 's> for WorldState {
/// // .add_system(reset_to_system(my_config))
/// # assert_is_system(reset_to_system(Config(10)));
/// ```
pub struct Local<'a, T: Resource>(&'a mut T);
pub struct Local<'a, T: Send + Sync + 'static>(&'a mut T);
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this Sync bound should be needed, although if removing it doesn't work that's also fine.

(I wonder if there's an abstraction to turn !Sync into Sync by enforcing access through a unique reference)

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree here. Started with the trivial conversion though :)

Copy link
Contributor

Choose a reason for hiding this comment

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

(I wonder if there's an abstraction to turn !Sync into Sync by enforcing access through a unique reference)

There's sync_wrapper for exactly this purpose. A similar thing is proposed in the standard library.

crates/bevy_ecs/src/system/system_param.rs Outdated Show resolved Hide resolved
Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
Comment on lines +224 to +232
/// A type that can be inserted into a [`World`](crate::world::World) as a singleton.
///
/// Resources are commonly used to store global collections (like assets or events),
/// or unique global information (such as the current level or state of the app).
///
/// You can access resource data in systems using the [`Res`] and [`ResMut`] system parameters.
///
/// Only one resource of each type can exist at any given time.
/// Inserting a duplicate resource will overwrite the existing resource.
Copy link
Contributor

@Nilirad Nilirad Jun 15, 2022

Choose a reason for hiding this comment

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

The second paragraph seems too specific to me: mentioning use cases and applications is something more suitable to the book imo. API docs are best suited to describe the item itself.

This description also does not illustrate how to insert a resource to the world (i.e. World::init_resource or World::insert_resource). I would avoid mentioning the App methods though, as they are not defined from the bevy_ecs perspective.

Comment on lines +224 to +232
/// A type that can be inserted into a [`World`](crate::world::World) as a singleton.
///
/// Resources are commonly used to store global collections (like assets or events),
/// or unique global information (such as the current level or state of the app).
///
/// You can access resource data in systems using the [`Res`] and [`ResMut`] system parameters.
///
/// Only one resource of each type can exist at any given time.
/// Inserting a duplicate resource will overwrite the existing resource.
Copy link
Contributor

Choose a reason for hiding this comment

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

Inserting a duplicate resource will overwrite the existing resource.

This is something that is up to the insert_resource method and not to the type that implements Resource. Also, if the concept of “inserting” is broadened to init_resource, that statement becomes incorrect.

@tim-blackbird
Copy link
Contributor

I'm working on this :)

@alice-i-cecile
Copy link
Member Author

Closing in favor of #5577.

bors bot pushed a commit that referenced this pull request Aug 8, 2022
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to #2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.

While ergonomic, this results in several drawbacks:

* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
 * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
   *ira: My commits are not as well organized :')*
 * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
 * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with #4981.

## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.

## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.

If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.

`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.


Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
maccesch pushed a commit to Synphonyte/bevy that referenced this pull request Sep 28, 2022
…yengine#5577)

*This PR description is an edited copy of bevyengine#5007, written by @alice-i-cecile.*
# Objective
Follow-up to bevyengine#2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.

While ergonomic, this results in several drawbacks:

* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
 * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
   *ira: My commits are not as well organized :')*
 * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
 * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with bevyengine#4981.

## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.

## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.

If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.

`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.


Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
…yengine#5577)

*This PR description is an edited copy of bevyengine#5007, written by @alice-i-cecile.*
# Objective
Follow-up to bevyengine#2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.

While ergonomic, this results in several drawbacks:

* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
 * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
   *ira: My commits are not as well organized :')*
 * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
 * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with bevyengine#4981.

## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.

## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.

If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.

`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.


Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
…yengine#5577)

*This PR description is an edited copy of bevyengine#5007, written by @alice-i-cecile.*
# Objective
Follow-up to bevyengine#2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.

While ergonomic, this results in several drawbacks:

* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
 * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
   *ira: My commits are not as well organized :')*
 * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
 * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with bevyengine#4981.

## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.

## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.

If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.

`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.


Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
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-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants