Followup to #7184
This makes `Reflect: DynamicTypePath` which allows us to remove
`Reflect::get_type_path`, reducing unnecessary codegen and simplifying
`Reflect` implementations.
# Objective
It was accidentally found that rustc is unable to parse certain
constructs in `where` clauses properly. `bevy_reflect::Reflect`'s habit
of copying and pasting the field types in a type's definition to its
`where` clauses made it very easy to accidentally run into this
behaviour - particularly with the construct
```rust
where
for<'a> fn(&'a T) -> &'a T: Trait1 + Trait2
```
which was incorrectly parsed as
```rust
where
for<'a> (fn(&'a T) -> &'a T: Trait1 + Trait2)
^ ^ incorrect syntax grouping
```
instead of
```rust
where
(for<'a> fn(&'a T) -> &'a T): Trait1 + Trait2
^ ^ correct syntax grouping
```
Fixes#8759
## Solution
This commit fixes the issue by inserting explicit parentheses to
disambiguate types from their bound lists.
# Objective
- Introduce a stable alternative to
[`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html).
- Rewrite of #5805 with heavy inspiration in design.
- On the path to #5830.
- Part of solving #3327.
## Solution
- Add a `TypePath` trait for static stable type path/name information.
- Add a `TypePath` derive macro.
- Add a `impl_type_path` macro for implementing internal and foreign
types in `bevy_reflect`.
---
## Changelog
- Added `TypePath` trait.
- Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`.
- Added a `TypePath` derive macro.
- Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on
internal and foreign types in `bevy_reflect`.
- Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to
`(Non)GenericTypedCell<T>` which allows us to be generic over both
`TypeInfo` and `TypePath`.
- `TypePath` is now a supertrait of `Asset`, `Material` and
`Material2d`.
- `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be
specified.
- `impl_reflect_value` needs to either specify path starting with a
double colon (`::core::option::Option`) or an `in my_crate::foo`
declaration.
- Added `bevy_reflect_derive::ReflectTypePath`.
- Most uses of `Ident` in `bevy_reflect_derive` changed to use
`ReflectTypePath`.
## Migration Guide
- Implementors of `Asset`, `Material` and `Material2d` now also need to
derive `TypePath`.
- Manual implementors of `Reflect` will need to implement the new
`get_type_path` method.
## Open Questions
- [x] ~This PR currently does not migrate any usages of
`std::any::type_name` to use `bevy_reflect::TypePath` to ease the review
process. Should it?~ Migration will be left to a follow-up PR.
- [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to
satisfy new bounds, mostly when deriving `TypeUuid`. Should we make
`TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in
favour of
`TypePath`?](2afbd85532 (r961067892))
# Objective
Fixes#8596
## Solution
Change interface of the trait Map. Adjust implementations of this trait
---
## Changelog
### Changed
- Interface of Map trait
### Added
- `Map::get_at_mut`
## Migration Guide
Every implementor of Map trait would need to implement `get_at_mut`.
Which, judging by changes in this PR, should be fairly trivial.
# Objective
Right now it's impossible to construct a MapIter outside of the
bevy_reflect crate, making it impossible to implement the Map trait for
custom map types.
## Solution
Addition of a pub constructor to MapIter.
# Objective
When using `FromReflect`, fields can be optionally left out if they are
marked with `#[reflect(default)]`. This is very handy for working with
serialized data as giant structs only need to list a subset of defined
fields in order to be constructed.
<details>
<summary>Example</summary>
Take the following struct:
```rust
#[derive(Reflect, FromReflect)]
struct Foo {
#[reflect(default)]
a: usize,
#[reflect(default)]
b: usize,
#[reflect(default)]
c: usize,
#[reflect(default)]
d: usize,
}
```
Since all the fields are default-able, we can successfully call
`FromReflect` on deserialized data like:
```rust
(
"foo::Foo": (
// Only set `b` and default the rest
b: 123
)
)
```
</details>
Unfortunately, this does not work with fields in enum variants. Marking
a variant field as `#[reflect(default)]` does nothing when calling
`FromReflect`.
## Solution
Allow enum variant fields to define a default value using
`#[reflect(default)]`.
### `#[reflect(Default)]`
One thing that structs and tuple structs can do is use their `Default`
implementation when calling `FromReflect`. Adding `#[reflect(Default)]`
to the struct or tuple struct both registers `ReflectDefault` and alters
the `FromReflect` implementation to use `Default` to generate any
missing fields.
This works well enough for structs and tuple structs, but for enums it's
not as simple. Since the `Default` implementation for an enum only
covers a single variant, it's not as intuitive as to what the behavior
will be. And (imo) it feels weird that we would be able to specify
default values in this way for one variant but not the others.
Because of this, I chose to not implement that behavior here. However,
I'm open to adding it in if anyone feels otherwise.
---
## Changelog
- Allow enum variant fields to define a default value using
`#[reflect(default)]`
# Objective
- Add Reflect and FromReflect for AssetPath
- Fixes#8458
## Solution
- Straightforward derive of `Reflect` and `FromReflect` for `AssetPath`
- Implement `Reflect` and `FromReflect` for `Cow<'static, Path>` as to
satisfy the 'static lifetime requierments of bevy_reflect.
Implementation is a direct copy of that for `Cow<'static, str>` so maybe
it begs the question that was already asked in #7429 - maybe it would be
benefitial to write a general implementation for `Reflect` for
`Cow<'static, T>`.
# Objective
> This PR is based on discussion from #6601
The Dynamic types (e.g. `DynamicStruct`, `DynamicList`, etc.) act as
both:
1. Dynamic containers which may hold any arbitrary data
2. Proxy types which may represent any other type
Currently, the only way we can represent the proxy-ness of a Dynamic is
by giving it a name.
```rust
// This is just a dynamic container
let mut data = DynamicStruct::default();
// This is a "proxy"
data.set_name(std::any::type_name::<Foo>());
```
This type name is the only way we check that the given Dynamic is a
proxy of some other type. When we need to "assert the type" of a `dyn
Reflect`, we call `Reflect::type_name` on it. However, because we're
only using a string to denote the type, we run into a few gotchas and
limitations.
For example, hashing a Dynamic proxy may work differently than the type
it proxies:
```rust
#[derive(Reflect, Hash)]
#[reflect(Hash)]
struct Foo(i32);
let concrete = Foo(123);
let dynamic = concrete.clone_dynamic();
let concrete_hash = concrete.reflect_hash();
let dynamic_hash = dynamic.reflect_hash();
// The hashes are not equal because `concrete` uses its own `Hash` impl
// while `dynamic` uses a reflection-based hashing algorithm
assert_ne!(concrete_hash, dynamic_hash);
```
Because the Dynamic proxy only knows about the name of the type, it's
unaware of any other information about it. This means it also differs on
`Reflect::reflect_partial_eq`, and may include ignored or skipped fields
in places the concrete type wouldn't.
## Solution
Rather than having Dynamics pass along just the type name of proxied
types, we can instead have them pass around the `TypeInfo`.
Now all Dynamic types contain an `Option<&'static TypeInfo>` rather than
a `String`:
```diff
pub struct DynamicTupleStruct {
- type_name: String,
+ represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn Reflect>>,
}
```
By changing `Reflect::get_type_info` to
`Reflect::represented_type_info`, hopefully we make this behavior a
little clearer. And to account for `None` values on these dynamic types,
`Reflect::represented_type_info` now returns `Option<&'static
TypeInfo>`.
```rust
let mut data = DynamicTupleStruct::default();
// Not proxying any specific type
assert!(dyn_tuple_struct.represented_type_info().is_none());
let type_info = <Foo as Typed>::type_info();
dyn_tuple_struct.set_represented_type(Some(type_info));
// Alternatively:
// let dyn_tuple_struct = foo.clone_dynamic();
// Now we're proxying `Foo`
assert!(dyn_tuple_struct.represented_type_info().is_some());
```
This means that we can have full access to all the static type
information for the proxied type. Future work would include
transitioning more static type information (trait impls, attributes,
etc.) over to the `TypeInfo` so it can actually be utilized by Dynamic
proxies.
### Alternatives & Rationale
> **Note**
> These alternatives were written when this PR was first made using a
`Proxy` trait. This trait has since been removed.
<details>
<summary>View</summary>
#### Alternative: The `Proxy<T>` Approach
I had considered adding something like a `Proxy<T>` type where `T` would
be the Dynamic and would contain the proxied type information.
This was nice in that it allows us to explicitly determine whether
something is a proxy or not at a type level. `Proxy<DynamicStruct>`
proxies a struct. Makes sense.
The reason I didn't go with this approach is because (1) tuples, (2)
complexity, and (3) `PartialReflect`.
The `DynamicTuple` struct allows us to represent tuples at runtime. It
also allows us to do something you normally can't with tuples: add new
fields. Because of this, adding a field immediately invalidates the
proxy (e.g. our info for `(i32, i32)` doesn't apply to `(i32, i32,
NewField)`). By going with this PR's approach, we can just remove the
type info on `DynamicTuple` when that happens. However, with the
`Proxy<T>` approach, it becomes difficult to represent this behavior—
we'd have to completely control how we access data for `T` for each `T`.
Secondly, it introduces some added complexities (aside from the manual
impls for each `T`). Does `Proxy<T>` impl `Reflect`? Likely yes, if we
want to represent it as `dyn Reflect`. What `TypeInfo` do we give it?
How would we forward reflection methods to the inner type (remember, we
don't have specialization)? How do we separate this from Dynamic types?
And finally, how do all this in a way that's both logical and intuitive
for users?
Lastly, introducing a `Proxy` trait rather than a `Proxy<T>` struct is
actually more inline with the [Unique Reflect
RFC](https://github.com/bevyengine/rfcs/pull/56). In a way, the `Proxy`
trait is really one part of the `PartialReflect` trait introduced in
that RFC (it's technically not in that RFC but it fits well with it),
where the `PartialReflect` serves as a way for proxies to work _like_
concrete types without having full access to everything a concrete
`Reflect` type can do. This would help bridge the gap between the
current state of the crate and the implementation of that RFC.
All that said, this is still a viable solution. If the community
believes this is the better path forward, then we can do that instead.
These were just my reasons for not initially going with it in this PR.
#### Alternative: The Type Registry Approach
The `Proxy` trait is great and all, but how does it solve the original
problem? Well, it doesn't— yet!
The goal would be to start moving information from the derive macro and
its attributes to the generated `TypeInfo` since these are known
statically and shouldn't change. For example, adding `ignored: bool` to
`[Un]NamedField` or a list of impls.
However, there is another way of storing this information. This is, of
course, one of the uses of the `TypeRegistry`. If we're worried about
Dynamic proxies not aligning with their concrete counterparts, we could
move more type information to the registry and require its usage.
For example, we could replace `Reflect::reflect_hash(&self)` with
`Reflect::reflect_hash(&self, registry: &TypeRegistry)`.
That's not the _worst_ thing in the world, but it is an ergonomics loss.
Additionally, other attributes may have their own requirements, further
restricting what's possible without the registry. The `Reflect::apply`
method will require the registry as well now. Why? Well because the
`map_apply` function used for the `Reflect::apply` impls on `Map` types
depends on `Map::insert_boxed`, which (at least for `DynamicMap`)
requires `Reflect::reflect_hash`. The same would apply when adding
support for reflection-based diffing, which will require
`Reflect::reflect_partial_eq`.
Again, this is a totally viable alternative. I just chose not to go with
it for the reasons above. If we want to go with it, then we can close
this PR and we can pursue this alternative instead.
#### Downsides
Just to highlight a quick potential downside (likely needs more
investigation): retrieving the `TypeInfo` requires acquiring a lock on
the `GenericTypeInfoCell` used by the `Typed` impls for generic types
(non-generic types use a `OnceBox which should be faster). I am not sure
how much of a performance hit that is and will need to run some
benchmarks to compare against.
</details>
### Open Questions
1. Should we use `Cow<'static, TypeInfo>` instead? I think that might be
easier for modding? Perhaps, in that case, we need to update
`Typed::type_info` and friends as well?
2. Are the alternatives better than the approach this PR takes? Are
there other alternatives?
---
## Changelog
### Changed
- `Reflect::get_type_info` has been renamed to
`Reflect::represented_type_info`
- This method now returns `Option<&'static TypeInfo>` rather than just
`&'static TypeInfo`
### Added
- Added `Reflect::is_dynamic` method to indicate when a type is dynamic
- Added a `set_represented_type` method on all dynamic types
### Removed
- Removed `TypeInfo::Dynamic` (use `Reflect::is_dynamic` instead)
- Removed `Typed` impls for all dynamic types
## Migration Guide
- The Dynamic types no longer take a string type name. Instead, they
require a static reference to `TypeInfo`:
```rust
#[derive(Reflect)]
struct MyTupleStruct(f32, f32);
let mut dyn_tuple_struct = DynamicTupleStruct::default();
dyn_tuple_struct.insert(1.23_f32);
dyn_tuple_struct.insert(3.21_f32);
// BEFORE:
let type_name = std::any::type_name::<MyTupleStruct>();
dyn_tuple_struct.set_name(type_name);
// AFTER:
let type_info = <MyTupleStruct as Typed>::type_info();
dyn_tuple_struct.set_represented_type(Some(type_info));
```
- `Reflect::get_type_info` has been renamed to
`Reflect::represented_type_info` and now also returns an
`Option<&'static TypeInfo>` (instead of just `&'static TypeInfo`):
```rust
// BEFORE:
let info: &'static TypeInfo = value.get_type_info();
// AFTER:
let info: &'static TypeInfo = value.represented_type_info().unwrap();
```
- `TypeInfo::Dynamic` and `DynamicInfo` has been removed. Use
`Reflect::is_dynamic` instead:
```rust
// BEFORE:
if matches!(value.get_type_info(), TypeInfo::Dynamic) {
// ...
}
// AFTER:
if value.is_dynamic() {
// ...
}
```
---------
Co-authored-by: radiish <cb.setho@gmail.com>
# Objective
Considering that `FromReflect` is a very common trait to derive, it
would make sense to include `ReflectFromReflect` in the `bevy_reflect`
prelude so users don't need to import it separately.
## Solution
Add `ReflectFromReflect` to the prelude.
Links in the api docs are nice. I noticed that there were several places
where structs / functions and other things were referenced in the docs,
but weren't linked. I added the links where possible / logical.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François <mockersf@gmail.com>
# Objective
- Fix the issue described in #8183: Box<dyn Reflect> structs with a
hashmap in them will panic when clone_value is called on it
- Fixes: #8183
## Solution
- Updates the implementation of Reflect for Hashmaps to make clone_value
call from_reflect on the key before inserting it into the new struct
Fixes issue mentioned in PR #8285.
_Note: By mistake, this is currently dependent on #8285_
# Objective
Ensure consistency in the spelling of the documentation.
Exceptions:
`crates/bevy_mikktspace/src/generated.rs` - Has not been changed from
licence to license as it is part of a licensing agreement.
Maybe for further consistency,
https://github.com/bevyengine/bevy-website should also be given a look.
## Solution
### Changed the spelling of the current words (UK/CN/AU -> US) :
cancelled -> canceled (Breaking API changes in #8285)
behaviour -> behavior (Breaking API changes in #8285)
neighbour -> neighbor
grey -> gray
recognise -> recognize
centre -> center
metres -> meters
colour -> color
### ~~Update [`engine_style_guide.md`]~~ Moved to #8324
---
## Changelog
Changed UK spellings in documentation to US
## Migration Guide
Non-breaking changes*
\* If merged after #8285
# Objective
The clippy lint `type_complexity` is known not to play well with bevy.
It frequently triggers when writing complex queries, and taking the
lint's advice of using a type alias almost always just obfuscates the
code with no benefit. Because of this, this lint is currently ignored in
CI, but unfortunately it still shows up when viewing bevy code in an
IDE.
As someone who's made a fair amount of pull requests to this repo, I
will say that this issue has been a consistent thorn in my side. Since
bevy code is filled with spurious, ignorable warnings, it can be very
difficult to spot the *real* warnings that must be fixed -- most of the
time I just ignore all warnings, only to later find out that one of them
was real after I'm done when CI runs.
## Solution
Suppress this lint in all bevy crates. This was previously attempted in
#7050, but the review process ended up making it more complicated than
it needs to be and landed on a subpar solution.
The discussion in https://github.com/rust-lang/rust-clippy/pull/10571
explores some better long-term solutions to this problem. Since there is
no timeline on when these solutions may land, we should resolve this
issue in the meantime by locally suppressing these lints.
### Unresolved issues
Currently, these lints are not suppressed in our examples, since that
would require suppressing the lint in every single source file. They are
still ignored in CI.
# Objective
Fix typo in bevy_reflect README: `MyType` is a struct and not a trait,
so `&dyn MyType` is incorrect.
## Solution
Replace `&dyn MyType` with `&dyn DoThing`
# Objective
Fixes#7989
Based on #7991 by @CoffeeVampir3
## Solution
There were three parts to this issue:
1. `extend_where_clause` did not account for the optionality of a where
clause's trailing comma
```rust
// OKAY
struct Foo<T> where T: Asset, {/* ... */}
// ERROR
struct Foo<T> where T: Asset {/* ... */}
```
2. `FromReflect` derive logic was not actively using
`extend_where_clause` which led to some inconsistencies (enums weren't
adding _any_ additional bounds even)
3. Using `extend_where_clause` in the `FromReflect` derive logic meant
we had to optionally add `Default` bounds to ignored fields iff the
entire item itself was not already `Default` (otherwise the definition
for `Handle<T>` wouldn't compile since `HandleType` doesn't impl
`Default` but `Handle<T>` itself does)
---
## Changelog
- Fixed issue where a missing trailing comma could break the reflection
derives
# Objective
- Update `glam` to the latest version.
## Solution
- Update `glam` to version `0.23`.
Since the breaking change in `glam` only affects the `scalar-math` feature, this should cause no issues.
# Objective
Implement `Reflect` for `std::collections::HashMap<K, V, S>` as well as `hashbrown::HashMap<K, V, S>` rather than just for `hashbrown::HashMap<K, V, RandomState>`. Fixes#7739.
## Solution
Rather than implementing on `HashMap<K, V>` I instead implemented most of the related traits on `HashMap<K, V, S> where S: BuildHasher + Send + Sync + 'static` and then `FromReflect` also needs the extra bound `S: Default` because it needs to use `with_capacity_and_hasher` so needs to be able to generate a default hasher.
As the API of `hashbrown::HashMap` is identical to `collections::HashMap` making them both work just required creating an `impl_reflect_for_hashmap` macro like the `impl_reflect_for_veclike` above and then applying this to both HashMaps.
---
## Changelog
`std::collections::HashMap` can now be reflected. Also more `State` generics than just `RandomState` can now be reflected for both `hashbrown::HashMap` and `collections::HashMap`
# Objective
There were a couple primitive types missing from the default `TypeRegistry` constructor.
## Solution
Added the missing registrations for `char` and `String`.
# Objective
`cargo run -p ci` is currently failing locally for me.
```
error: variables can be used directly in the `format!` string
--> crates/bevy_reflect/bevy_reflect_derive/src/type_uuid.rs:106:69
|
106 | let uuid = Uuid::parse_str(&uuid).map_err(|err| input.error(format!("{}", err)))?;
```
It's not clear to me why CI/clippy didn't pick this up in #6633.
# Objective
`bevy_reflect` can be a moderately complex crate to try and understand. It has many moving parts, a handful of gotchas, and a few subtle contracts that aren't immediately obvious to users and even other contributors.
The current README does an okay job demonstrating how the crate can be used. However, the crate's actual documentation should give a better overview of the crate, its inner-workings, and show some of its own examples.
## Solution
Added crate-level documentation that attempts to summarize the main parts of `bevy_reflect` into small sections.
This PR also updates the documentation for:
- `Reflect`
- `FromReflect`
- The reflection subtraits
- Other important types and traits
- The reflection macros (including the derive macros)
- Crate features
### Open Questions
1. ~~Should I update the docs for the Dynamic types? I was originally going to, but I'm getting a little concerned about the size of this PR 😅~~ Decided to not do this in this PR. It'll be better served from its own PR.
2. Should derive macro documentation be moved to the trait itself? This could improve visibility and allow for better doc links, but could also clutter up the trait's documentation (as well as not being on the actual derive macro's documentation).
### TODO
- [ ] ~~Document Dynamic types (?)~~ I think this should be done in a separate PR.
- [x] Document crate features
- [x] Update docs for `GetTypeRegistration`
- [x] Update docs for `TypeRegistration`
- [x] Update docs for `derive_from_reflect`
- [x] Document `reflect_trait`
- [x] Document `impl_reflect_value`
- [x] Document `impl_from_reflect_value`
---
## Changelog
- Updated documentation across the `bevy_reflect` crate
- Removed `#[module]` helper attribute for `Reflect` derives (this is not currently used)
## Migration Guide
- Removed `#[module]` helper attribute for `Reflect` derives. If your code is relying on this attribute, please replace it with either `#[reflect]` or `#[reflect_value]` (dependent on use-case).
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- bevy_ggrs uses `reflect_hash` in order to produce checksums for its world snapshots. These checksums are sent between clients in order to detect desyncronization.
- However, since we currently use `async::AHasher` with the `std` feature, this means that hashes will always be different for different peers, even if the state is identical.
- This means bevy_ggrs needs a way to get a deterministic (fixed) hash.
## Solution
- ~~Add a feature to use `bevy_utils::FixedState` for the hasher used by bevy_reflect.~~
- Always use `bevy_utils::FixedState` for initializing the bevy_reflect hasher.
---
## Changelog
- bevy_reflect now uses a fixed state for its hasher, which means the output of `Reflect::reflect_hash` is now deterministic across processes.
# Objective
- Fixes#5432
- Fixes#6680
## Solution
- move code responsible for generating the `impl TypeUuid` from `type_uuid_derive` into a new function, `gen_impl_type_uuid`.
- this allows the new proc macro, `impl_type_uuid`, to call the code for generation.
- added struct `TypeUuidDef` and implemented `syn::Parse` to allow parsing of the input for the new macro.
- finally, used the new macro `impl_type_uuid` to implement `TypeUuid` for the standard library (in `crates/bevy_reflect/src/type_uuid_impl.rs`).
- fixes#6680 by doing a wrapping add of the param's index to its `TYPE_UUID`
Co-authored-by: dis-da-moe <84386186+dis-da-moe@users.noreply.github.com>
# Objective
Resolves#7121
## Solution
Decouples `List` and `Array` by removing `Array` as a supertrait of `List`. Additionally, similar methods from `Array` have been added to `List` so that their usages can remain largely unchanged.
#### Possible Alternatives
##### `Sequence`
My guess for why we originally made `List` a subtrait of `Array` is that they share a lot of common operations. We could potentially move these overlapping methods to a `Sequence` (name taken from #7059) trait and make that a supertrait of both. This would allow functions to contain logic that simply operates on a sequence rather than "list vs array".
However, this means that we'd need to add methods for converting to a `dyn Sequence`. It also might be confusing since we wouldn't add a `ReflectRef::Sequence` or anything like that. Is such a trait worth adding (either in this PR or a followup one)?
---
## Changelog
- Removed `Array` as supertrait of `List`
- Added methods to `List` that were previously provided by `Array`
## Migration Guide
The `List` trait is no longer dependent on `Array`. Implementors of `List` can remove the `Array` impl and move its methods into the `List` impl (with only a couple tweaks).
```rust
// BEFORE
impl Array for Foo {
fn get(&self, index: usize) -> Option<&dyn Reflect> {/* ... */}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {/* ... */}
fn len(&self) -> usize {/* ... */}
fn is_empty(&self) -> bool {/* ... */}
fn iter(&self) -> ArrayIter {/* ... */}
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {/* ... */}
fn clone_dynamic(&self) -> DynamicArray {/* ... */}
}
impl List for Foo {
fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {/* ... */}
fn remove(&mut self, index: usize) -> Box<dyn Reflect> {/* ... */}
fn push(&mut self, value: Box<dyn Reflect>) {/* ... */}
fn pop(&mut self) -> Option<Box<dyn Reflect>> {/* ... */}
fn clone_dynamic(&self) -> DynamicList {/* ... */}
}
// AFTER
impl List for Foo {
fn get(&self, index: usize) -> Option<&dyn Reflect> {/* ... */}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {/* ... */}
fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {/* ... */}
fn remove(&mut self, index: usize) -> Box<dyn Reflect> {/* ... */}
fn push(&mut self, value: Box<dyn Reflect>) {/* ... */}
fn pop(&mut self) -> Option<Box<dyn Reflect>> {/* ... */}
fn len(&self) -> usize {/* ... */}
fn is_empty(&self) -> bool {/* ... */}
fn iter(&self) -> ListIter {/* ... */}
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {/* ... */}
fn clone_dynamic(&self) -> DynamicList {/* ... */}
}
```
Some other small tweaks that will need to be made include:
- Use `ListIter` for `List::iter` instead of `ArrayIter` (the return type from `Array::iter`)
- Replace `array_hash` with `list_hash` in `Reflect::reflect_hash` for implementors of `List`
# Objective
Currently the `GetPath` documentation suggests it can be used with `Tuple` types (reflected tuples). However, this is not currently the case.
## Solution
Add reflection path support for `Tuple` types.
---
## Changelog
- Add reflection path support for `Tuple` types
Implementing GetTypeRegistration in macro impl_reflect_for_veclike! had typos!
It only implement GetTypeRegistration for Vec<T>, but not for VecDeque<T>.
This will cause serialization and deserialization failure.
# Objective
- Fixes#7430.
## Solution
- Changed fields of `ArrayIter` to be private.
- Add a constructor `new` to `ArrayIter`.
- Replace normal struct creation with `new`.
---
## Changelog
- Add a constructor `new` to `ArrayIter`.
Co-authored-by: Elbert Ronnie <103196773+elbertronnie@users.noreply.github.com>
# Objective
I recently had an issue, where I have a struct:
```
struct Property {
inner: T
}
```
that I use as a wrapper for internal purposes.
I don't want to update my struct definition to
```
struct Property<T: Reflect>{
inner: T
}
```
because I still want to be able to build `Property<T>` for types `T` that are not `Reflect`. (and also because I don't want to update my whole code base with `<T: Reflect>` bounds)
I still wanted to have reflection on it (for `bevy_inspector_egui`), but adding `derive(Reflect)` fails with the error:
`T cannot be sent between threads safely. T needs to implement Sync.`
I believe that `bevy_reflect` should adopt the model of other derives in the case of generics, which is to add the `Reflect` implementation only if the generics also implement `Reflect`. (That is the behaviour of other macros such as `derive(Clone)` or `derive(Debug)`.
It's also the current behavior of `derive(FromReflect)`.
Basically doing something like:
```
impl<T> Reflect for Foo<T>
where T: Reflect
```
## Solution
- I updated the derive macros for `Structs` and `TupleStructs` to add extra `where` bounds.
- Every type that is reflected will need a `T: Reflect` bound
- Ignored types will need a `T: 'static + Send + Sync` bound. Here's the reason. For cases like this:
```
#[derive(Reflect)]
struct Foo<T, U>{
a: T
#[reflect(ignore)]
b: U
}
```
I had to add the bound `'static + Send + Sync` to ignored generics like `U`.
The reason is that we want `Foo<T, U>` to be `Reflect: 'static + Send + Sync`, so `Foo<T, U>` must be able to implement those auto-traits. `Foo<T, U>` will only implement those auto-traits if every generic type implements them, including ignored types.
This means that the previously compile-fail case now compiles:
```
#[derive(Reflect)]
struct Foo<'a> {
#[reflect(ignore)]
value: &'a str,
}
```
But `Foo<'a>` will only be useable in the cases where `'a: 'static` and panic if we don't have `'a: 'static`, which is what we want (nice bonus from this PR ;) )
---
## Changelog
> This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section.
### Added
Possibility to add `derive(Reflect)` to structs and enums that contain generic types, like so:
```
#[derive(Reflect)]
struct Foo<T>{
a: T
}
```
Reflection will only be available if the generic type T also implements `Reflect`.
(previously, this would just return a compiler error)
# Objective
I found several words in code and docs are incorrect. This should be fixed.
## Solution
- Fix several minor typos
Co-authored-by: Chris Ohk <utilforever@gmail.com>
# Objective
> ℹ️ **This is an adoption of #4081 by @james7132**
Fixes#4080.
Provide a way to pre-parse reflection paths so as to avoid having to parse at each call to `GetPath::path` (or similar method).
## Solution
Adds the `ParsedPath` struct (named `FieldPath` in the original PR) that parses and caches the sequence of accesses to a reflected element. This is functionally similar to the `GetPath` trait, but removes the need to parse an unchanged path more than once.
### Additional Changes
Included in this PR from the original is cleaner code as well as the introduction of a new pathing operation: field access by index. This allows struct and struct variant fields to be accessed in a more performant (albeit more fragile) way if needed. This operation is faster due to not having to perform string matching. As an example, if we wanted the third field on a struct, we'd write `#2`—where `#` denotes indexed access and `2` denotes the desired field index.
This PR also contains improved documentation for `GetPath` and friends, including renaming some of the methods to be more clear to the end-user with a reduced risk of getting them mixed up.
### Future Work
There are a few things that could be done as a separate PR (order doesn't matter— they could be followup PRs or done in parallel). These are:
- [x] ~~Add support for `Tuple`. Currently, we hint that they work but they do not.~~ See #7324
- [ ] Cleanup `ReflectPathError`. I think it would be nicer to give `ReflectPathError` two variants: `ReflectPathError::ParseError` and `ReflectPathError::AccessError`, with all current variants placed within one of those two. It's not obvious when one might expect to receive one type of error over the other, so we can help by explicitly categorizing them.
---
## Changelog
- Cleaned up `GetPath` logic
- Added `ParsedPath` for cached reflection paths
- Added new reflection path syntax: struct field access by index (example syntax: `foo#1`)
- Renamed methods on `GetPath`:
- `path` -> `reflect_path`
- `path_mut` -> `reflect_path_mut`
- `get_path` -> `path`
- `get_path_mut` -> `path_mut`
## Migration Guide
`GetPath` methods have been renamed according to the following:
- `path` -> `reflect_path`
- `path_mut` -> `reflect_path_mut`
- `get_path` -> `path`
- `get_path_mut` -> `path_mut`
Co-authored-by: Gino Valente <gino.valente.code@gmail.com>
# Objective
Enums are now reflectable, but are not accessible via reflection paths.
This would allow us to do things like:
```rust
#[derive(Reflect)]
struct MyStruct {
data: MyEnum
}
#[derive(Reflect)]
struct MyEnum {
Foo(u32, u32),
Bar(bool)
}
let x = MyStruct {
data: MyEnum::Foo(123),
};
assert_eq!(*x.get_path::<u32>("data.1").unwrap(), 123);
```
## Solution
Added support for enums in reflection paths.
##### Note
This uses a simple approach of just getting the field with the given accessor. It does not do matching or anything else to ensure the enum is the intended variant. This means that the variant must be known ahead of time or matched outside the reflection path (i.e. path to variant, perform manual match, and continue pathing).
---
## Changelog
- Added support for enums in reflection paths
# Objective
There are times where we want to simply take an owned `dyn Reflect` and cast it to a type `T`.
Currently, this involves doing:
```rust
let value = value.take::<T>().unwrap_or_else(|value| {
T::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"expected value of type {} to convert to type {}.",
value.type_name(),
std::any::type_name::<T>()
)
})
});
```
This is a common operation that could be easily be simplified.
## Solution
Add the `FromReflect::take_from_reflect` method. This first tries to `take` the value, calling `from_reflect` iff that fails.
```rust
let value = T::take_from_reflect(value).unwrap_or_else(|value| {
panic!(
"expected value of type {} to convert to type {}.",
value.type_name(),
std::any::type_name::<T>()
)
});
```
Based on suggestion from @soqb on [Discord](https://discord.com/channels/691052431525675048/1002362493634629796/1041046880316043374).
---
## Changelog
- Add `FromReflect::take_from_reflect` method
# Objective
This a follow-up to #6894, see https://github.com/bevyengine/bevy/pull/6894#discussion_r1045203113
The goal is to avoid cloning any string when getting a `&TypeRegistration` corresponding to a string which is being deserialized. As a bonus code duplication is also reduced.
## Solution
The manual deserialization of a string and lookup into the type registry has been moved into a separate `TypeRegistrationDeserializer` type, which implements `DeserializeSeed` with a `Visitor` that accepts any string with `visit_str`, even ones that may not live longer than that function call.
`BorrowedStr` has been removed since it's no longer used.
---
## Changelog
- The type `TypeRegistrationDeserializer` has been added, which simplifies getting a `&TypeRegistration` while deserializing a string.
# Objective
- Fixes#7061
## Solution
- Add and implement `insert` and `remove` methods for `List`.
---
## Changelog
- Added `insert` and `remove` methods to `List`.
- Changed the `push` and `pop` methods on `List` to have default implementations.
## Migration Guide
- Manual implementors of `List` need to implement the new methods `insert` and `remove` and
consider whether to use the new default implementation of `push` and `pop`.
Co-authored-by: radiish <thesethskigamer@gmail.com>
# Objective
Fixes#6891
## Solution
Replaces deserializing map keys as `&str` with deserializing them as `String`.
This bug seems to occur when using something like `File` or `BufReader` rather than bytes or a string directly (I only tested `File` and `BufReader` for `rmp-serde` and `serde_json`). This might be an issue with other `Read` impls as well (except `&[u8]` it seems).
We already had passing tests for Message Pack but none that use a `File` or `BufReader`. This PR also adds or modifies tests to check for this in the future.
This change was also based on [feedback](https://github.com/bevyengine/bevy/pull/4561#discussion_r957385136) I received in a previous PR.
---
## Changelog
- Fix bug where scene deserialization using certain readers could fail (e.g. `BufReader`, `File`, etc.)
# Objective
This is an adoption of #5792. Fixes#5791.
## Solution
Implemented all the required reflection traits for `VecDeque`, taking from `Vec`'s impls.
---
## Changelog
Added: `std::collections::VecDeque` now implements `Reflect` and all relevant traits.
Co-authored-by: james7132 <contact@jamessliu.com>
# Objective
Resolves#4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed#4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
Fixes#6866.
## Solution
Docs now should describe what the _front_, _first_, _back_, and _last_ elements are for an implementor of the `bevy::reflect::list::List` Trait. Further, the docs should describe how `bevy::reflect::list::List::push` and `bevy::reflect::list::List::pop` should act on these elements.
Co-authored-by: Linus Käll <linus.kall.business@gmail.com>
# Objective
- Fixes#3004
## Solution
- Replaced all the types with their fully quallified names
- Replaced all trait methods and inherent methods on dyn traits with their fully qualified names
- Made a new file `fq_std.rs` that contains structs corresponding to commonly used Structs and Traits from `std`. These structs are replaced by their respective fully qualified names when used inside `quote!`
# Objective
> Followup to [this](https://github.com/bevyengine/bevy/pull/6755#discussion_r1032671178) comment
Rearrange the impls in the `impls/std.rs` file.
The issue was that I had accidentally misplaced the impl for `Option<T>` and put it between the `Cow<'static, str>` impls. This is just a slight annoyance and readability issue.
## Solution
Move the `Option<T>` and `&'static Path` impls around to be more readable.
# Objective
Fixes#6739
## Solution
Implement the required traits. They cannot be implemented for `Path` directly, since it is a dynamically-sized type.
# Objective
> Part of #6573
When serializing a `DynamicScene` we end up treating almost all non-value types as though their type data doesn't exist. This is because when creating the `DynamicScene` we call `Reflect::clone_value` on the components, which generates a Dynamic type for all non-value types.
What this means is that the `glam` types are treated as though their `ReflectSerialize` registrations don't exist. However, the deserializer _does_ pick up the registration and attempts to use that instead. This results in the deserializer trying to operate on "malformed" data, causing this error:
```
WARN bevy_asset::asset_server: encountered an error while loading an asset: Expected float
```
## Solution
Ideally, we should better handle the serialization of possibly-Dynamic types. However, this runs into issues where the `ReflectSerialize` expects the concrete type and not a Dynamic representation, resulting in a panic:
0aa4147af6/crates/bevy_reflect/src/type_registry.rs (L402-L413)
Since glam types are so heavily used in Bevy (specifically in `Transform` and `GlobalTransform`), it makes sense to just a quick fix in that enables them to be used properly in scenes while a proper solution is found.
This PR simply removes all `ReflectSerialize` and `ReflectDeserialize` registrations from the glam types that are reflected as structs.
---
## Changelog
- Remove `ReflectSerialize` and `ReflectDeserialize` registrations from most glam types
## Migration Guide
This PR removes `ReflectSerialize` and `ReflectDeserialize` registrations from most glam types. This means any code relying on either of those type data existing for those glam types will need to not do that.
This also means that some serialized glam types will need to be updated. For example, here is `Affine3A`:
```rust
// BEFORE
(
"glam::f32::affine3a::Affine3A": (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0),
// AFTER
"glam::f32::affine3a::Affine3A": (
matrix3: (
x_axis: (
x: 1.0,
y: 0.0,
z: 0.0,
),
y_axis: (
x: 0.0,
y: 1.0,
z: 0.0,
),
z_axis: (
x: 0.0,
y: 0.0,
z: 1.0,
),
),
translation: (
x: 0.0,
y: 0.0,
z: 0.0,
),
)
)
```
# Objective
Fixes#6713
Binary deserialization is failing for unit structs as well as structs with all ignored/skipped fields.
## Solution
Add a check for the number of possible fields in a struct before deserializing. If empty, don't attempt to deserialize any fields (as there will be none).
Note: ~~This does not apply to enums as they do not properly handle skipped fields (see #6721).~~ Enums still do not properly handle skipped fields, but I decided to include the logic for it anyways to account for `#[reflect(ignore)]`'d fields in the meantime.
---
## Changelog
- Fix bug where deserializing unit structs would fail for non-self-describing formats
# Objective
Currently, `Ptr` and `PtrMut` can only be constructed via unsafe code. This means that downgrading a reference to an untyped pointer is very cumbersome, despite being a very simple operation.
## Solution
Define conversions for easily and safely constructing untyped pointers. This is the non-owned counterpart to `OwningPtr::make`.
Before:
```rust
let ptr = unsafe { PtrMut::new(NonNull::from(&mut value).cast()) };
```
After:
```rust
let ptr = PtrMut::from(&mut value);
```
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- Implements removal of entries from a `dyn Map`
- Fixes#6563
## Solution
- Adds a `remove` method to the `Map` trait which takes in a `&dyn Reflect` key and returns the value removed if it was present.
---
## Changelog
- Added `Map::remove`
## Migration Guide
- Implementors of `Map` will need to implement the `remove` method.
Co-authored-by: radiish <thesethskigamer@gmail.com>
# Objective
Using `Reflect` we can easily switch between a specific reflection trait object, such as a `dyn Struct`, to a `dyn Reflect` object via `Reflect::as_reflect` or `Reflect::as_reflect_mut`.
```rust
fn do_something(value: &dyn Reflect) {/* ... */}
let foo: Box<dyn Struct> = Box::new(Foo::default());
do_something(foo.as_reflect());
```
However, there is no way to convert a _boxed_ reflection trait object to a `Box<dyn Reflect>`.
## Solution
Add a `Reflect::into_reflect` method which allows converting a boxed reflection trait object back into a boxed `Reflect` trait object.
```rust
fn do_something(value: Box<dyn Reflect>) {/* ... */}
let foo: Box<dyn Struct> = Box::new(Foo::default());
do_something(foo.into_reflect());
```
---
## Changelog
- Added `Reflect::into_reflect`
# Objective
There is no way to gen an owned value of `Reflect`.
## Solution
Add it! This was originally a part of #6421, but @MrGVSV asked me to create a separate for it to implement reflect diffing.
---
## Changelog
### Added
- `Reflect::reflect_owned` to get an owned version of `Reflect`.
# Objective
- adding a new `.register` should not overwrite old type data
- separate crates should both be able to register the same type
I ran into this while debugging why `register::<Handle<T>>` removed the `ReflectHandle` type data from a prior `register_asset_reflect`.
## Solution
- make `register` do nothing if called again for the same type
- I also removed some unnecessary duplicate registrations
# Objective
Closes#5934
Currently it is not possible to de/serialize data to non-self-describing formats using reflection.
## Solution
Add support for non-self-describing de/serialization using reflection.
This allows us to use binary formatters, like [`postcard`](https://crates.io/crates/postcard):
```rust
#[derive(Reflect, FromReflect, Debug, PartialEq)]
struct Foo {
data: String
}
let mut registry = TypeRegistry::new();
registry.register::<Foo>();
let input = Foo {
data: "Hello world!".to_string()
};
// === Serialize! === //
let serializer = ReflectSerializer::new(&input, ®istry);
let bytes: Vec<u8> = postcard::to_allocvec(&serializer).unwrap();
println!("{:?}", bytes); // Output: [129, 217, 61, 98, ...]
// === Deserialize! === //
let deserializer = UntypedReflectDeserializer::new(®istry);
let dynamic_output = deserializer
.deserialize(&mut postcard::Deserializer::from_bytes(&bytes))
.unwrap();
let output = <Foo as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
assert_eq!(expected, output); // OK!
```
#### Crates Tested
- ~~[`rmp-serde`](https://crates.io/crates/rmp-serde)~~ Apparently, this _is_ self-describing
- ~~[`bincode` v2.0.0-rc.1](https://crates.io/crates/bincode/2.0.0-rc.1) (using [this PR](https://github.com/bincode-org/bincode/pull/586))~~ This actually works for the latest release (v1.3.3) of [`bincode`](https://crates.io/crates/bincode) as well. You just need to be sure to use fixed-int encoding.
- [`postcard`](https://crates.io/crates/postcard)
## Future Work
Ideally, we would refactor the `serde` module, but I don't think I'll do that in this PR so as to keep the diff relatively small (and to avoid any painful rebases). This should probably be done once this is merged, though.
Some areas we could improve with a refactor:
* Split deserialization logic across multiple files
* Consolidate helper functions/structs
* Make the logic more DRY
---
## Changelog
- Add support for non-self-describing de/serialization using reflection.
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
This reverts commit 53d387f340.
# Objective
Reverts #6448. This didn't have the intended effect: we're now getting bevy::prelude shown in the docs again.
Co-authored-by: Alejandro Pascual <alejandro.pascual.pozo@gmail.com>
# Objective
- Right now re-exports are completely hidden in prelude docs.
- Fixes#6433
## Solution
- We could show the re-exports without inlining their documentation.
# Objective
- `ReflectDefault` can be used to create default values for reflected types
- `std` primitives that are `Default`-constructable should register `ReflectDefault`
## Solution
- register `ReflectDefault`
# Objective
Fixes#6378
`bevy_transform` is missing a feature corresponding to the `serialize` feature on the `bevy` crate.
## Solution
Adds a `serialize` feature to `bevy_transform`.
Derives `serde::Serialize` and `Deserialize` when feature is enabled.
# Objective
- fix new clippy lints before they get stable and break CI
## Solution
- run `clippy --fix` to auto-fix machine-applicable lints
- silence `clippy::should_implement_trait` for `fn HandleId::default<T: Asset>`
## Changes
- always prefer `format!("{inline}")` over `format!("{}", not_inline)`
- prefer `Box::default` (or `Box::<T>::default` if necessary) over `Box::new(T::default())`
# Objective
When running the scene example, you might notice we end up printing out the following:
```ron
// ...
{
"scene::ComponentB": (
value: "hello",
_time_since_startup: (
secs: 0,
nanos: 0,
),
),
},
// ...
```
We should not be printing out `_time_since_startup` as the field is marked with `#[reflect(skip_serializing)]`:
```rust
#[derive(Component, Reflect)]
#[reflect(Component)]
struct ComponentB {
pub value: String,
#[reflect(skip_serializing)]
pub _time_since_startup: Duration,
}
```
This is because when we create the `DynamicScene`, we end up calling `Reflect::clone_value`:
82126697ee/crates/bevy_scene/src/dynamic_scene_builder.rs (L114-L114)
This results in non-Value types being cloned into Dynamic types, which means the `TypeId` returned from `reflected_value.type_id()` is not the same as the original component's.
And this meant we were not able to locate the correct `TypeRegistration`.
## Solution
Use `TypeInfo::type_id()` instead of calling `Any::type_id()` on the value directly.
---
## Changelog
* Fix a bug introduced in `0.9.0-dev` where scenes disregarded component's type registrations
# Objective
Resolves#6197
Make it so that doc comments can be retrieved via reflection.
## Solution
Adds the new `documentation` feature to `bevy_reflect` (disabled by default).
When enabled, documentation can be found using `TypeInfo::doc` for reflected types:
```rust
/// Some struct.
///
/// # Example
///
/// ```ignore
/// let some_struct = SomeStruct;
/// ```
#[derive(Reflect)]
struct SomeStruct;
let info = <SomeStruct as Typed>::type_info();
assert_eq!(
Some(" Some struct.\n\n # Example\n\n ```ignore\n let some_struct = SomeStruct;\n ```"),
info.docs()
);
```
### Notes for Reviewers
The bulk of the files simply added the same 16 lines of code (with slightly different documentation). Most of the real changes occur in the `bevy_reflect_derive` files as well as in the added tests.
---
## Changelog
* Added `documentation` feature to `bevy_reflect`
* Added `TypeInfo::docs` method (and similar methods for all info types)
# Objective
Currently, surprising behavior happens when specifying `#[reflect(...)]` or `#[reflect_value(...)]` multiple times. Rather than merging the traits lists from all attributes, only the trait list from the last attribute is used. For example, in the following code, only the `Debug` and `Hash` traits are reflected and not `Default` or `PartialEq`:
```rs
#[derive(Debug, PartialEq, Hash, Default, Reflect)]
#[reflect(PartialEq, Default)]
#[reflect(Debug, Hash)]
struct Foo;
```
This is especially important when some traits should only be reflected under certain circumstances. For example, this previously had surprisingly behavior when the "serialize" feature is enabled:
```rs
#[derive(Debug, Hash, Reflect)]
#[reflect(Debug, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Serialize, Deserialize),
reflect(Serialize, Deserialize)
]
struct Foo;
```
In addition, compile error messages generated from using the derive macro often point to the `#[derive(Reflect)]` rather than to the source of the error. It would be a lot more helpful if the compiler errors pointed to what specifically caused the error rather than just to the derive macro itself.
## Solution
Merge the trait lists in all `#[reflect(...)]` and `#[reflect_value(...)]` attributes. Additionally, make `#[reflect]` and `#[reflect_value]` mutually exclusive.
Additionally, span information is carried throughout some parts of the code now to ensure that error messages point to more useful places and better indicate what caused those errors. For example, `#[reflect(Hash, Hash)]` points to the second `Hash` as the source of an error. Also, in the following example, the compiler error now points to the `Hash` in `#[reflect(Hash)]` rather than to the derive macro:
```rs
#[derive(Reflect)]
#[reflect(Hash)] // <-- compiler error points to `Hash` for lack of a `Hash` implementation
struct Foo;
```
---
## Changelog
Changed
- Using multiple `#[reflect(...)]` or `#[reflect_value(...)]` attributes now merges the trait lists. For example, `#[reflect(Debug, Hash)] #[reflect(PartialEq, Default)]` is equivalent to `#[reflect(Debug, Hash, PartialEq, Default)]`.
- Multiple `#[reflect(...)]` and `#[reflect_value(...)]` attributes were previously accepted, but only the last attribute was respected.
- Using both `#[reflect(...)]` and `#[reflect_value(...)]` was previously accepted, but had surprising behavior. This is no longer accepted.
- Improved error messages for `#[derive(Reflect)]` by propagating useful span information. Many errors should now point to the source of those errors rather than to the derive macro.
# Objective
Currently, arrays cannot indexed using the reflection path API.
This change makes them behave like lists so `x.get_path("list[0]")` will behave the same way, whether x.list is a "List" (e.g. a Vec) or an array.
## Solution
When syntax is encounterd `[ <idx> ]` we check if the referenced type is either a `ReflectRef::List` or `ReflectRef::Array` (or `ReflectMut` for the mutable case). Since both provide the identical API for accessing entries, we do the same for both, although it requires code duplication as far as I can tell.
This was born from working on #5764, but since this seems to be an easier fix (and I am not sure if I can actually solve #5812) I figured it might be worth to split this out.
> Note: This is rebased off #4561 and can be viewed as a competitor to that PR. See `Comparison with #4561` section for details.
# Objective
The current serialization format used by `bevy_reflect` is both verbose and error-prone. Taking the following structs[^1] for example:
```rust
// -- src/inventory.rs
#[derive(Reflect)]
struct Inventory {
id: String,
max_storage: usize,
items: Vec<Item>
}
#[derive(Reflect)]
struct Item {
name: String
}
```
Given an inventory of a single item, this would serialize to something like:
```rust
// -- assets/inventory.ron
{
"type": "my_game::inventory::Inventory",
"struct": {
"id": {
"type": "alloc::string::String",
"value": "inv001",
},
"max_storage": {
"type": "usize",
"value": 10
},
"items": {
"type": "alloc::vec::Vec<alloc::string::String>",
"list": [
{
"type": "my_game::inventory::Item",
"struct": {
"name": {
"type": "alloc::string::String",
"value": "Pickaxe"
},
},
},
],
},
},
}
```
Aside from being really long and difficult to read, it also has a few "gotchas" that users need to be aware of if they want to edit the file manually. A major one is the requirement that you use the proper keys for a given type. For structs, you need `"struct"`. For lists, `"list"`. For tuple structs, `"tuple_struct"`. And so on.
It also ***requires*** that the `"type"` entry come before the actual data. Despite being a map— which in programming is almost always orderless by default— the entries need to be in a particular order. Failure to follow the ordering convention results in a failure to deserialize the data.
This makes it very prone to errors and annoyances.
## Solution
Using #4042, we can remove a lot of the boilerplate and metadata needed by this older system. Since we now have static access to type information, we can simplify our serialized data to look like:
```rust
// -- assets/inventory.ron
{
"my_game::inventory::Inventory": (
id: "inv001",
max_storage: 10,
items: [
(
name: "Pickaxe"
),
],
),
}
```
This is much more digestible and a lot less error-prone (no more key requirements and no more extra type names).
Additionally, it is a lot more familiar to users as it follows conventional serde mechanics. For example, the struct is represented with `(...)` when serialized to RON.
#### Custom Serialization
Additionally, this PR adds the opt-in ability to specify a custom serde implementation to be used rather than the one created via reflection. For example[^1]:
```rust
// -- src/inventory.rs
#[derive(Reflect, Serialize)]
#[reflect(Serialize)]
struct Item {
#[serde(alias = "id")]
name: String
}
```
```rust
// -- assets/inventory.ron
{
"my_game::inventory::Inventory": (
id: "inv001",
max_storage: 10,
items: [
(
id: "Pickaxe"
),
],
),
},
```
By allowing users to define their own serialization methods, we do two things:
1. We give more control over how data is serialized/deserialized to the end user
2. We avoid having to re-define serde's attributes and forcing users to apply both (e.g. we don't need a `#[reflect(alias)]` attribute).
### Improved Formats
One of the improvements this PR provides is the ability to represent data in ways that are more conventional and/or familiar to users. Many users are familiar with RON so here are some of the ways we can now represent data in RON:
###### Structs
```js
{
"my_crate::Foo": (
bar: 123
)
}
// OR
{
"my_crate::Foo": Foo(
bar: 123
)
}
```
<details>
<summary>Old Format</summary>
```js
{
"type": "my_crate::Foo",
"struct": {
"bar": {
"type": "usize",
"value": 123
}
}
}
```
</details>
###### Tuples
```js
{
"(f32, f32)": (1.0, 2.0)
}
```
<details>
<summary>Old Format</summary>
```js
{
"type": "(f32, f32)",
"tuple": [
{
"type": "f32",
"value": 1.0
},
{
"type": "f32",
"value": 2.0
}
]
}
```
</details>
###### Tuple Structs
```js
{
"my_crate::Bar": ("Hello World!")
}
// OR
{
"my_crate::Bar": Bar("Hello World!")
}
```
<details>
<summary>Old Format</summary>
```js
{
"type": "my_crate::Bar",
"tuple_struct": [
{
"type": "alloc::string::String",
"value": "Hello World!"
}
]
}
```
</details>
###### Arrays
It may be a bit surprising to some, but arrays now also use the tuple format. This is because they essentially _are_ tuples (a sequence of values with a fixed size), but only allow for homogenous types. Additionally, this is how RON handles them and is probably a result of the 32-capacity limit imposed on them (both by [serde](https://docs.rs/serde/latest/serde/trait.Serialize.html#impl-Serialize-for-%5BT%3B%2032%5D) and by [bevy_reflect](https://docs.rs/bevy/latest/bevy/reflect/trait.GetTypeRegistration.html#impl-GetTypeRegistration-for-%5BT%3B%2032%5D)).
```js
{
"[i32; 3]": (1, 2, 3)
}
```
<details>
<summary>Old Format</summary>
```js
{
"type": "[i32; 3]",
"array": [
{
"type": "i32",
"value": 1
},
{
"type": "i32",
"value": 2
},
{
"type": "i32",
"value": 3
}
]
}
```
</details>
###### Enums
To make things simple, I'll just put a struct variant here, but the style applies to all variant types:
```js
{
"my_crate::ItemType": Consumable(
name: "Healing potion"
)
}
```
<details>
<summary>Old Format</summary>
```js
{
"type": "my_crate::ItemType",
"enum": {
"variant": "Consumable",
"struct": {
"name": {
"type": "alloc::string::String",
"value": "Healing potion"
}
}
}
}
```
</details>
### Comparison with #4561
This PR is a rebased version of #4561. The reason for the split between the two is because this PR creates a _very_ different scene format. You may notice that the PR descriptions for either PR are pretty similar. This was done to better convey the changes depending on which (if any) gets merged first. If #4561 makes it in first, I will update this PR description accordingly.
---
## Changelog
* Re-worked serialization/deserialization for reflected types
* Added `TypedReflectDeserializer` for deserializing data with known `TypeInfo`
* Renamed `ReflectDeserializer` to `UntypedReflectDeserializer`
* ~~Replaced usages of `deserialize_any` with `deserialize_map` for non-self-describing formats~~ Reverted this change since there are still some issues that need to be sorted out (in a separate PR). By reverting this, crates like `bincode` can throw an error when attempting to deserialize non-self-describing formats (`bincode` results in `DeserializeAnyNotSupported`)
* Structs, tuples, tuple structs, arrays, and enums are now all de/serialized using conventional serde methods
## Migration Guide
* This PR reduces the verbosity of the scene format. Scenes will need to be updated accordingly:
```js
// Old format
{
"type": "my_game::item::Item",
"struct": {
"id": {
"type": "alloc::string::String",
"value": "bevycraft:stone",
},
"tags": {
"type": "alloc::vec::Vec<alloc::string::String>",
"list": [
{
"type": "alloc::string::String",
"value": "material"
},
],
},
}
// New format
{
"my_game::item::Item": (
id: "bevycraft:stone",
tags: ["material"]
)
}
```
[^1]: Some derives omitted for brevity.
# Objective
Add traits to events in `bevy_input` and `bevy_windows`: `Copy`, `Serialize`/`Deserialize`, `PartialEq`, and `Eq`, as requested in https://github.com/bevyengine/bevy/issues/6022, https://github.com/bevyengine/bevy/issues/6023, https://github.com/bevyengine/bevy/issues/6024.
## Solution
Added the traits to events in `bevy_input` and `bevy_windows`. Added dependency of `serde` in `Cargo.toml` of `bevy_input`.
## Migration Guide
If one has been `.clone()`'ing `bevy_input` events, Clippy will now complain about that. Just remove `.clone()` to solve.
## Other Notes
Some events in `bevy_input` had `f32` fields, so `Eq` trait was not derived for them.
Some events in `bevy_windows` had `String` fields, so `Copy` trait was not derived for them.
Co-authored-by: targrub <62773321+targrub@users.noreply.github.com>
# Objective
When trying derive `Debug` for type that has `DynamicEnum` it wasn't possible, since neither of `DynamicEnum`, `DynamicTuple`, `DynamicVariant` or `DynamicArray` implements `Debug`.
## Solution
Implement Debug for those types, using `derive` macro
---
## Changelog
- `DynamicEnum`, `DynamicTuple`, `DynamicVariant` and `DynamicArray` now implements `Debug`
# Objective
- To address problems outlined in https://github.com/bevyengine/bevy/issues/5245
## Solution
- Introduce `reflect(skip_serializing)` on top of `reflect(ignore)` which disables automatic serialisation to scenes, but does not disable reflection of the field.
---
## Changelog
- Adds:
- `bevy_reflect::serde::type_data` module
- `SerializationData` structure for describing which fields are to be/not to be ignored, automatically registers as type_data for struct-based types
- the `skip_serialization` flag for `#[reflect(...)]`
- Removes:
- ability to ignore Enum variants in serialization, since that didn't work anyway
## Migration Guide
- Change `#[reflect(ignore)]` to `#[reflect(skip_serializing)]` where disabling reflection is not the intended effect.
- Remove ignore/skip attributes from enum variants as these won't do anything anymore
# Objective
Fixes Issue #6005.
## Solution
Replaced WorldQuery with ReadOnlyWorldQuery on F generic in Query filters and QueryState to restrict its trait bound.
## Migration Guide
Query filter (`F`) generics are now bound by `ReadOnlyWorldQuery`, rather than `WorldQuery`. If for some reason you were requesting `Query<&A, &mut B>`, please use `Query<&A, With<B>>` instead.
# Objective
- I'm currently working on being able to call methods on reflect types (https://github.com/jakobhellermann/bevy_reflect_fns)
- for that, I'd like to add methods to the `Input<KeyCode>` resource (which I'm doing by registering type data)
- implementing `Reflect` is currently a requirement for having type data in the `TypeRegistry`
## Solution
- derive `Reflect` for `KeyCode` and `Input`
- uses `#[reflect_value]` for `Input`, since it's fields aren't supposed to be observable
- using reflect_value would need `Clone` bounds on `T`, but since all the methods (`.pressed` etc) already require `T: Copy`, I unified everything to requiring `Copy`
- add `Send + Sync + 'static` bounds, also required by reflect derive
## Unrelated improvements
I can extract into a separate PR if needed.
- the `Reflect` derive would previously ignore `#[reflect_value]` and only accept `#[reflect_value()]` which was a bit confusing
- the generated code used `val.clone()` on a reference, which is fine if `val` impls `Clone`, but otherwise also compiles with a worse error message. Change to `std::clone::Clone::clone(val)` instead which gives a neat `T does not implement Clone` error
# Objective
The documentation on `Reflect` doesn't account for the recently added reflection traits: [`Array`](https://github.com/bevyengine/bevy/pull/4701) and [`Enum`](https://github.com/bevyengine/bevy/pull/4761).
## Solution
Updated the documentation for `Reflect` to account for the `Array` and `Enum`.
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- Update ron to 0.8.0
- Fix breaking changes
- Closes#5862
## Solution
- Removed now non-existing method call (behavior is now the same without it)
# Objective
Promote the `Rect` utility of `sprite::Rect`, which defines a rectangle
by its minimum and maximum corners, to the `bevy_math` crate to make it
available as a general math type to all crates without the need to
depend on the `bevy_sprite` crate.
Fixes#5575
## Solution
Move `sprite::Rect` into `bevy_math` and fix all uses.
Implement `Reflect` for `Rect` directly into the `bevy_reflect` crate by
having `bevy_reflect` depend on `bevy_math`. This looks like a new
dependency, but the `bevy_reflect` was "cheating" for other math types
by directly depending on `glam` to reflect other math types, thereby
giving the illusion that there was no dependency on `bevy_math`. In
practice conceptually Bevy's math types are reflected into the
`bevy_reflect` crate to avoid a dependency of that crate to a "lower
level" utility crate like `bevy_math` (which in turn would make
`bevy_reflect` be a dependency of most other crates, and increase the
risk of circular dependencies). So this change simply formalizes that
dependency in `Cargo.toml`.
The `Rect` struct is also augmented in this change with a collection of
utility methods to improve its usability. A few uses cases are updated
to use those new methods, resulting is more clear and concise syntax.
---
## Changelog
### Changed
- Moved the `sprite::Rect` type into `bevy_math`.
### Added
- Added several utility methods to the `math::Rect` type.
## Migration Guide
The `bevy::sprite::Rect` type moved to the math utility crate as
`bevy::math::Rect`. You should change your imports from `use
bevy::sprite::Rect` to `use bevy::math::Rect`.
# Objective
Sometimes it's useful to be able to retrieve all the fields of a container type so that they may be processed separately. With reflection, however, we typically only have access to references.
The only alternative is to "clone" the value using `Reflect::clone_value`. This, however, returns a Dynamic type in most cases. The solution there would be to use `FromReflect` instead, but this also has a problem in that it means we need to add `FromReflect` as an additional bound.
## Solution
Add a `drain` method to all container traits. This returns a `Vec<Box<dyn Reflect>>` (except for `Map` which returns `Vec<(Box<dyn Reflect>, Box<dyn Reflect>)>`).
This allows us to do things a lot simpler. For example, if we finished processing a struct and just need a particular value:
```rust
// === OLD === //
/// May or may not return a Dynamic*** value (even if `container` wasn't a `DynamicStruct`)
fn get_output(container: Box<dyn Struct>, output_index: usize) -> Box<dyn Reflect> {
container.field_at(output_index).unwrap().clone_value()
}
// === NEW === //
/// Returns _exactly_ whatever was in the given struct
fn get_output(container: Box<dyn Struct>, output_index: usize) -> Box<dyn Reflect> {
container.drain().remove(output_index).unwrap()
}
```
### Discussion
* Is `drain` the best method name? It makes sense that it "drains" all the fields and that it consumes the container in the process, but I'm open to alternatives.
---
## Changelog
* Added a `drain` method to the following traits:
* `Struct`
* `TupleStruct`
* `Tuple`
* `Array`
* `List`
* `Map`
* `Enum`
# Objective
- The reflection `List` trait does not have a `pop` function.
- Popping elements off a list is a common use case and is almost always supported by `List`-like types.
## Solution
- Add the `pop()` method to the `List` trait and add the appropriate implementations of this function.
## Migration Guide
- Any custom type that implements the `List` trait will now need to implement the `pop` method.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
Fixes#5763
## Solution
Implemented as reflect value like the current `Range`. Is there a benefit to changing everything to a reflect struct?
# Objective
Some of the reflection impls for container types had unnecessary `Clone` bounds on their generic arguments. These come from before `FromReflect` when types were instead bound by `Reflect + Clone`. With `FromReflect` this is no longer necessary.
## Solution
Removed all leftover `Clone` bounds from types that use `FromReflect` instead.
## Note
I skipped `Result<T, E>`, `HashSet<T>`, and `Range<T>` since those do not use `FromReflect`. This should probably be handled in a separate PR since it would be a breaking change.
---
## Changelog
- Remove unnecessary `Clone` bounds on reflected containers
# Objective
#5658 made it so that `FromReflect` was used as the bound for `T` in `Option<T>`. However, it did not use this change effectively for the implementation of `Reflect::apply` (it was still using `take`, which would fail for Dynamic types).
Additionally, the changes were not consistent with other methods within the file, such as the ones for `Vec<T>` and `HashMap<K, V>`.
## Solution
Update `Option<T>` to fallback on `FromReflect` if `take` fails, instead of wholly relying on one or the other.
I also chose to update the error messages, as they weren't all too descriptive before.
---
## Changelog
- Use `FromReflect::from_reflect` as a fallback in the `Reflect::apply` implementation for `Option<T>`
# Objective
`SmallVec<T>` was missing a `GetTypeRegistration` impl.
## Solution
Added a `GetTypeRegistration` impl.
---
## Changelog
* Added a `GetTypeRegistration` impl for `SmallVec<T>`
# Objective
`FromReflect` is a commonly used component to the Reflect API. It's required as a bound for reflecting things like `Vec<T>` and `HashMap<K, V>` and is generally useful (if not necessary) to derive on most structs or enums.
Currently, however, it is not exported in `bevy_reflect`'s prelude. This means a module that uses `bevy_reflect` might have the following two lines:
```rust
use bevy_reflect::prelude::*;
use bevy_reflect::FromReflect;
```
Additionally, users of the full engine might need to put:
```rust
use bevy::prelude::*;
use bevy::reflect::FromReflect;
```
## Solution
Add `FromReflect` to the prelude of `bevy_reflect`.
---
## Changelog
- Added `FromReflect` to the prelude of `bevy_reflect`
# Objective
The reflection impls on `Option<T>` have the bound `T: Reflect + Clone`. This means that using `FromReflect` requires `Clone` even though we can normally get away with just `FromReflect`.
## Solution
Update the bounds on `Option<T>` to match that of `Vec<T>`, where `T: FromReflect`.
This helps remove a `Clone` implementation that may be undesired but added for the sole purpose of getting the code to compile.
---
## Changelog
* Reflection on `Option<T>` now has `T` bound by `FromReflect` rather than `Reflect + Clone`
* Added a `FromReflect` impl for `Instant`
## Migration Guide
If using `Option<T>` with Bevy's reflection API, `T` now needs to implement `FromReflect` rather than just `Clone`. This can be achieved easily by simply deriving `FromReflect`:
```rust
// OLD
#[derive(Reflect, Clone)]
struct Foo;
let reflected: Box<dyn Reflect> = Box::new(Some(Foo));
// NEW
#[derive(Reflect, FromReflect)]
struct Foo;
let reflected: Box<dyn Reflect> = Box::new(Some(Foo));
```
> Note: You can still derive `Clone`, but it's not required in order to compile.
# Objective
- The `Display` impl for `ReflectPathError` is pretty unspecific (e.g. `the current struct doesn't have a field with the given name`
- it has info for better messages available
## Solution
- make the display impl more descriptive by including values from the type
# Objective
Add reflect/from reflect impls for NonZero integer types. I'm guessing these haven't been added yet because no one has needed them as of yet.
# Objective
> This is a revival of #1347. Credit for the original PR should go to @Davier.
Currently, enums are treated as `ReflectRef::Value` types by `bevy_reflect`. Obviously, there needs to be better a better representation for enums using the reflection API.
## Solution
Based on prior work from @Davier, an `Enum` trait has been added as well as the ability to automatically implement it via the `Reflect` derive macro. This allows enums to be expressed dynamically:
```rust
#[derive(Reflect)]
enum Foo {
A,
B(usize),
C { value: f32 },
}
let mut foo = Foo::B(123);
assert_eq!("B", foo.variant_name());
assert_eq!(1, foo.field_len());
let new_value = DynamicEnum::from(Foo::C { value: 1.23 });
foo.apply(&new_value);
assert_eq!(Foo::C{value: 1.23}, foo);
```
### Features
#### Derive Macro
Use the `#[derive(Reflect)]` macro to automatically implement the `Enum` trait for enum definitions. Optionally, you can use `#[reflect(ignore)]` with both variants and variant fields, just like you can with structs. These ignored items will not be considered as part of the reflection and cannot be accessed via reflection.
```rust
#[derive(Reflect)]
enum TestEnum {
A,
// Uncomment to ignore all of `B`
// #[reflect(ignore)]
B(usize),
C {
// Uncomment to ignore only field `foo` of `C`
// #[reflect(ignore)]
foo: f32,
bar: bool,
},
}
```
#### Dynamic Enums
Enums may be created/represented dynamically via the `DynamicEnum` struct. The main purpose of this struct is to allow enums to be deserialized into a partial state and to allow dynamic patching. In order to ensure conversion from a `DynamicEnum` to a concrete enum type goes smoothly, be sure to add `FromReflect` to your derive macro.
```rust
let mut value = TestEnum::A;
// Create from a concrete instance
let dyn_enum = DynamicEnum::from(TestEnum::B(123));
value.apply(&dyn_enum);
assert_eq!(TestEnum::B(123), value);
// Create a purely dynamic instance
let dyn_enum = DynamicEnum::new("TestEnum", "A", ());
value.apply(&dyn_enum);
assert_eq!(TestEnum::A, value);
```
#### Variants
An enum value is always represented as one of its variants— never the enum in its entirety.
```rust
let value = TestEnum::A;
assert_eq!("A", value.variant_name());
// Since we are using the `A` variant, we cannot also be the `B` variant
assert_ne!("B", value.variant_name());
```
All variant types are representable within the `Enum` trait: unit, struct, and tuple.
You can get the current type like:
```rust
match value.variant_type() {
VariantType::Unit => println!("A unit variant!"),
VariantType::Struct => println!("A struct variant!"),
VariantType::Tuple => println!("A tuple variant!"),
}
```
> Notice that they don't contain any values representing the fields. These are purely tags.
If a variant has them, you can access the fields as well:
```rust
let mut value = TestEnum::C {
foo: 1.23,
bar: false
};
// Read/write specific fields
*value.field_mut("bar").unwrap() = true;
// Iterate over the entire collection of fields
for field in value.iter_fields() {
println!("{} = {:?}", field.name(), field.value());
}
```
#### Variant Swapping
It might seem odd to group all variant types under a single trait (why allow `iter_fields` on a unit variant?), but the reason this was done ~~is to easily allow *variant swapping*.~~ As I was recently drafting up the **Design Decisions** section, I discovered that other solutions could have been made to work with variant swapping. So while there are reasons to keep the all-in-one approach, variant swapping is _not_ one of them.
```rust
let mut value: Box<dyn Enum> = Box::new(TestEnum::A);
value.set(Box::new(TestEnum::B(123))).unwrap();
```
#### Serialization
Enums can be serialized and deserialized via reflection without needing to implement `Serialize` or `Deserialize` themselves (which can save thousands of lines of generated code). Below are the ways an enum can be serialized.
> Note, like the rest of reflection-based serialization, the order of the keys in these representations is important!
##### Unit
```json
{
"type": "my_crate::TestEnum",
"enum": {
"variant": "A"
}
}
```
##### Tuple
```json
{
"type": "my_crate::TestEnum",
"enum": {
"variant": "B",
"tuple": [
{
"type": "usize",
"value": 123
}
]
}
}
```
<details>
<summary>Effects on Option</summary>
This ends up making `Option` look a little ugly:
```json
{
"type": "core::option::Option<usize>",
"enum": {
"variant": "Some",
"tuple": [
{
"type": "usize",
"value": 123
}
]
}
}
```
</details>
##### Struct
```json
{
"type": "my_crate::TestEnum",
"enum": {
"variant": "C",
"struct": {
"foo": {
"type": "f32",
"value": 1.23
},
"bar": {
"type": "bool",
"value": false
}
}
}
}
```
## Design Decisions
<details>
<summary><strong>View Section</strong></summary>
This section is here to provide some context for why certain decisions were made for this PR, alternatives that could have been used instead, and what could be improved upon in the future.
### Variant Representation
One of the biggest decisions was to decide on how to represent variants. The current design uses a "all-in-one" design where unit, tuple, and struct variants are all simultaneously represented by the `Enum` trait. This is not the only way it could have been done, though.
#### Alternatives
##### 1. Variant Traits
One way of representing variants would be to define traits for each variant, implementing them whenever an enum featured at least one instance of them. This would allow us to define variants like:
```rust
pub trait Enum: Reflect {
fn variant(&self) -> Variant;
}
pub enum Variant<'a> {
Unit,
Tuple(&'a dyn TupleVariant),
Struct(&'a dyn StructVariant),
}
pub trait TupleVariant {
fn field_len(&self) -> usize;
// ...
}
```
And then do things like:
```rust
fn get_tuple_len(foo: &dyn Enum) -> usize {
match foo.variant() {
Variant::Tuple(tuple) => tuple.field_len(),
_ => panic!("not a tuple variant!")
}
}
```
The reason this PR does not go with this approach is because of the fact that variants are not separate types. In other words, we cannot implement traits on specific variants— these cover the *entire* enum. This means we offer an easy footgun:
```rust
let foo: Option<i32> = None;
let my_enum = Box::new(foo) as Box<dyn TupleVariant>;
```
Here, `my_enum` contains `foo`, which is a unit variant. However, since we need to implement `TupleVariant` for `Option` as a whole, it's possible to perform such a cast. This is obviously wrong, but could easily go unnoticed. So unfortunately, this makes it not a good candidate for representing variants.
##### 2. Variant Structs
To get around the issue of traits necessarily needing to apply to both the enum and its variants, we could instead use structs that are created on a per-variant basis. This was also considered but was ultimately [[removed](71d27ab3c6) due to concerns about allocations.
Each variant struct would probably look something like:
```rust
pub trait Enum: Reflect {
fn variant_mut(&self) -> VariantMut;
}
pub enum VariantMut<'a> {
Unit,
Tuple(TupleVariantMut),
Struct(StructVariantMut),
}
struct StructVariantMut<'a> {
fields: Vec<&'a mut dyn Reflect>,
field_indices: HashMap<Cow<'static, str>, usize>
}
```
This allows us to isolate struct variants into their own defined struct and define methods specifically for their use. It also prevents users from casting to it since it's not a trait. However, this is not an optimal solution. Both `field_indices` and `fields` will require an allocation (remember, a `Box<[T]>` still requires a `Vec<T>` in order to be constructed). This *might* be a problem if called frequently enough.
##### 3. Generated Structs
The original design, implemented by @Davier, instead generates structs specific for each variant. So if we had a variant path like `Foo::Bar`, we'd generate a struct named `FooBarWrapper`. This would be newtyped around the original enum and forward tuple or struct methods to the enum with the chosen variant.
Because it involved using the `Tuple` and `Struct` traits (which are also both bound on `Reflect`), this meant a bit more code had to be generated. For a single struct variant with one field, the generated code amounted to ~110LoC. However, each new field added to that variant only added ~6 more LoC.
In order to work properly, the enum had to be transmuted to the generated struct:
```rust
fn variant(&self) -> crate::EnumVariant<'_> {
match self {
Foo::Bar {value: i32} => {
let wrapper_ref = unsafe {
std::mem::transmute::<&Self, &FooBarWrapper>(self)
};
crate::EnumVariant::Struct(wrapper_ref as &dyn crate::Struct)
}
}
}
```
This works because `FooBarWrapper` is defined as `repr(transparent)`.
Out of all the alternatives, this would probably be the one most likely to be used again in the future. The reasons for why this PR did not continue to use it was because:
* To reduce generated code (which would hopefully speed up compile times)
* To avoid cluttering the code with generated structs not visible to the user
* To keep bevy_reflect simple and extensible (these generated structs act as proxies and might not play well with current or future systems)
* To avoid additional unsafe blocks
* My own misunderstanding of @Davier's code
That last point is obviously on me. I misjudged the code to be too unsafe and unable to handle variant swapping (which it probably could) when I was rebasing it. Looking over it again when writing up this whole section, I see that it was actually a pretty clever way of handling variant representation.
#### Benefits of All-in-One
As stated before, the current implementation uses an all-in-one approach. All variants are capable of containing fields as far as `Enum` is concerned. This provides a few benefits that the alternatives do not (reduced indirection, safer code, etc.).
The biggest benefit, though, is direct field access. Rather than forcing users to have to go through pattern matching, we grant direct access to the fields contained by the current variant. The reason we can do this is because all of the pattern matching happens internally. Getting the field at index `2` will automatically return `Some(...)` for the current variant if it has a field at that index or `None` if it doesn't (or can't).
This could be useful for scenarios where the variant has already been verified or just set/swapped (or even where the type of variant doesn't matter):
```rust
let dyn_enum: &mut dyn Enum = &mut Foo::Bar {value: 123};
// We know it's the `Bar` variant
let field = dyn_enum.field("value").unwrap();
```
Reflection is not a type-safe abstraction— almost every return value is wrapped in `Option<...>`. There are plenty of places to check and recheck that a value is what Reflect says it is. Forcing users to have to go through `match` each time they want to access a field might just be an extra step among dozens of other verification processes.
Some might disagree, but ultimately, my view is that the benefit here is an improvement to the ergonomics and usability of reflected enums.
</details>
---
## Changelog
### Added
* Added `Enum` trait
* Added `Enum` impl to `Reflect` derive macro
* Added `DynamicEnum` struct
* Added `DynamicVariant`
* Added `EnumInfo`
* Added `VariantInfo`
* Added `StructVariantInfo`
* Added `TupleVariantInfo`
* Added `UnitVariantInfo`
* Added serializtion/deserialization support for enums
* Added `EnumSerializer`
* Added `VariantType`
* Added `VariantFieldIter`
* Added `VariantField`
* Added `enum_partial_eq(...)`
* Added `enum_hash(...)`
### Changed
* `Option<T>` now implements `Enum`
* `bevy_window` now depends on `bevy_reflect`
* Implemented `Reflect` and `FromReflect` for `WindowId`
* Derive `FromReflect` on `PerspectiveProjection`
* Derive `FromReflect` on `OrthographicProjection`
* Derive `FromReflect` on `WindowOrigin`
* Derive `FromReflect` on `ScalingMode`
* Derive `FromReflect` on `DepthCalculation`
## Migration Guide
* Enums no longer need to be treated as values and usages of `#[reflect_value(...)]` can be removed or replaced by `#[reflect(...)]`
* Enums (including `Option<T>`) now take a different format when serializing. The format is described above, but this may cause issues for existing scenes that make use of enums.
---
Also shout out to @nicopap for helping clean up some of the code here! It's a big feature so help like this is really appreciated!
Co-authored-by: Gino Valente <gino.valente.code@gmail.com>
# Objective
Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.
This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (https://github.com/bevyengine/bevy/issues/4054).
## Solution
- remove the `Serialize + Deserialize` bounds on wrapper types
- this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
I believe this is the best we can do for extensibility and convenience without specialization.
## Changelog
- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
# Objective
https://github.com/bevyengine/bevy/pull/4447 adds functions that can fetch resources/components as `*const ()` ptr by providing the `ComponentId`. This alone is not enough for them to be usable safely with reflection, because there is no general way to go from the raw pointer to a `&dyn Reflect` which is the pointer + a pointer to the VTable of the `Reflect` impl.
By adding a `ReflectFromPtr` type that is included in the type type registration when deriving `Reflect`, safe functions can be implemented in scripting languages that don't assume a type layout and can access the component data via reflection:
```rust
#[derive(Reflect)]
struct StringResource {
value: String
}
```
```lua
local res_id = world:resource_id_by_name("example::StringResource")
local res = world:resource(res_id)
print(res.value)
```
## Solution
1. add a `ReflectFromPtr` type with a `FromType<T: Reflect>` implementation and the following methods:
- ` pub unsafe fn as_reflect_ptr<'a>(&self, val: Ptr<'a>) -> &'a dyn Reflect`
- ` pub unsafe fn as_reflect_ptr_mut<'a>(&self, val: PtrMut<'a>) -> &'a mud dyn Reflect`
Safety requirements of the methods are that you need to check that the `ReflectFromPtr` was constructed for the correct type.
2. add that type to the `TypeRegistration` in the `GetTypeRegistration` impl generated by `#[derive(Reflect)]`.
This is different to other reflected traits because it doesn't need `#[reflect(ReflectReflectFromPtr)]` which IMO should be there by default.
Co-authored-by: Jakob Hellermann <hellermann@sipgate.de>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Remove unnecessary calls to `iter()`/`iter_mut()`.
Mainly updates the use of queries in our code, docs, and examples.
```rust
// From
for _ in list.iter() {
for _ in list.iter_mut() {
// To
for _ in &list {
for _ in &mut list {
```
We already enable the pedantic lint [clippy::explicit_iter_loop](https://rust-lang.github.io/rust-clippy/stable/) inside of Bevy. However, this only warns for a few known types from the standard library.
## Note for reviewers
As you can see the additions and deletions are exactly equal.
Maybe give it a quick skim to check I didn't sneak in a crypto miner, but you don't have to torture yourself by reading every line.
I already experienced enough pain making this PR :)
Co-authored-by: devil-ira <justthecooldude@gmail.com>