2022-05-16 13:53:20 +00:00
|
|
|
//! Demonstrates how reflection is used with generic Rust types.
|
|
|
|
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/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 https://github.com/bevyengine/bevy/issues/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>
2022-08-08 21:36:35 +00:00
|
|
|
use bevy::prelude::*;
|
2020-11-28 00:39:59 +00:00
|
|
|
use std::any::TypeId;
|
|
|
|
|
|
|
|
fn main() {
|
2021-07-27 20:21:06 +00:00
|
|
|
App::new()
|
2020-11-28 00:39:59 +00:00
|
|
|
.add_plugins(DefaultPlugins)
|
2022-05-16 13:53:20 +00:00
|
|
|
// You must manually register each instance of a generic type
|
2020-11-28 00:39:59 +00:00
|
|
|
.register_type::<MyType<u32>>()
|
2023-03-18 01:45:34 +00:00
|
|
|
.add_systems(Startup, setup)
|
2020-11-28 00:39:59 +00:00
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
bevy_reflect: Recursive registration (#5781)
# Objective
Resolves #4154
Currently, registration must all be done manually:
```rust
#[derive(Reflect)]
struct Foo(Bar);
#[derive(Reflect)]
struct Bar(Baz);
#[derive(Reflect)]
struct Baz(usize);
fn main() {
// ...
app
.register_type::<Foo>()
.register_type::<Bar>()
.register_type::<Baz>()
// .register_type::<usize>() <- This one is handled by Bevy, thankfully
// ...
}
```
This can grow really quickly and become very annoying to add, remove,
and update as types change. It would be great if we could help reduce
the number of types that a user must manually implement themselves.
## Solution
As suggested in #4154, this PR adds automatic recursive registration.
Essentially, when a type is registered, it may now also choose to
register additional types along with it using the new
`GetTypeRegistration::register_type_dependencies` trait method.
The `Reflect` derive macro now automatically does this for all fields in
structs, tuple structs, struct variants, and tuple variants. This is
also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and
`Option<T>`.
This allows us to simplify the code above like:
```rust
#[derive(Reflect)]
struct Foo(Bar);
#[derive(Reflect)]
struct Bar(Baz);
#[derive(Reflect)]
struct Baz(usize);
fn main() {
// ...
app.register_type::<Foo>()
// ...
}
```
This automatic registration only occurs if the type has not yet been
registered. If it has been registered, we simply skip it and move to the
next one. This reduces the cost of registration and prevents overwriting
customized registrations.
## Considerations
While this does improve ergonomics on one front, it's important to look
at some of the arguments against adopting a PR like this.
#### Generic Bounds
~~Since we need to be able to register the fields individually, we need
those fields to implement `GetTypeRegistration`. This forces users to
then add this trait as a bound on their generic arguments. This
annoyance could be relieved with something like #5772.~~
This is no longer a major issue as the `Reflect` derive now adds the
`GetTypeRegistration` bound by default. This should technically be okay,
since we already add the `Reflect` bound.
However, this can also be considered a breaking change for manual
implementations that left out a `GetTypeRegistration` impl ~~or for
items that contain dynamic types (e.g. `DynamicStruct`) since those also
do not implement `GetTypeRegistration`~~.
#### Registration Assumptions
By automatically registering fields, users might inadvertently be
relying on certain types to be automatically registered. If `Foo`
auto-registers `Bar`, but `Foo` is later removed from the code, then
anywhere that previously used or relied on `Bar`'s registration would
now fail.
---
## Changelog
- Added recursive type registration to structs, tuple structs, struct
variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and
`Option<T>`
- Added a new trait in the hidden `bevy_reflect::__macro_exports` module
called `RegisterForReflection`
- Added `GetTypeRegistration` impl for
`bevy_render::render_asset::RenderAssetUsages`
## Migration Guide
All types that derive `Reflect` will now automatically add
`GetTypeRegistration` as a bound on all (unignored) fields. This means
that all reflected fields will need to also implement
`GetTypeRegistration`.
If all fields **derive** `Reflect` or are implemented in `bevy_reflect`,
this should not cause any issues. However, manual implementations of
`Reflect` that excluded a `GetTypeRegistration` impl for their type will
need to add one.
```rust
#[derive(Reflect)]
struct Foo<T: FromReflect> {
data: MyCustomType<T>
}
// OLD
impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */}
// NEW
impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */}
impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */}
```
---------
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: radiish <cb.setho@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
|
|
|
/// The `#[derive(Reflect)]` macro will automatically add any required bounds to `T`,
|
|
|
|
/// such as `Reflect` and `GetTypeRegistration`.
|
2020-11-28 00:39:59 +00:00
|
|
|
#[derive(Reflect)]
|
bevy_reflect: Recursive registration (#5781)
# Objective
Resolves #4154
Currently, registration must all be done manually:
```rust
#[derive(Reflect)]
struct Foo(Bar);
#[derive(Reflect)]
struct Bar(Baz);
#[derive(Reflect)]
struct Baz(usize);
fn main() {
// ...
app
.register_type::<Foo>()
.register_type::<Bar>()
.register_type::<Baz>()
// .register_type::<usize>() <- This one is handled by Bevy, thankfully
// ...
}
```
This can grow really quickly and become very annoying to add, remove,
and update as types change. It would be great if we could help reduce
the number of types that a user must manually implement themselves.
## Solution
As suggested in #4154, this PR adds automatic recursive registration.
Essentially, when a type is registered, it may now also choose to
register additional types along with it using the new
`GetTypeRegistration::register_type_dependencies` trait method.
The `Reflect` derive macro now automatically does this for all fields in
structs, tuple structs, struct variants, and tuple variants. This is
also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and
`Option<T>`.
This allows us to simplify the code above like:
```rust
#[derive(Reflect)]
struct Foo(Bar);
#[derive(Reflect)]
struct Bar(Baz);
#[derive(Reflect)]
struct Baz(usize);
fn main() {
// ...
app.register_type::<Foo>()
// ...
}
```
This automatic registration only occurs if the type has not yet been
registered. If it has been registered, we simply skip it and move to the
next one. This reduces the cost of registration and prevents overwriting
customized registrations.
## Considerations
While this does improve ergonomics on one front, it's important to look
at some of the arguments against adopting a PR like this.
#### Generic Bounds
~~Since we need to be able to register the fields individually, we need
those fields to implement `GetTypeRegistration`. This forces users to
then add this trait as a bound on their generic arguments. This
annoyance could be relieved with something like #5772.~~
This is no longer a major issue as the `Reflect` derive now adds the
`GetTypeRegistration` bound by default. This should technically be okay,
since we already add the `Reflect` bound.
However, this can also be considered a breaking change for manual
implementations that left out a `GetTypeRegistration` impl ~~or for
items that contain dynamic types (e.g. `DynamicStruct`) since those also
do not implement `GetTypeRegistration`~~.
#### Registration Assumptions
By automatically registering fields, users might inadvertently be
relying on certain types to be automatically registered. If `Foo`
auto-registers `Bar`, but `Foo` is later removed from the code, then
anywhere that previously used or relied on `Bar`'s registration would
now fail.
---
## Changelog
- Added recursive type registration to structs, tuple structs, struct
variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and
`Option<T>`
- Added a new trait in the hidden `bevy_reflect::__macro_exports` module
called `RegisterForReflection`
- Added `GetTypeRegistration` impl for
`bevy_render::render_asset::RenderAssetUsages`
## Migration Guide
All types that derive `Reflect` will now automatically add
`GetTypeRegistration` as a bound on all (unignored) fields. This means
that all reflected fields will need to also implement
`GetTypeRegistration`.
If all fields **derive** `Reflect` or are implemented in `bevy_reflect`,
this should not cause any issues. However, manual implementations of
`Reflect` that excluded a `GetTypeRegistration` impl for their type will
need to add one.
```rust
#[derive(Reflect)]
struct Foo<T: FromReflect> {
data: MyCustomType<T>
}
// OLD
impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */}
// NEW
impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */}
impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */}
```
---------
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: radiish <cb.setho@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
|
|
|
struct MyType<T> {
|
2020-11-28 00:39:59 +00:00
|
|
|
value: T,
|
|
|
|
}
|
|
|
|
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/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 https://github.com/bevyengine/bevy/issues/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>
2022-08-08 21:36:35 +00:00
|
|
|
fn setup(type_registry: Res<AppTypeRegistry>) {
|
2020-11-28 00:39:59 +00:00
|
|
|
let type_registry = type_registry.read();
|
|
|
|
|
|
|
|
let registration = type_registry.get(TypeId::of::<MyType<u32>>()).unwrap();
|
2023-10-09 19:33:03 +00:00
|
|
|
info!(
|
|
|
|
"Registration for {} exists",
|
|
|
|
registration.type_info().type_path(),
|
|
|
|
);
|
2020-11-28 00:39:59 +00:00
|
|
|
|
|
|
|
// MyType<String> was not manually registered, so it does not exist
|
|
|
|
assert!(type_registry.get(TypeId::of::<MyType<String>>()).is_none());
|
|
|
|
}
|