Commit graph

419 commits

Author SHA1 Message Date
Nathan Lilienthal
0b2e0cfaca
bevy_reflect: Add crate level functions feature docs (#15086)
Adds the missing section for the `functions` cargo feature of the
`bevy_reflect` crate.
2024-10-09 18:06:56 +00:00
Zachary Harrold
3cc1527e9e
Remove thiserror from bevy_reflect (#15766)
# Objective

- Contributes to #15460

## Solution

- Removed `thiserror` from `bevy_reflect`
2024-10-09 14:25:41 +00:00
notmd
cab00766d9
Serialize and deserialize tuple struct with one field as newtype struct (#15628)
# Objective

- fix https://github.com/bevyengine/bevy/issues/15623
## Solution

- Checking field length of tuple struct before ser/der

## Testing

- CI should pass

## Migration Guide

- Reflection now will serialize and deserialize tuple struct with single
field as newtype struct. Consider this code.
```rs
#[derive(Reflect, Serialize)]
struct Test(usize);
let reflect = Test(3);
let serializer = TypedReflectSerializer::new(reflect.as_partial_reflect(), &registry);
return serde_json::to_string(&serializer)
```
Old behavior will return `["3"]`. New behavior will return `"3"`. If you
were relying on old behavior you need to update your logic. Especially
with `serde_json`. `ron` doesn't affect from this.
2024-10-07 23:40:03 +00:00
Benjamin Brienen
c841dd92a1
Documentation for variadics (#15387)
# Objective

Relevant: #15208

## Solution

I went ahead and added the variadics documentation in all applicable
locations.

## Testing

- I built the documentation and inspected it to see whether the feature
is there.
2024-10-02 12:48:36 +00:00
Gino Valente
eaa37f3b45
bevy_reflect: Add DeserializeWithRegistry and SerializeWithRegistry (#8611)
# Objective

### The Problem

Currently, the reflection deserializers give little control to users for
how a type is deserialized. The most control a user can have is to
register `ReflectDeserialize`, which will use a type's `Deserialize`
implementation.

However, there are times when a type may require slightly more control.

For example, let's say we want to make Bevy's `Mesh` easier to
deserialize via reflection (assume `Mesh` actually implemented
`Reflect`). Since we want this to be extensible, we'll make it so users
can use their own types so long as they satisfy `Into<Mesh>`. The end
result should allow users to define a RON file like:

```rust
{
  "my_game::meshes::Sphere": (
    radius: 2.5
  )
}
```

### The Current Solution

Since we don't know the types ahead of time, we'll need to use
reflection. Luckily, we can access type information dynamically via the
type registry. Let's make a custom type data struct that users can
register on their types:

```rust
pub struct ReflectIntoMesh {
  // ...
}

impl<T: FromReflect + Into<Mesh>> FromType<T> for ReflectIntoMesh {
  fn from_type() -> Self {
    // ...
  }
}
```

Now we'll need a way to use this type data during deserialization.
Unfortunately, we can't use `Deserialize` since we need access to the
registry. This is where `DeserializeSeed` comes in handy:

```rust
pub struct MeshDeserializer<'a> {
  pub registry: &'a TypeRegistry
}

impl<'a, 'de> DeserializeSeed<'de> for MeshDeserializer<'a> {
  type Value = Mesh;

  fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
  where
    D: serde::Deserializer<'de>,
  {
    struct MeshVisitor<'a> {
      registry: &'a TypeRegistry
    }

    impl<'a, 'de> Visitor<'de> for MeshVisitor<'a> {
      fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
        write!(formatter, "map containing mesh information")
      }

      fn visit_map<A>(self, mut map: A) -> Result<Self::Value, serde:🇩🇪:Error> where A: MapAccess<'de> {
        // Parse the type name
        let type_name = map.next_key::<String>()?.unwrap();

        // Deserialize the value based on the type name
        let registration = self.registry
          .get_with_name(&type_name)
          .expect("should be registered");
        let value = map.next_value_seed(TypedReflectDeserializer {
          registration,
          registry: self.registry,
        })?;

        // Convert the deserialized value into a `Mesh`
        let into_mesh = registration.data::<ReflectIntoMesh>().unwrap();
        Ok(into_mesh.into(value))
      }
    }
  }
}
```

### The Problem with the Current Solution

The solution above works great when all we need to do is deserialize
`Mesh` directly. But now, we want to be able to deserialize a struct
like this:

```rust
struct Fireball {
  damage: f32,
  mesh: Mesh,
}
```

This might look simple enough and should theoretically be no problem for
the reflection deserializer to handle, but this is where our
`MeshDeserializer` solution starts to break down.

In order to use `MeshDeserializer`, we need to have access to the
registry. The reflection deserializers have access to that, but we have
no way of borrowing it for our own deserialization since they have no
way of knowing about `MeshDeserializer`.

This means we need to implement _another_ `DeserializeSeed`— this time
for `Fireball`!
And if we decided to put `Fireball` inside another type, well now we
need one for that type as well.

As you can see, this solution does not scale well and results in a lot
of unnecessary boilerplate for the user.

## Solution

> [!note]
> This PR originally only included the addition of
`DeserializeWithRegistry`. Since then, a corresponding
`SerializeWithRegistry` trait has also been added. The reasoning and
usage is pretty much the same as the former so I didn't bother to update
the full PR description.

Created the `DeserializeWithRegistry` trait and
`ReflectDeserializeWithRegistry` type data.

The `DeserializeWithRegistry` trait works like a standard `Deserialize`
but provides access to the registry. And by registering the
`ReflectDeserializeWithRegistry` type data, the reflection deserializers
will automatically use the `DeserializeWithRegistry` implementation,
just like it does for `Deserialize`.

All we need to do is make the following changes:

```diff
#[derive(Reflect)]
+ #[reflect(DeserializeWithRegistry)]
struct Mesh {
  // ...
}

- impl<'a, 'de> DeserializeSeed<'de> for MeshDeserializer<'a> {
-   type Value = Mesh;
-   fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ impl<'de> DeserializeWithRegistry<'de> for Mesh {
+   fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
    where
      D: serde::Deserializer<'de>,
    {
      // ...
    }
}
```

Now, any time the reflection deserializer comes across `Mesh`, it will
opt to use its `DeserializeWithRegistry` implementation. And this means
we no longer need to create a whole slew of `DeserializeSeed` types just
to deserialize `Mesh`.

### Why not a trait like `DeserializeSeed`?

While this would allow for anyone to define a deserializer for `Mesh`,
the problem is that it means __anyone can define a deserializer for
`Mesh`.__ This has the unfortunate consequence that users can never be
certain that their registration of `ReflectDeserializeSeed` is the one
that will actually be used.

We could consider adding something like that in the future, but I think
this PR's solution is much safer and follows the example set by
`ReflectDeserialize`.

### What if we made the `TypeRegistry` globally available?

This is one potential solution and has been discussed before (#6101).
However, that change is much more controversial and comes with its own
set of disadvantages (can't have multiple registries such as with
multiple worlds, likely some added performance cost with each access,
etc.).

### Followup Work

Once this PR is merged, we should consider merging `ReflectDeserialize`
into `DeserializeWithRegistry`. ~~There is already a blanket
implementation to make this transition generally pretty
straightforward.~~ The blanket implementations were removed for the sake
of this PR and will need to be re-added in the followup. I would propose
that we first mark `ReflectDeserialize` as deprecated, though, before we
outright remove it in a future release.

---

## Changelog

- Added the `DeserializeReflect` trait and `ReflectDeserializeReflect`
type data
- Added the `SerializeReflect` trait and `ReflectSerializeReflect` type
data
- Added `TypedReflectDeserializer::of` convenience constructor

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: aecsocket <43144841+aecsocket@users.noreply.github.com>
2024-10-02 01:54:32 +00:00
Gino Valente
397f20e835
bevy_reflect: Generic parameter info (#15475)
# Objective

Currently, reflecting a generic type provides no information about the
generic parameters. This means that you can't get access to the type of
`T` in `Foo<T>` without creating custom type data (we do this for
[`ReflectHandle`](https://docs.rs/bevy/0.14.2/bevy/asset/struct.ReflectHandle.html#method.asset_type_id)).

## Solution

This PR makes it so that generic type parameters and generic const
parameters are tracked in a `Generics` struct stored on the `TypeInfo`
for a type.

For example, `struct Foo<T, const N: usize>` will store `T` and `N` as a
`TypeParamInfo` and `ConstParamInfo`, respectively.

The stored information includes:

- The name of the generic parameter (i.e. `T`, `N`, etc.)
- The type of the generic parameter (remember that we're dealing with
monomorphized types, so this will actually be a concrete type)
- The default type/value, if any (e.g. `f32` in `T = f32` or `10` in
`const N: usize = 10`)

### Caveats

The only requirement for this to work is that the user does not opt-out
of the automatic `TypePath` derive with `#[reflect(type_path = false)]`.

Doing so prevents the macro code from 100% knowing that the generic type
implements `TypePath`. This in turn means the generated `Typed` impl
can't add generics to the type.

There are two solutions for this—both of which I think we should explore
in a future PR:

1. We could just not use `TypePath`. This would mean that we can't store
the `Type` of the generic, but we can at least store the `TypeId`.
2. We could provide a way to opt out of the automatic `Typed` derive
with a `#[reflect(typed = false)]` attribute. This would allow users to
manually implement `Typed` to add whatever generic information they need
(e.g. skipping a parameter that can't implement `TypePath` while the
rest can).

I originally thought about making `Generics` an enum with `Generic`,
`NonGeneric`, and `Unavailable` variants to signify whether there are
generics, no generics, or generics that cannot be added due to opting
out of `TypePath`. I ultimately decided against this as I think it adds
a bit too much complexity for such an uncommon problem.

Additionally, user's don't necessarily _have_ to know the generics of a
type, so just skipping them should generally be fine for now.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect
```

---

## Showcase

You can now access generic parameters via `TypeInfo`!

```rust
#[derive(Reflect)]
struct MyStruct<T, const N: usize>([T; N]);

let generics = MyStruct::<f32, 10>::type_info().generics();

// Get by index:
let t = generics.get(0).unwrap();
assert_eq!(t.name(), "T");
assert!(t.ty().is::<f32>());
assert!(!t.is_const());

// Or by name:
let n = generics.get_named("N").unwrap();
assert_eq!(n.name(), "N");
assert!(n.ty().is::<usize>());
assert!(n.is_const());
```

You can even access parameter defaults:

```rust
#[derive(Reflect)]
struct MyStruct<T = String, const N: usize = 10>([T; N]);

let generics = MyStruct::<f32, 5>::type_info().generics();

let GenericInfo::Type(info) = generics.get_named("T").unwrap() else {
    panic!("expected a type parameter");
};

let default = info.default().unwrap();

assert!(default.is::<String>());

let GenericInfo::Const(info) = generics.get_named("N").unwrap() else {
    panic!("expected a const parameter");
};

let default = info.default().unwrap();

assert_eq!(default.downcast_ref::<usize>().unwrap(), &10);
```
2024-09-30 17:58:37 +00:00
andriyDev
04d5685889
Make drain take a mutable borrow instead of Box<Self> for reflected Map, List, and Set. (#15406)
# Objective

Fixes #15185.

# Solution

Change `drain` to take a `&mut self` for most reflected types.

Some notable exceptions to this change are `Array` and `Tuple`. These
types don't make sense with `drain` taking a mutable borrow since they
can't get "smaller". Also `BTreeMap` doesn't have a `drain` function, so
we have to pop elements off one at a time.

## Testing

- The existing tests are sufficient.

---

## Migration Guide

- `reflect::Map`, `reflect::List`, and `reflect::Set` all now take a
`&mut self` instead of a `Box<Self>`. Callers of these traits should add
`&mut` before their boxes, and implementers of these traits should
update to match.
2024-09-30 17:19:13 +00:00
Giacomo Stevanato
0d751e8809
Use HashTable in DynamicMap and fix bug in remove (#15158)
# Objective

- `DynamicMap` currently uses an `HashMap` from a `u64` hash to the
entry index in a `Vec`. This is incorrect in the presence of hash
collisions, so let's fix it;
- `DynamicMap::remove` was also buggy, as it didn't fix up the indexes
of the other elements after removal. Fix that up as well and add a
regression test.

## Solution

- Use `HashTable` in `DynamicMap` to distinguish entries that have the
same hash by using `reflect_partial_eq`, bringing it more in line with
what `DynamicSet` does;
- Reimplement `DynamicMap::remove` to properly fix up the index of moved
elements after the removal.

## Testing

- A regression test was added for the `DynamicMap::remove` issue.

---

Some kinda related considerations: the use of a separate `Vec` for
storing the entries adds some complications that I'm not sure are worth.
This is mainly used to implement an efficient `get_at`, which is relied
upon by `MapIter`. However both `HashMap` and `BTreeMap` implement
`get_at` inefficiently (and cannot do so efficiently), leading to a
`O(N^2)` complexity for iterating them. This could be removed in favor
of a `Box<dyn Iterator>` like it's done in `DynamicSet`.
2024-09-30 17:02:10 +00:00
hshrimp
7ee5143d45
Remove Return::Unit variant (#15484)
# Objective

- Fixes #15447 

## Solution

- Remove the `Return::Unit` variant and use a `Return::Owned` variant
holding a unit `()` type.

## Migration Guide

- Removed the `Return::Unit` variant; use `Return::unit()` instead.

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-09-28 16:26:55 +00:00
JohnTheCoolingFan
1175cf7920
Fix ReflectKind description wording (#15498)
# Objective

The "zero-sized" description was outdated and misleading.

## Solution

Changed the description to just say that it's an enumeration (an enum)
2024-09-28 16:26:00 +00:00
Zachary Harrold
d70595b667
Add core and alloc over std Lints (#15281)
# Objective

- Fixes #6370
- Closes #6581

## Solution

- Added the following lints to the workspace:
  - `std_instead_of_core`
  - `std_instead_of_alloc`
  - `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.

## Testing

- Ran CI locally

## Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

## Notes

- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
Clar Fon
efda7f3f9c
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this
comment:
https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300

See #15375 for more reasoning/motivation.

## Rebasing (rerunning)

```rust
git switch simpler-lint-fixes
git reset --hard main
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "rustfmt"
cargo clippy --workspace --all-targets --all-features --fix
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "clippy"
git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887
```
2024-09-24 11:42:59 +00:00
Gino Valente
1a41c736b3
bevy_reflect: Update EulerRot to match glam 0.29 (#15402)
# Objective

#15349 added an `impl_reflect!` for `glam::EulerRot`. This was done by
copying and pasting the enum definition from `glam` into `bevy_reflect`
so that the macro could interpret the variants.

However, as mentioned in the description for that PR, this would need to
be updated for `glam` 0.29, as it had not been updated yet.

#15249 came and updated `glam` to 0.29, but did not change these impls.
This is understandable as failing to do so doesn't cause any compile
errors.

This PR updates the definition and aims to make this silent breakage a
little less silent.

## Solution

Firstly, I updated the definition for `EulerRot` to match the one from
`glam`.

Secondly, I added the `assert_type_match` crate, which I created
specifically to solve this problem. By using this crate, we'll get a
compile time error if `glam` ever decides to change `EulerRot` again.

In the future we can consider using it for other types with this
problem, including in other crates (I'm pretty sure `bevy_window` and/or
`bevy_winit` also copy+paste some types). I made sure to use as few
dependencies as possible so everything should already be in-tree (it's
just `quote`, `proc-macro2`, and `syn` with default features).

## Testing

No tests added. CI should pass.

---

## Migration Guide

The reflection implementation for `EulerRot` has been updated to align
with `glam` 0.29. Please update any reflection-based usages accordingly.
2024-09-23 22:50:12 +00:00
targrub
de3c70a8d3
Update `glam to 0.29, encase` to 0.10. (#15249)
# Objective

Updating ``glam`` to 0.29, ``encase`` to 0.10.

## Solution

Update the necessary ``Cargo.toml`` files.

## Testing

Ran ``cargo run -p ci`` on Windows; no issues came up.

---------

Co-authored-by: aecsocket <aecsocket@tutanota.com>
2024-09-23 19:44:02 +00:00
Gino Valente
83356b12c9
bevy_reflect: Replace "value" terminology with "opaque" (#15240)
# Objective

Currently, the term "value" in the context of reflection is a bit
overloaded.

For one, it can be used synonymously with "data" or "variable". An
example sentence would be "this function takes a reflected value".

However, it is also used to refer to reflected types which are
`ReflectKind::Value`. These types are usually either primitives, opaque
types, or types that don't fall into any other `ReflectKind` (or perhaps
could, but don't due to some limitation/difficulty). An example sentence
would be "this function takes a reflected value type".

This makes it difficult to write good documentation or other learning
material without causing some amount of confusion to readers. Ideally,
we'd be able to move away from the `ReflectKind::Value` usage and come
up with a better term.

## Solution

This PR replaces the terminology of "value" with "opaque" across
`bevy_reflect`. This includes in documentation, type names, variant
names, and macros.

The term "opaque" was chosen because that's essentially how the type is
treated within the reflection API. In other words, its internal
structure is hidden. All we can do is work with the type itself.

### Primitives

While primitives are not technically opaque types, I think it's still
clearer to refer to them as "opaque" rather than keep the confusing
"value" terminology.

We could consider adding another concept for primitives (e.g.
`ReflectKind::Primitive`), but I'm not sure that provides a lot of
benefit right now. In most circumstances, they'll be treated just like
an opaque type. They would also likely use the same macro (or two copies
of the same macro but with different names).

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```

---

## Migration Guide

The reflection concept of "value type" has been replaced with a clearer
"opaque type". The following renames have been made to account for this:

- `ReflectKind::Value` → `ReflectKind::Opaque`
- `ReflectRef::Value` → `ReflectRef::Opaque`
- `ReflectMut::Value` → `ReflectMut::Opaque`
- `ReflectOwned::Value` → `ReflectOwned::Opaque`
- `TypeInfo::Value` → `TypeInfo::Opaque`
- `ValueInfo` → `OpaqueInfo`
- `impl_reflect_value!` → `impl_reflect_opaque!`
- `impl_from_reflect_value!` → `impl_from_reflect_opaque!`

Additionally, declaring your own opaque types no longer uses
`#[reflect_value]`. This attribute has been replaced by
`#[reflect(opaque)]`:

```rust
// BEFORE
#[derive(Reflect)]
#[reflect_value(Default)]
struct MyOpaqueType(u32);

// AFTER
#[derive(Reflect)]
#[reflect(opaque)]
#[reflect(Default)]
struct MyOpaqueType(u32);
```

Note that the order in which `#[reflect(opaque)]` appears does not
matter.
2024-09-23 18:04:57 +00:00
Benjamin Brienen
8a6d0b063c
Use crate: disqualified (#15372)
# Objective

Fixes #15351 

## Solution

- Created new external crate and ported over the code

## Testing

- CI

## Migration guide

Replace references to `bevy_utils::ShortName` with
`disqualified::ShortName`.
2024-09-23 17:34:17 +00:00
Clar Fon
2c5be2ef4c
Reflect for TextureFormat (#15355)
# Objective

In order to derive `Reflect`, all of a struct's fields must implement
`FromReflect`. [As part of looking into some of the work mentioned
here](https://github.com/bevyengine/bevy/issues/13713#issuecomment-2364786694),
I noticed that `TextureFormat` doesn't implement `Reflect`, and decided
to split that into a separate PR.

## Solution

I decided that `TextureFormat` should be a `reflect_value` since,
although one variant has fields, most users will treat this as an opaque
value set explicitly. It also substantially reduces the complexity of
the implementation.

For now, this implementation isn't actually used by any crates, so, I
decided to not preemptively enable the feature on anything. But it's
technically an option, now, and more `wgpu` types can be added in the
future.

## Testing

Everything compiles okay, and I can't really see how this could be done
incorrectly given the above constraints.
2024-09-23 17:26:12 +00:00
aecsocket
fb324f0e89
impl_reflect! for EulerRot instead of treating it as an opaque value (#15349)
# Objective

Currently, Bevy implements reflection for `glam::EulerRot` using:
```rs
impl_reflect_value!(::glam::EulerRot(Debug, Default, Deserialize, Serialize));
```

Treating it as an opaque type. However, it's useful to expose the
EulerRot enum variants directly, which I make use of from a drop down
selection box in `bevy_egui`. This PR changes this to use
`impl_reflect!`.

**Importantly**, Bevy currently uses glam 0.28.0, in which `EulerRot`
has just 6 variants. In glam 0.29.0, this is exanded to 24 variants, see
bb2ab05613.
When Bevy updates to 0.29.0, this reflect impl must also be updated to
include the new variants.

## Solution

Replaces the `impl_reflect_value!` with `impl_reflect!` and a
handwritten version of `EulerRot` with the same variants.

## Testing

Added a `tests` module to `glam.rs` to ensure that de/serialization
works. However, my main concern is making sure that the number of enum
variants matches glam's, which I'm not sure how to do using `Enum`.
2024-09-23 17:24:28 +00:00
Gino Valente
51accd34ed
bevy_reflect: Add dynamic type data access and iteration to TypeRegistration (#15347)
# Objective

There's currently no way to iterate through all the type data in a
`TypeRegistration`. While these are all type-erased, it can still be
useful to see what types (by `TypeId`) are registered for a given type.

Additionally, it might be good to have ways of dynamically working with
`TypeRegistration`.

## Solution

Added a way to iterate through all type data on a given
`TypeRegistration`. This PR also adds methods for working with type data
dynamically as well as methods for conveniently checking if a given type
data exists on the registration.

I also took this opportunity to reorganize the methods on
`TypeRegistration` as it has always bothered me haha (i.e. the
constructor not being at the top, etc.).

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect
```

---

## Showcase

The type-erased type data on a `TypeRegistration` can now be iterated!

```rust
#[derive(Reflect)]
struct Foo;

#[derive(Clone)]
struct DataA(i32);

#[derive(Clone)]
struct DataB(i32);

let mut registration = TypeRegistration::of::<Foo>();
registration.insert(DataA(123));
registration.insert(DataB(456));

let mut iter = registration.iter();

let (id, data) = iter.next().unwrap();
assert_eq!(id, TypeId::of::<DataA>());
assert_eq!(data.downcast_ref::<DataA>().unwrap().0, 123);

let (id, data) = iter.next().unwrap();
assert_eq!(id, TypeId::of::<DataB>());
assert_eq!(data.downcast_ref::<DataB>().unwrap().0, 456);

assert!(iter.next().is_none());
```
2024-09-23 17:21:22 +00:00
Patrick Walton
8154164f1b
Allow animation clips to animate arbitrary properties. (#15282)
Currently, Bevy restricts animation clips to animating
`Transform::translation`, `Transform::rotation`, `Transform::scale`, or
`MorphWeights`, which correspond to the properties that glTF can
animate. This is insufficient for many use cases such as animating UI,
as the UI layout systems expect to have exclusive control over UI
elements' `Transform`s and therefore the `Style` properties must be
animated instead.

This commit fixes this, allowing for `AnimationClip`s to animate
arbitrary properties. The `Keyframes` structure has been turned into a
low-level trait that can be implemented to achieve arbitrary animation
behavior. Along with `Keyframes`, this patch adds a higher-level trait,
`AnimatableProperty`, that simplifies the task of animating single
interpolable properties. Built-in `Keyframes` implementations exist for
translation, rotation, scale, and morph weights. For the most part, you
can migrate by simply changing your code from
`Keyframes::Translation(...)` to `TranslationKeyframes(...)`, and
likewise for rotation, scale, and morph weights.

An example `AnimatableProperty` implementation for the font size of a
text section follows:

     #[derive(Reflect)]
     struct FontSizeProperty;

     impl AnimatableProperty for FontSizeProperty {
         type Component = Text;
         type Property = f32;
fn get_mut(component: &mut Self::Component) -> Option<&mut
Self::Property> {
             Some(&mut component.sections.get_mut(0)?.style.font_size)
         }
     }

In order to keep this patch relatively small, this patch doesn't include
an implementation of `AnimatableProperty` on top of the reflection
system. That can be a follow-up.

This patch builds on top of the new `EntityMutExcept<>` type in order to
widen the `AnimationTarget` query to include write access to all
components. Because `EntityMutExcept<>` has some performance overhead
over an explicit query, we continue to explicitly query `Transform` in
order to avoid regressing the performance of skeletal animation, such as
the `many_foxes` benchmark. I've measured the performance of that
benchmark and have found no significant regressions.

A new example, `animated_ui`, has been added. This example shows how to
use Bevy's built-in animation infrastructure to animate font size and
color, which wasn't possible before this patch.

## Showcase


https://github.com/user-attachments/assets/1fa73492-a9ce-405a-a8f2-4aacd7f6dc97

## Migration Guide

* Animation keyframes are now an extensible trait, not an enum. Replace
`Keyframes::Translation(...)`, `Keyframes::Scale(...)`,
`Keyframes::Rotation(...)`, and `Keyframes::Weights(...)` with
`Box::new(TranslationKeyframes(...))`, `Box::new(ScaleKeyframes(...))`,
`Box::new(RotationKeyframes(...))`, and
`Box::new(MorphWeightsKeyframes(...))` respectively.
2024-09-23 17:14:12 +00:00
Gino Valente
6e95f297ea
bevy_reflect: Automatic arg count validation (#15145)
# Objective

Functions created into `DynamicFunction[Mut]` do not currently validate
the number of arguments they are given before calling the function.

I originally did this because I felt users would want to validate this
themselves in the function rather than have it be done
behind-the-scenes. I'm now realizing, however, that we could remove this
boilerplate and if users wanted to check again then they would still be
free to do so (it'd be more of a sanity check at that point).

## Solution

Automatically validate the number of arguments passed to
`DynamicFunction::call` and `DynamicFunctionMut::call[_once]`.

This is a pretty trivial change since we just need to compare the length
of the `ArgList` to the length of the `[ArgInfo]` in the function's
`FunctionInfo`.

I also ran the benchmarks just in case and saw no regression by doing
this.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```
2024-09-23 17:03:14 +00:00
Gino Valente
4d0961cc8a
bevy_reflect: Add ReflectRef/ReflectMut/ReflectOwned convenience casting methods (#15235)
# Objective

#13320 added convenience methods for casting a `TypeInfo` into its
respective variant:

```rust
let info: &TypeInfo = <Vec<i32> as Typed>::type_info();

// We know `info` contains a `ListInfo`, so we can simply cast it:
let list_info: &ListInfo = info.as_list().unwrap();
```

This is especially helpful when you have already verified a type is a
certain kind via `ReflectRef`, `ReflectMut`, `ReflectOwned`, or
`ReflectKind`.

As mentioned in that PR, though, it would be useful to add similar
convenience methods to those types as well.

## Solution

Added convenience casting methods to `ReflectRef`, `ReflectMut`, and
`ReflectOwned`.

With these methods, I was able to reduce our nesting in certain places
throughout the crate.

Additionally, I took this opportunity to move these types (and
`ReflectKind`) to their own module to help clean up the `reflect`
module.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```

---

## Showcase

Convenience methods for casting `ReflectRef`, `ReflectMut`, and
`ReflectOwned` into their respective variants has been added! This
allows you to write cleaner code if you already know the kind of your
reflected data:

```rust
// BEFORE
let ReflectRef::List(list) = list.reflect_ref() else {
    panic!("expected list");
};

// AFTER
let list = list.reflect_ref().as_list().unwrap();
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
2024-09-23 16:50:46 +00:00
Benjamin Brienen
67615c5051
split bevy_reflect::derive::utilities into proper modules (#15354)
# Objective

- A utilities module is considered to be a bad practice and poor
organization of code, so this fixes it.

## Solution

- Split each struct into its own module
- Move related lose functions into their own module
- Move the last few bits into good places

## Testing

- CI

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-09-22 14:24:14 +00:00
Gino Valente
59c0521690
bevy_reflect: Add Function trait (#15205)
# Objective

While #13152 added function reflection, it didn't really make functions
reflectable. Instead, it made it so that they can be called with
reflected arguments and return reflected data. But functions themselves
cannot be reflected.

In other words, we can't go from `DynamicFunction` to `dyn
PartialReflect`.

## Solution

Allow `DynamicFunction` to actually be reflected.

This PR adds the `Function` reflection subtrait (and corresponding
`ReflectRef`, `ReflectKind`, etc.). With this new trait, we're able to
implement `PartialReflect` on `DynamicFunction`.

### Implementors

`Function` is currently only implemented for `DynamicFunction<'static>`.
This is because we can't implement it generically over all
functions—even those that implement `IntoFunction`.

What about `DynamicFunctionMut`? Well, this PR does **not** implement
`Function` for `DynamicFunctionMut`.

The reasons for this are a little complicated, but it boils down to
mutability. `DynamicFunctionMut` requires `&mut self` to be invoked
since it wraps a `FnMut`. However, we can't really model this well with
`Function`. And if we make `DynamicFunctionMut` wrap its internal
`FnMut` in a `Mutex` to allow for `&self` invocations, then we run into
either concurrency issues or recursion issues (or, in the worst case,
both).

So for the time-being, we won't implement `Function` for
`DynamicFunctionMut`. It will be better to evaluate it on its own. And
we may even consider the possibility of removing it altogether if it
adds too much complexity to the crate.

### Dynamic vs Concrete

One of the issues with `DynamicFunction` is the fact that it's both a
dynamic representation (like `DynamicStruct` or `DynamicList`) and the
only way to represent a function.

Because of this, it's in a weird middle ground where we can't easily
implement full-on `Reflect`. That would require `Typed`, but what static
`TypeInfo` could it provide? Just that it's a `DynamicFunction`? None of
the other dynamic types implement `Typed`.

However, by not implementing `Reflect`, we lose the ability to downcast
back to our `DynamicStruct`. Our only option is to call
`Function::clone_dynamic`, which clones the data rather than by simply
downcasting. This works in favor of the `PartialReflect::try_apply`
implementation since it would have to clone anyways, but is definitely
not ideal. This is also the reason I had to add `Debug` as a supertrait
on `Function`.

For now, this PR chooses not to implement `Reflect` for
`DynamicFunction`. We may want to explore this in a followup PR (or even
this one if people feel strongly that it's strictly required).

The same is true for `FromReflect`. We may decide to add an
implementation there as well, but it's likely out-of-scope of this PR.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```

---

## Showcase

You can now pass around a `DynamicFunction` as a `dyn PartialReflect`!
This also means you can use it as a field on a reflected type without
having to ignore it (though you do need to opt out of `FromReflect`).

```rust
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct ClickEvent {
    callback: DynamicFunction<'static>,
}

let event: Box<dyn Struct> = Box::new(ClickEvent {
    callback: (|| println!("Clicked!")).into_function(),
});

// We can access our `DynamicFunction` as a `dyn PartialReflect`
let callback: &dyn PartialReflect = event.field("callback").unwrap();

// And access function-related methods via the new `Function` trait
let ReflectRef::Function(callback) = callback.reflect_ref() else {
    unreachable!()
};

// Including calling the function
callback.reflect_call(ArgList::new()).unwrap(); // Prints: Clicked!
```
2024-09-22 14:19:12 +00:00
Benjamin Brienen
02a9ed4b0b
move ShortName to bevy_reflect (#15340)
# Objective

- Goal is to minimize bevy_utils #11478

## Solution

- Move the file short_name wholesale into bevy_reflect

## Testing

- Unit tests
- CI

## Migration Guide

- References to `bevy_utils::ShortName` should instead now be
`bevy_reflect::ShortName`.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-21 20:52:46 +00:00
VitalyR
661ab1ab41
Fix warnings triggered by elided_named_lifetimes lint (#15328)
# Objective

Eliminate some warnings introduced by the new rust lint
[elided_named_lifetimes](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/builtin/static.ELIDED_NAMED_LIFETIMES.html),
fix #15326.

## Solution

- Add or remove lifetime markers to not trigger the lint.

## Testing

- When the lint comes to stable, the CI will fail and this PR could fix
that.
2024-09-20 19:17:33 +00:00
Rich Churcher
fd329c0426
Allow to expect (adopted) (#15301)
# Objective

> Rust 1.81 released the #[expect(...)] attribute, which works like
#[allow(...)] but throws a warning if the lint isn't raised. This is
preferred to #[allow(...)] because it tells us when it can be removed.

- Adopts the parts of #15118 that are complete, and updates the branch
so it can be merged.
- There were a few conflicts, let me know if I misjudged any of 'em.

Alice's
[recommendation](https://github.com/bevyengine/bevy/issues/15059#issuecomment-2349263900)
seems well-taken, let's do this crate by crate now that @BD103 has done
the lion's share of this!

(Relates to, but doesn't yet completely finish #15059.)

Crates this _doesn't_ cover:

- bevy_input
- bevy_gilrs
- bevy_window
- bevy_winit
- bevy_state
- bevy_render
- bevy_picking
- bevy_core_pipeline
- bevy_sprite
- bevy_text
- bevy_pbr
- bevy_ui
- bevy_gltf
- bevy_gizmos
- bevy_dev_tools
- bevy_internal
- bevy_dylib

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
Co-authored-by: Antony <antony.m.3012@gmail.com>
2024-09-20 19:16:42 +00:00
Gino Valente
ebb57c5511
bevy_reflect: Add FunctionRegistry::call (#15148)
# Objective

There may be times where a function in the `FunctionRegistry` doesn't
need to be fully retrieved. A user may just need to call it with a set
of arguments.

We should provide a shortcut for doing this.

## Solution

Add the `FunctionRegistry::call` method to directly call a function in
the registry with the given name and arguments.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```
2024-09-20 19:14:57 +00:00
Zachary Harrold
fcfa60844a
Remove allocation in get_short_name (#15294)
`ShortName` is lazily evaluated and does not allocate, instead providing
`Display` and `Debug` implementations which write directly to a
formatter using the original algorithm. When using `ShortName` in format
strings (`panic`, `dbg`, `format`, etc.) you can directly use the
`ShortName` type. If you require a `String`, simply call
`ShortName(...).to_string()`.

# Objective

- Remove the requirement for allocation when using `get_short_name`

## Solution

- Added new type `ShortName` which wraps a name and provides its own
`Debug` and `Display` implementations, using the original
`get_short_name` algorithm without the need for allocating.
- Removed `get_short_name`, as `ShortName(...)` is more performant and
ergonomic.
- Added `ShortName::of::<T>` method to streamline the common use-case
for name shortening.

## Testing

- CI

## Migration Guide

### For `format!`, `dbg!`, `panic!`, etc.

```rust
// Before
panic!("{} is too short!", get_short_name(name));

// After
panic!("{} is too short!", ShortName(name));
```

### Need a `String` Value

```rust
// Before
let short: String = get_short_name(name);

// After
let short: String = ShortName(name).to_string();
```

## Notes

`ShortName` lazily evaluates, and directly writes to a formatter via
`Debug` and `Display`, which removes the need to allocate a `String`
when printing a shortened type name. Because the implementation has been
moved into the `fmt` method, repeated printing of the `ShortName` type
may be less performant than converting it into a `String`. However, no
instances of this are present in Bevy, and the user can get the original
behaviour by calling `.to_string()` at no extra cost.

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-09-19 15:34:03 +00:00
Gino Valente
69541462c5
bevy_reflect: Add Reflectable trait (#5772)
# Objective

When deriving `Reflect`, users will notice that their generic arguments
also need to implement `Reflect`:

```rust
#[derive(Reflect)]
struct Foo<T: Reflect> {
  value: T
}
```

This works well for now. However, as we want to do more with `Reflect`,
these bounds might need to change. For example, to get #4154 working, we
likely need to enforce the `GetTypeRegistration` trait. So now we have:

```rust
#[derive(Reflect)]
struct Foo<T: Reflect + GetTypeRegistration> {
  value: T
}
```

Not great, but not horrible. However, we might then want to do something
as suggested in
[this](https://github.com/bevyengine/bevy/issues/5745#issuecomment-1221389131)
comment and add a `ReflectTypeName` trait for stable type name support.
Well now we have:

```rust
#[derive(Reflect)]
struct Foo<T: Reflect + GetTypeRegistration + ReflectTypeName> {
  value: T
}
```

Now imagine that for even two or three generic types. Yikes!

As the API changes it would be nice if users didn't need to manually
migrate their generic type bounds like this.

A lot of these traits are (or will/might be) core to the entire
reflection API. And although `Reflect` can't add them as supertraits for
object-safety reasons, they are still indirectly required for things to
function properly (manual implementors will know how easy it is to
forget to implement `GetTypeRegistration`). And they should all be
automatically implemented for user types anyways as long they're using
`#[derive(Reflect)]`.

## Solution

Add a "catch-all" trait called `Reflectable` whose supertraits are a
select handful of core reflection traits.

This allows us to consolidate all the examples above into this:

```rust
#[derive(Reflect)]
struct Foo<T: Reflectable> {
  value: T
}
```

And as we experiment with the API, users can rest easy knowing they
don't need to migrate dozens upon dozens of types. It should all be
automatic!

## Discussion

1. Thoughts on the name `Reflectable`? Is it too easily confused with
`Reflect`? Or does it at least accurately describe that this contains
the core traits? If not, maybe `BaseReflect`?

---

## Changelog

- Added the `Reflectable` trait

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-09-18 00:36:41 +00:00
Wybe Westra
612731edfb
Add DynamicTyped link to TypeInfo docs (#15188) (#15259)
Also added a bit to the paragraph to explain when to use the new
function.
Fixes #15188.
2024-09-17 19:27:26 +00:00
Al M.
2ea51fc60f
Use FromReflect when extracting entities in dynamic scenes (#15174)
# Objective

Fix #10284.

## Solution

When `DynamicSceneBuilder` extracts entities, they are cloned via
`PartialReflect::clone_value`, making them into dynamic versions of the
original components. This loses any custom `ReflectSerialize` type data.
Dynamic scenes are deserialized with the original types, not the dynamic
versions, and so any component with a custom serialize may fail. In this
case `Rect` and `Vec2`. The dynamic version includes the field names 'x'
and 'y' but the `Serialize` impl doesn't, hence the "expect float"
error.

The solution here: Instead of using `clone_value` to clone the
components, `FromReflect` clones and retains the original information
needed to serialize with any custom `Serialize` impls. I think using
something like `reflect_clone` from
(https://github.com/bevyengine/bevy/pull/13432) might make this more
efficient.

I also did the same when deserializing dynamic scenes to appease some of
the round-trip tests which use `ReflectPartialEq`, which requires the
types be the same and not a unique/proxy pair. I'm not sure it's
otherwise necessary. Maybe this would also be more efficient when
spawning dynamic scenes with `reflect_clone` instead of `FromReflect`
again?

An alternative solution would be to fall back to the dynamic version
when deserializing `DynamicScene`s if the custom version fails. I think
that's possible. Or maybe simply always deserializing via the dynamic
route for dynamic scenes?

## Testing

This example is similar to the original test case in #10284:

``` rust
#![allow(missing_docs)]

use bevy::{prelude::*, scene::SceneInstanceReady};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, (save, load).chain())
        .observe(check)
        .run();
}

static SAVEGAME_SAVE_PATH: &str = "savegame.scn.ron";

fn save(world: &mut World) {
    let entity = world.spawn(OrthographicProjection::default()).id();

    let scene = DynamicSceneBuilder::from_world(world)
        .extract_entity(entity)
        .build();

    if let Some(registry) = world.get_resource::<AppTypeRegistry>() {
        let registry = registry.read();
        let serialized_scene = scene.serialize(&registry).unwrap();
        // println!("{}", serialized_scene);
        std::fs::write(format!("assets/{SAVEGAME_SAVE_PATH}"), serialized_scene).unwrap();
    }

    world.entity_mut(entity).despawn_recursive();
}

fn load(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(DynamicSceneBundle {
        scene: asset_server.load(SAVEGAME_SAVE_PATH),
        ..default()
    });
}

fn check(_trigger: Trigger<SceneInstanceReady>, query: Query<&OrthographicProjection>) {
    dbg!(query.single());
}
```


## Migration Guide

The `DynamicScene` format is changed to use custom serialize impls so
old scene files will need updating:

Old: 

```ron
(
  resources: {},
  entities: {
    4294967299: (
      components: {
        "bevy_render:📷:projection::OrthographicProjection": (
          near: 0.0,
          far: 1000.0,
          viewport_origin: (
            x: 0.5,
            y: 0.5,
          ),
          scaling_mode: WindowSize(1.0),
          scale: 1.0,
          area: (
            min: (
              x: -1.0,
              y: -1.0,
            ),
            max: (
              x: 1.0,
              y: 1.0,
            ),
          ),
        ),
      },
    ),
  },
)
```

New:

```ron
(
  resources: {},
  entities: {
    4294967299: (
      components: {
        "bevy_render:📷:projection::OrthographicProjection": (
          near: 0.0,
          far: 1000.0,
          viewport_origin: (0.5, 0.5),
          scaling_mode: WindowSize(1.0),
          scale: 1.0,
          area: (
            min: (-1.0, -1.0),
            max: (1.0, 1.0),
          ),
        ),
      },
    ),
  },
)
```

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-09-15 14:33:39 +00:00
Cole Varner
cf55e6cb22
ParsedPath::try_from<&str> (#15180)
# Objective

- implements ParsedPath::try_from<&str>
- resolves #14438

## Testing

- Added unit test for ParsedPath::try_from<&str>

Note: I don't claim to be an expert on lifetimes! That said I think it
makes sense that the error shares a lifetime with input string as deeper
down it is used to construct it.
2024-09-13 17:37:09 +00:00
Gino Valente
37443e0f3f
bevy_reflect: Add DynamicTyped trait (#15108)
# Objective

Thanks to #7207, we now have a way to validate at the type-level that a
reflected value is actually the type it says it is and not just a
dynamic representation of that type.

`dyn PartialReflect` values _might_ be a dynamic type, but `dyn Reflect`
values are guaranteed to _not_ be a dynamic type.

Therefore, we can start to add methods to `Reflect` that weren't really
possible before. For example, we should now be able to always get a
`&'static TypeInfo`, and not just an `Option<&'static TypeInfo>`.

## Solution

Add the `DynamicTyped` trait.

This trait is similar to `DynamicTypePath` in that it provides a way to
use the non-object-safe `Typed` trait in an object-safe way.

And since all types that derive `Reflect` will also derive `Typed`, we
can safely add `DynamicTyped` as a supertrait of `Reflect`. This allows
us to use it when just given a `dyn Reflect` trait object.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect
```

---

## Showcase

`Reflect` now has a supertrait of `DynamicTyped`, allowing `TypeInfo` to
be retrieved from a `dyn Reflect` trait object without having to unwrap
anything!

```rust
let value: Box<dyn Reflect> = Box::new(String::from("Hello!"));

// BEFORE
let info: &'static TypeInfo = value.get_represented_type_info().unwrap();

// AFTER
let info: &'static TypeInfo = value.reflect_type_info();
```

## Migration Guide

`Reflect` now has a supertrait of `DynamicTyped`. If you were manually
implementing `Reflect` and did not implement `Typed`, you will now need
to do so.
2024-09-13 17:17:10 +00:00
mamekoro
15e246eff8
Fix typo in bevy_reflect/src/reflect.rs (#15157)
Corrected a typo "enumuration" to "enumeration".
2024-09-11 21:51:17 +00:00
Gino Valente
75343ef584
bevy_reflect: Mention FunctionRegistry in bevy_reflect::func docs (#15147)
# Objective

The module docs for `bevy_reflect::func` don't mention the
`FunctionRegistry`.

## Solution

Add a section about the `FunctionRegistry` to the module-level
documentation.

## Testing

You can test locally by running:

```
cargo test --doc --package bevy_reflect --all-features
```
2024-09-10 23:39:05 +00:00
Gino Valente
90bb1adeb2
bevy_reflect: Contextual serialization error messages (#13888)
# Objective

Reflection serialization can be difficult to debug. A lot of times a
type fails to be serialized and the user is left wondering where that
type came from.

This is most often encountered with Bevy's scenes. Attempting to
serialize all resources in the world will fail because some resources
can't be serialized.

For example, users will often get complaints about `bevy_utils::Instant`
not registering `ReflectSerialize`. Well, `Instant` can't be serialized,
so the only other option is to exclude the resource that contains it.
But what resource contains it? This is where reflection serialization
can get a little tricky (it's `Time<Real>` btw).

## Solution

Add the `debug_stack` feature to `bevy_reflect`. When enabled, the
reflection serializers and deserializers will keep track of the current
type stack. And this stack will be used in error messages to help with
debugging.

Now, if we unknowingly try to serialize `Time<Real>`, we'll get the
following error:

```
type `bevy_utils::Instant` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `bevy_time::time::Time<bevy_time::real::Real>` -> `bevy_time::real::Real` -> `bevy_utils::Instant`)
```

### Implementation

This makes use of `thread_local!` to manage an internal `TypeInfoStack`
which holds a stack of `&'static TypeInfo`. We push to the stack before
a type is (de)serialized and pop from the stack afterwards.

Using a thread-local should be fine since we know two (de)serializers
can't be running at the same time (and if they're running on separate
threads, then we're still good).

The only potential issue would be if a user went through one of the
sub-serializers, like `StructSerializer`. However, I don't think many
users are going through these types (I don't even know if we necessarily
want to keep those public either, but we'll save that for a different
PR). Additionally, this is just a debug feature that only affects error
messages, so it wouldn't have any drastically negative effect. It would
just result in the stack not being cleared properly if there were any
errors.

Lastly, this is not the most performant implementation since we now
fetch the `TypeInfo` an extra time. But I figured that for a debug tool,
it wouldn't matter too much.

### Feature

This also adds a `debug` feature, which enables the `debug_stack`
feature.

I added it because I think we may want to potentially add more debug
tools in the future, and this gives us a good framework for adding
those. Users who want all debug features, present and future, can just
set `debug`. If they only want this feature, then they can just use
`debug_stack`.

I also made the `debug` feature default to help capture the widest
audience (i.e. the users who want this feature but don't know they do).
However, if we think it's better as a non-default feature, I can change
it!

And if there's any bikeshedding around the name `debug_stack`, let me
know!

## Testing

Run the following command:

```
cargo test --package bevy_reflect --features debug_stack
```

---

## Changelog

- Added the `debug` and `debug_stack` features to `bevy_reflect`
- Updated the error messages returned by the reflection serializers and
deserializers to include more contextual information when the
`debug_stack` or `debug` feature is enabled
2024-09-09 17:52:40 +00:00
Gino Valente
245d03a78a
bevy_reflect: Update on_unimplemented attributes (#15110)
# Objective

Some of the new compile error messages are a little unclear (at least to
me). For example:

```
error[E0277]: `tests::foo::Bar` can not be created through reflection
   --> crates/bevy_reflect/src/lib.rs:679:18
    |
679 |         #[derive(Reflect)]
    |                  ^^^^^^^ the trait `from_reflect::FromReflect` is not implemented for `tests::foo::Bar`
    |
    = note: consider annotating `tests::foo::Bar` with `#[derive(Reflect)]` or `#[derive(FromReflect)]`
```

While the annotation makes it clear that `FromReflect` is missing, it's
not very clear from the main error message.

My IDE lists errors with only their message immediately present:

<p align="center">
<img width="700" alt="Image of said IDE listing errors with only their
message immediately present. These errors are as follows:
\"`tests::foo::Bar` can not be created through reflection\", \"The trait
bound `tests::foo::Bar: RegisterForReflection` is not satisfied\", and
\"The trait bound `tests::foo::Bar: type_info::MaybeTyped` is not
satisfied\""
src="https://github.com/user-attachments/assets/42c24051-9e8e-4555-8477-51a9407446aa">
</p>

This makes it hard to tell at a glance why my code isn't compiling.

## Solution

Updated all `on_unimplemented` attributes in `bevy_reflect` to mention
the relevant trait—either the actual trait or the one users actually
need to implement—as well as a small snippet of what not implementing
them means.

For example, failing to implement `TypePath` now mentions missing a
`TypePath` implementation. And failing to implement `DynamicTypePath`
now also mentions missing a `TypePath` implementation, since that's the
actual trait users need to implement (i.e. they shouldn't implement
`DynamicTypePath` directly).

Lastly, I also added some missing `on_unimplemented` attributes for
`MaybeTyped` and `RegisterForReflection` (which you can see in the image
above).

Here's how this looks in my IDE now:

<p align="center">
<img width="700" alt="Similar image as before showing the errors listed
by the IDE. This time the errors read as follows: \"`tests::foo::Bar`
does not implement `FromReflect` so cannot be reified through
reflection\", \"`tests::foo::Bar` does not implement
`GetTypeRegistration` so cannot be registered for reflection\", and
\"`tests::foo::Bar` does not implement `Typed` so cannot provide static
type information\""
src="https://github.com/user-attachments/assets/f6f8501f-0450-4f78-b84f-00e7a18d0533">
</p>


## Testing

You can test by adding the following code and verifying the compile
errors are correct:

```rust
#[derive(Reflect)]
struct Foo(Bar);

struct Bar;
```
2024-09-09 16:26:17 +00:00
Christian Hughes
e939d6c33f
Remove remnant EntityHash and related types from bevy_utils (#15039)
# Objective

`EntityHash` and related types were moved from `bevy_utils` to
`bevy_ecs` in #11498, but seemed to have been accidentally reintroduced
a week later in #11707.

## Solution

Remove the old leftover code.

---

## Migration Guide

- Uses of `bevy::utils::{EntityHash, EntityHasher, EntityHashMap,
EntityHashSet}` now have to be imported from `bevy::ecs::entity`.
2024-09-09 15:24:17 +00:00
Gino Valente
ba3d9b3fb6
bevy_reflect: Refactor serde module (#15107)
# Objective

The `ser` and `de` modules in `bevy_reflect/serde` are very long and
difficult to navigate.

## Solution

Refactor both modules into many smaller modules that each have a single
primary focus (i.e. a `structs` module that only handles struct
serialization/deserialization).

I chose to keep the `ser` and `de` modules separate. We could have
instead broken it up kind (e.g. lists, maps, etc.), but I think this is
a little cleaner. Serialization and deserialization, while related, can
be very different. So keeping them separated makes sense for
organizational purposes.

That being said, if people disagree and think we should structure this a
different way, I am open to changing it.

Note that this PR's changes are mainly structural. There are a few
places I refactored code to reduce duplication and to make things a bit
cleaner, but these are largely cosmetic and shouldn't have any impact on
behavior.

### Other Details

This PR also hides a lot of the internal logic from being exported.
These were originally public, but it's unlikely they really saw any use
outside of these modules. In fact, you don't really gain anything by
using them outside of this module either.

By privatizing these fields and items, we also set ourselves up for more
easily changing internal logic around without involving a breaking
change.

I also chose not to mess around with tests since that would really blow
up the diff haha.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```

---

## Migration Guide

The fields on `ReflectSerializer` and `TypedReflectSerializer` are now
private. To instantiate, the corresponding constructor must be used:

```rust
// BEFORE
let serializer = ReflectSerializer {
    value: &my_value,
    registry: &type_registry,
};

// AFTER
let serializer = ReflectSerializer::new(&my_value, &type_registry);
```

Additionally, the following types are no longer public:

- `ArraySerializer`
- `EnumSerializer`
- `ListSerializer`
- `MapSerializer`
- `ReflectValueSerializer` (fully removed)
- `StructSerializer`
- `TupleSerializer`
- `TupleStructSerializer`

As well as the following traits:

- `DeserializeValue` (fully removed)
2024-09-09 14:03:42 +00:00
BD103
6ec6a55645
Unify crate-level preludes (#15080)
# Objective

- Crate-level prelude modules, such as `bevy_ecs::prelude`, are plagued
with inconsistency! Let's fix it!

## Solution

Format all preludes based on the following rules:

1. All preludes should have brief documentation in the format of:
   > The _name_ prelude.
   >
> This includes the most common types in this crate, re-exported for
your convenience.
2. All documentation should be outer, not inner. (`///` instead of
`//!`.)
3. No prelude modules should be annotated with `#[doc(hidden)]`. (Items
within them may, though I'm not sure why this was done.)

## Testing

- I manually searched for the term `mod prelude` and updated all
occurrences by hand. 🫠

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-09-08 17:10:57 +00:00
Zachary Harrold
547b1c7a7a
Reflect SmolStr's De/Serialize implementation (#14982)
# Objective

- Fixes #14969

## Solution

- Added `Deserialize` to the list of reflected traits for `SmolStr`

## Testing

- CI passed locally.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-09-02 22:35:17 +00:00
Zachary Harrold
bc13161416
Migrated NonZero* to NonZero<*> (#14978)
# Objective

- Fixes #14974

## Solution

- Replace all* instances of `NonZero*` with `NonZero<*>`

## Testing

- CI passed locally.

---

## Notes

Within the `bevy_reflect` implementations for `std` types,
`impl_reflect_value!()` will continue to use the type aliases instead,
as it inappropriately parses the concrete type parameter as a generic
argument. If the `ZeroablePrimitive` trait was stable, or the macro
could be modified to accept a finite list of types, then we could fully
migrate.
2024-08-30 02:37:47 +00:00
Zachary Harrold
44620dd6ae
Split GenericTypeCell::get_or_insert into smaller pieces (#14865)
# Objective

Based on the discussion in #14864, I wanted to experiment with the core
`GenericTypeCell` type, whose `get_or_insert` method accounted for 2% of
the final binary size of the `3d_scene` example. The reason for this
large percentage is likely because the type is fundamental to the rest
of Bevy while having 3 generic parameters (the type stored `T`, the type
to retrieve `G`, and the function used to insert a new value `F`).

- Acts on #14864 

## Solution

- Split `get_or_insert` into smaller functions with minimised
parameterisation. These new functions are private as to preserve the
public facing API, but could be exposed if desired.

## Testing

- Ran CI locally.
- Used `cargo bloat --release --example 3d_scene -n 100000
--message-format json > out.json` and @cart's [bloat
analyzer](https://gist.github.com/cart/722756ba3da0e983d207633e0a48a8ab)
to measure a 428KiB reduction in binary size when compiling on Windows
10.
- ~I have _not_ benchmarked to determine if this improves/hurts
performance.~ See
[below](https://github.com/bevyengine/bevy/pull/14865#issuecomment-2306083606).

## Notes

In my opinion this seems like a good test-case for the concept of
debloating generics within the Bevy codebase. I believe the performance
impact here is negligible in either direction (at runtime and compile
time), but the binary reduction is measurable and quite significant for
a relatively minor change in code.

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-08-26 18:20:01 +00:00
Gino Valente
3892adcb47
bevy_reflect: Add Type type (#14838)
# Objective

Closes #7622.

I was working on adding support for reflecting generic functions and
found that I wanted to use an argument's `TypeId` for hashing and
comparison, but its `TypePath` for debugging and error messaging.

While I could just keep them separate, place them in a tuple or a local
struct or something, I think I see an opportunity to make a dedicate
type for this.

Additionally, we can use this type to clean up some duplication amongst
the type info structs in a manner similar to #7622.

## Solution

Added the `Type` type. This should be seen as the most basic
representation of a type apart from `TypeId`. It stores both the
`TypeId` of the type as well as its `TypePathTable`.

The `Hash` and `PartialEq` implementations rely on the `TypeId`, while
the `Debug` implementation relies on the `TypePath`.

This makes it especially useful as a key in a `HashMap` since we get the
speed of the `TypeId` hashing/comparisons with the readability of
`TypePath`.

With this type, we're able to reduce the duplication across the type
info structs by removing individual fields for `TypeId` and
`TypePathTable`, replacing them with a single `Type` field. Similarly,
we can remove many duplicate methods and replace it with a macro that
delegates to the stored `Type`.

### Caveats

It should be noted that this type is currently 3x larger than `TypeId`.
On my machine, it's 48 bytes compared to `TypeId`'s 16. While this
doesn't matter for `TypeInfo` since it would contain that data
regardless, it is something to keep in mind when using elsewhere.

## Testing

All tests should pass as normal:

```
cargo test --package bevy_reflect
```

---

## Showcase

`bevy_reflect` now exports a `Type` struct. This type contains both the
`TypeId` and the `TypePathTable` of the given type, allowing it to be
used like `TypeId` but have the debuggability of `TypePath`.

```rust
// We can create this for any type implementing `TypePath`:
let ty = Type::of::<String>();

// It has `Hash` and `Eq` impls powered by `TypeId`, making it useful for maps:
let mut map = HashMap::<Type, i32>::new();
map.insert(ty, 25);

// And it has a human-readable `Debug` representation:
let debug = format!("{:?}", map);
assert_eq!(debug, "{alloc::string::String: 25}");
```

## Migration Guide

Certain type info structs now only return their item types as `Type`
instead of exposing direct methods on them.

The following methods have been removed:

- `ArrayInfo::item_type_path_table`
- `ArrayInfo::item_type_id`
- `ArrayInfo::item_is`
- `ListInfo::item_type_path_table`
- `ListInfo::item_type_id`
- `ListInfo::item_is`
- `SetInfo::value_type_path_table`
- `SetInfo::value_type_id`
- `SetInfo::value_is`
- `MapInfo::key_type_path_table`
- `MapInfo::key_type_id`
- `MapInfo::key_is`
- `MapInfo::value_type_path_table`
- `MapInfo::value_type_id`
- `MapInfo::value_is`

Instead, access the `Type` directly using one of the new methods:

- `ArrayInfo::item_ty`
- `ListInfo::item_ty`
- `SetInfo::value_ty`
- `MapInfo::key_ty`
- `MapInfo::value_ty`

For example:

```rust
// BEFORE
let type_id = array_info.item_type_id();

// AFTER
let type_id = array_info.item_ty().id();
```
2024-08-25 17:57:07 +00:00
Lubba64
f9fbd08f9f
Implement Reflect for std::ops::Bound (#14861)
# Objective

- Fixes #14844

## Solution

- implement reflect using the `impl_reflect_value` macro

## Testing

- I wrote a test locally to understand and learn how reflection worked
on a basic level and to confirm that yes indeed the bound struct could
use the reflection traits that have been implemented for it.

note: I did remove a line that asked for bound to not have reflect
implemented in a test, since that's the point of this PR and the test
worked without the line so I am not sure what that was about, not sure
if that uncovers a deeper issue or not.
2024-08-22 23:01:38 +00:00
EdJoPaTo
938d810766
Apply unused_qualifications lint (#14828)
# Objective

Fixes #14782

## Solution

Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?

Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.

## Testing

`cargo clippy` and `cargo run -p ci` are happy.
2024-08-21 12:29:33 +00:00
Gino Valente
2b4180ca8f
bevy_reflect: Function reflection terminology refactor (#14813)
# Objective

One of the changes in #14704 made `DynamicFunction` effectively the same
as `DynamicClosure<'static>`. This change meant that the de facto
function type would likely be `DynamicClosure<'static>` instead of the
intended `DynamicFunction`, since the former is much more flexible.

We _could_ explore ways of making `DynamicFunction` implement `Copy`
using some unsafe code, but it likely wouldn't be worth it. And users
would likely still reach for the convenience of
`DynamicClosure<'static>` over the copy-ability of `DynamicFunction`.

The goal of this PR is to fix this confusion between the two types.

## Solution

Firstly, the `DynamicFunction` type was removed. Again, it was no
different than `DynamicClosure<'static>` so it wasn't a huge deal to
remove.

Secondly, `DynamicClosure<'env>` and `DynamicClosureMut<'env>` were
renamed to `DynamicFunction<'env>` and `DynamicFunctionMut<'env>`,
respectively.

Yes, we still ultimately kept the naming of `DynamicFunction`, but
changed its behavior to that of `DynamicClosure<'env>`. We need a term
to refer to both functions and closures, and "function" was the best
option.


[Originally](https://discord.com/channels/691052431525675048/1002362493634629796/1274091992162242710),
I was going to go with "callable" as the replacement term to encompass
both functions and closures (e.g. `DynamciCallable<'env>`). However, it
was
[suggested](https://discord.com/channels/691052431525675048/1002362493634629796/1274653581777047625)
by @SkiFire13 that the simpler "function" term could be used instead.

While "callable" is perhaps the better umbrella term—being truly
ambiguous over functions and closures— "function" is more familiar, used
more often, easier to discover, and is subjectively just
"better-sounding".

## Testing

Most changes are purely swapping type names or updating documentation,
but you can verify everything still works by running the following
command:

```
cargo test --package bevy_reflect
```
2024-08-19 21:52:36 +00:00
Gino Valente
423285cf1c
bevy_reflect: Store functions as DynamicClosure<'static> in FunctionRegistry (#14704)
# Objective

#14098 added the `FunctionRegistry` for registering functions such that
they can be retrieved by name and used dynamically. One thing we chose
to leave out in that initial PR is support for closures.

Why support closures? Mainly, we don't want to prohibit users from
injecting environmental data into their registered functions. This
allows these functions to not leak their internals to the public API.

For example, let's say we're writing a library crate that allows users
to register callbacks for certain actions. We want to perform some
actions before invoking the user's callback so we can't just call it
directly. We need a closure for this:

```rust
registry.register("my_lib::onclick", move |event: ClickEvent| {
    // ...other work...

    user_onclick.call(event); // <-- Captured variable
});
```

We could have made our callback take a reference to the user's callback.
This would remove the need for the closure, but it would change our
desired API to place the burden of fetching the correct callback on the
caller.

## Solution

Modify the `FunctionRegistry` to store registered functions as
`DynamicClosure<'static>` instead of `DynamicFunction` (now using
`IntoClosure` instead of `IntoFunction`).

Due to limitations in Rust and how function reflection works,
`DynamicClosure<'static>` is functionally equivalent to
`DynamicFunction`. And a normal function is considered a subset of
closures (it's a closure that doesn't capture anything), so there
shouldn't be any difference in usage: all functions that satisfy
`IntoFunction` should satisfy `IntoClosure`.

This means that the registration API introduced in #14098 should require
little-to-no changes on anyone following `main`.

### Closures vs Functions

One consideration here is whether we should keep closures and functions
separate.

This PR unifies them into `DynamicClosure<'static>`, but we can consider
splitting them up. The reasons we might want to do so are:

- Simplifies mental model and terminology (users don't have to
understand that functions turn into closures)
- If Rust ever improves its function model, we may be able to add
additional guarantees to `DynamicFunction` that make it useful to
separate the two
- Adding support for generic functions may be less confusing for users
since closures in Rust technically can't be generic

The reasons behind this PR's unification approach are:

- Reduces the number of methods needed on `FunctionRegistry`
- Reduces the number of lookups a user may have to perform (i.e.
"`get_function` or else `get_closure`")
- Establishes `DynamicClosure<'static>` as the de facto dynamic callable
(similar to how most APIs in Rust code tend to prefer `impl Fn() ->
String` over `fn() -> String`)

I'd love to hear feedback on this matter, and whether we should continue
with this PR's approach or switch to a split model.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect
```

---

## Showcase

Closures can now be registered into the `FunctionRegistry`:

```rust
let punct = String::from("!!!");

registry.register_with_name("my_crate::punctuate", move |text: String| {
  format!("{}{}", text, punct)
});
```
2024-08-17 00:20:47 +00:00
eckz
a44278aee6
Making DynamicEnum::is_dynamic() return true (#14732)
# Objective

- Right now `DynamicEnum::is_dynamic()` is returning `false`. I don't
think this was expected, since the rest of `Dynamic*` types return
`true`.

## Solution

- Making `DynamicEnum::is_dynamic()` return true

## Testing

- Added an extra unit test to verify that `.is_dynamic()` returns
`true`.
2024-08-15 14:10:52 +00:00