Commit graph

352 commits

Author SHA1 Message Date
Gino Valente
aa241672e1
bevy_reflect: Nested TypeInfo getters (#13321)
# Objective

Right now, `TypeInfo` can be accessed directly from a type using either
`Typed::type_info` or `Reflect::get_represented_type_info`.

However, once that `TypeInfo` is accessed, any nested types must be
accessed via the `TypeRegistry`.

```rust
#[derive(Reflect)]
struct Foo {
  bar: usize
}

let registry = TypeRegistry::default();

let TypeInfo::Struct(type_info) = Foo::type_info() else {
  panic!("expected struct info");
};

let field = type_info.field("bar").unwrap();

let field_info = registry.get_type_info(field.type_id()).unwrap();
assert!(field_info.is::<usize>());;
```

## Solution

Enable nested types within a `TypeInfo` to be retrieved directly.

```rust
#[derive(Reflect)]
struct Foo {
  bar: usize
}

let TypeInfo::Struct(type_info) = Foo::type_info() else {
  panic!("expected struct info");
};

let field = type_info.field("bar").unwrap();

let field_info = field.type_info().unwrap();
assert!(field_info.is::<usize>());;
```

The particular implementation was chosen for two reasons.

Firstly, we can't just store `TypeInfo` inside another `TypeInfo`
directly. This is because some types are recursive and would result in a
deadlock when trying to create the `TypeInfo` (i.e. it has to create the
`TypeInfo` before it can use it, but it also needs the `TypeInfo` before
it can create it). Therefore, we must instead store the function so it
can be retrieved lazily.

I had considered also using a `OnceLock` or something to lazily cache
the info, but I figured we can look into optimizations later. The API
should remain the same with or without the `OnceLock`.

Secondly, a new wrapper trait had to be introduced: `MaybeTyped`. Like
`RegisterForReflection`, this trait is `#[doc(hidden)]` and only exists
so that we can properly handle dynamic type fields without requiring
them to implement `Typed`. We don't want dynamic types to implement
`Typed` due to the fact that it would make the return type
`Option<&'static TypeInfo>` for all types even though only the dynamic
types ever need to return `None` (see #6971 for details).

Users should never have to interact with this trait as it has a blanket
impl for all `Typed` types. And `Typed` is automatically implemented
when deriving `Reflect` (as it is required).

The one downside is we do need to return `Option<&'static TypeInfo>`
from all these new methods so that we can handle the dynamic cases. If
we didn't have to, we'd be able to get rid of the `Option` entirely. But
I think that's an okay tradeoff for this one part of the API, and keeps
the other APIs intact.

## Testing

This PR contains tests to verify everything works as expected. You can
test locally by running:

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

---

## Changelog

### Public Changes

- Added `ArrayInfo::item_info` method
- Added `NamedField::type_info` method
- Added `UnnamedField::type_info` method
- Added `ListInfo::item_info` method
- Added `MapInfo::key_info` method
- Added `MapInfo::value_info` method
- All active fields now have a `Typed` bound (remember that this is
automatically satisfied for all types that derive `Reflect`)

### Internal Changes

- Added `MaybeTyped` trait

## Migration Guide

All active fields for reflected types (including lists, maps, tuples,
etc.), must implement `Typed`. For the majority of users this won't have
any visible impact.

However, users implementing `Reflect` manually may need to update their
types to implement `Typed` if they weren't already.

Additionally, custom dynamic types will need to implement the new hidden
`MaybeTyped` trait.
2024-07-15 00:40:07 +00:00
Gino Valente
e512cb602c
bevy_reflect: TypeInfo casting methods (#13320)
# Objective

There are times when we might know the type of a `TypeInfo` ahead of
time. Or we may have already checked it one way or another.

In such cases, it's a bit cumbersome to have to pattern match every time
we want to access the nested info:

```rust
if let TypeInfo::List(info) = <Vec<i32>>::type_info() {
  // ...
} else {
  panic!("expected list info");
}
```

Ideally, there would be a way to simply perform the cast down to
`ListInfo` since we already know it will succeed.

Or even if we don't, perhaps we just want a cleaner way of exiting a
function early (i.e. with the `?` operator).

## Solution

Taking a bit from
[`mirror-mirror`](https://docs.rs/mirror-mirror/latest/mirror_mirror/struct.TypeDescriptor.html#implementations),
`TypeInfo` now has methods for attempting a cast into the variant's info
type.

```rust
let info = <Vec<i32>>::type_info().as_list().unwrap();
// ...
```

These new conversion methods return a `Result` where the error type is a
new `TypeInfoError` enum.

A `Result` was chosen as the return type over `Option` because if we do
choose to `unwrap` it, the error message will give us some indication of
what went wrong. In other words, it can truly replace those instances
where we were panicking in the `else` case.

### Open Questions

1. Should the error types instead be a struct? I chose an enum for
future-proofing, but right now it only has one error state.
Alternatively, we could make it a reflect-wide casting error so it could
be used for similar methods on `ReflectRef` and friends.
2. I was going to do it in a separate PR but should I just go ahead and
add similar methods to `ReflectRef`, `ReflectMut`, and `ReflectOwned`? 🤔
3. Should we name these `try_as_***` instead of `as_***` since they
return a `Result`?

## Testing

You can test locally by running:

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

---

## Changelog

### Added

- `TypeInfoError` enum
- `TypeInfo::kind` method
- `TypeInfo::as_struct` method
- `TypeInfo::as_tuple_struct` method
- `TypeInfo::as_tuple` method
- `TypeInfo::as_list` method
- `TypeInfo::as_array` method
- `TypeInfo::as_map` method
- `TypeInfo::as_enum` method
- `TypeInfo::as_value` method
- `VariantInfoError` enum
- `VariantInfo::variant_type` method
- `VariantInfo::as_unit_variant` method
- `VariantInfo::as_tuple_variant` method
- `VariantInfo::as_struct_variant` method
2024-07-14 20:10:31 +00:00
Gino Valente
99c9218b56
bevy_reflect: Feature-gate function reflection (#14174)
# Objective

Function reflection requires a lot of macro code generation in the form
of several `all_tuples!` invocations, as well as impls generated in the
`Reflect` derive macro.

Seeing as function reflection is currently a bit more niche, it makes
sense to gate it all behind a feature.

## Solution

Add a `functions` feature to `bevy_reflect`, which can be enabled in
Bevy using the `reflect_functions` feature.

## Testing

You can test locally by running:

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

That should ensure that everything still works with the feature
disabled.

To test with the feature on, you can run:

```
cargo test --package bevy_reflect --features functions
```

---

## Changelog

- Moved function reflection behind a Cargo feature
(`bevy/reflect_functions` and `bevy_reflect/functions`)
- Add `IntoFunction` export in `bevy_reflect::prelude`

## Internal Migration Guide

> [!important]
> Function reflection was introduced as part of the 0.15 dev cycle. This
migration guide was written for developers relying on `main` during this
cycle, and is not a breaking change coming from 0.14.

Function reflection is now gated behind a feature. To use function
reflection, enable the feature:
- If using `bevy_reflect` directly, enable the `functions` feature
- If using `bevy`, enable the `reflect_functions` feature
2024-07-14 15:55:31 +00:00
Giacomo Stevanato
d7080369a7
Fix intra-doc links and make CI test them (#14076)
# Objective

- Bevy currently has lot of invalid intra-doc links, let's fix them!
- Also make CI test them, to avoid future regressions.
- Helps with #1983 (but doesn't fix it, as there could still be explicit
links to docs.rs that are broken)

## Solution

- Make `cargo r -p ci -- doc-check` check fail on warnings (could also
be changed to just some specific lints)
- Manually fix all the warnings (note that in some cases it was unclear
to me what the fix should have been, I'll try to highlight them in a
self-review)
2024-07-11 13:08:31 +00:00
Rob Parrett
3594c4f2f5
Fix doc list indentation (#14225)
# Objective

Fixes #14221

## Solution

Add indentation as suggested.

## Testing

Confirmed that
- This makes Clippy happy with rust beta
- Built docs visually look the same before/after
2024-07-09 01:21:54 +00:00
github-actions[bot]
8df10d2713
Bump Version after Release (#14219)
Bump version after release
This PR has been auto-generated

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
2024-07-08 12:54:08 +00:00
Gino Valente
09d86bfb96
bevy_reflect: Re-enable reflection compile fail tests (#14165)
# Objective

Looks like I accidentally disabled the reflection compile fail tests in
#13152. These should be re-enabled.

## Solution

Re-enable reflection compile fail tests.

## Testing

CI should pass. You can also test locally by navigating to
`crates/bevy_reflect/compile_fail/` and running:

```
cargo test --target-dir ../../../target
```
2024-07-05 20:49:03 +00:00
Lura
856b39d821
Apply Clippy lints regarding lazy evaluation and closures (#14015)
# Objective

- Lazily evaluate
[default](https://rust-lang.github.io/rust-clippy/master/index.html#/unwrap_or_default)~~/[or](https://rust-lang.github.io/rust-clippy/master/index.html#/or_fun_call)~~
values where it makes sense
  - ~~`unwrap_or(foo())` -> `unwrap_or_else(|| foo())`~~
  - `unwrap_or(Default::default())` -> `unwrap_or_default()`
  - etc.
- Avoid creating [redundant
closures](https://rust-lang.github.io/rust-clippy/master/index.html#/redundant_closure),
even for [method
calls](https://rust-lang.github.io/rust-clippy/master/index.html#/redundant_closure_for_method_calls)
  - `map(|something| something.into())` -> `map(Into:into)`

## Solution

- Apply Clippy lints:
-
~~[or_fun_call](https://rust-lang.github.io/rust-clippy/master/index.html#/or_fun_call)~~
-
[unwrap_or_default](https://rust-lang.github.io/rust-clippy/master/index.html#/unwrap_or_default)
-
[redundant_closure_for_method_calls](https://rust-lang.github.io/rust-clippy/master/index.html#/redundant_closure_for_method_calls)
([redundant
closures](https://rust-lang.github.io/rust-clippy/master/index.html#/redundant_closure)
is already enabled)

## Testing

- Tested on Windows 11 (`stable-x86_64-pc-windows-gnu`, 1.79.0)
- Bevy compiles without errors or warnings and examples seem to work as
intended
  - `cargo clippy` 
  - `cargo run -p ci -- compile` 

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-07-01 15:54:40 +00:00
Gino Valente
276dd04001
bevy_reflect: Function reflection (#13152)
# Objective

We're able to reflect types sooooooo... why not functions?

The goal of this PR is to make functions callable within a dynamic
context, where type information is not readily available at compile
time.

For example, if we have a function:

```rust
fn add(left: i32, right: i32) -> i32 {
  left + right
}
```

And two `Reflect` values we've already validated are `i32` types:

```rust
let left: Box<dyn Reflect> = Box::new(2_i32);
let right: Box<dyn Reflect> = Box::new(2_i32);
```

We should be able to call `add` with these values:

```rust
// ?????
let result: Box<dyn Reflect> = add.call_dynamic(left, right);
```

And ideally this wouldn't just work for functions, but methods and
closures too!

Right now, users have two options:

1. Manually parse the reflected data and call the function themselves
2. Rely on registered type data to handle the conversions for them

For a small function like `add`, this isn't too bad. But what about for
more complex functions? What about for many functions?

At worst, this process is error-prone. At best, it's simply tedious.

And this is assuming we know the function at compile time. What if we
want to accept a function dynamically and call it with our own
arguments?

It would be much nicer if `bevy_reflect` could alleviate some of the
problems here.

## Solution

Added function reflection!

This adds a `DynamicFunction` type to wrap a function dynamically. This
can be called with an `ArgList`, which is a dynamic list of
`Reflect`-containing `Arg` arguments. It returns a `FunctionResult`
which indicates whether or not the function call succeeded, returning a
`Reflect`-containing `Return` type if it did succeed.

Many functions can be converted into this `DynamicFunction` type thanks
to the `IntoFunction` trait.

Taking our previous `add` example, this might look something like
(explicit types added for readability):

```rust
fn add(left: i32, right: i32) -> i32 {
  left + right
}

let mut function: DynamicFunction = add.into_function();
let args: ArgList = ArgList::new().push_owned(2_i32).push_owned(2_i32);
let result: Return = function.call(args).unwrap();
let value: Box<dyn Reflect> = result.unwrap_owned();
assert_eq!(value.take::<i32>().unwrap(), 4);
```

And it also works on closures:

```rust
let add = |left: i32, right: i32| left + right;

let mut function: DynamicFunction = add.into_function();
let args: ArgList = ArgList::new().push_owned(2_i32).push_owned(2_i32);
let result: Return = function.call(args).unwrap();
let value: Box<dyn Reflect> = result.unwrap_owned();
assert_eq!(value.take::<i32>().unwrap(), 4);
```

As well as methods:

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

impl Foo {
  fn add(&mut self, value: i32) {
    self.0 += value;
  }
}

let mut foo = Foo(2);

let mut function: DynamicFunction = Foo::add.into_function();
let args: ArgList = ArgList::new().push_mut(&mut foo).push_owned(2_i32);
function.call(args).unwrap();
assert_eq!(foo.0, 4);
```

### Limitations

While this does cover many functions, it is far from a perfect system
and has quite a few limitations. Here are a few of the limitations when
using `IntoFunction`:

1. The lifetime of the return value is only tied to the lifetime of the
first argument (useful for methods). This means you can't have a
function like `(a: i32, b: &i32) -> &i32` without creating the
`DynamicFunction` manually.
2. Only 15 arguments are currently supported. If the first argument is a
(mutable) reference, this number increases to 16.
3. Manual implementations of `Reflect` will need to implement the new
`FromArg`, `GetOwnership`, and `IntoReturn` traits in order to be used
as arguments/return types.

And some limitations of `DynamicFunction` itself:

1. All arguments share the same lifetime, or rather, they will shrink to
the shortest lifetime.
2. Closures that capture their environment may need to have their
`DynamicFunction` dropped before accessing those variables again (there
is a `DynamicFunction::call_once` to make this a bit easier)
3. All arguments and return types must implement `Reflect`. While not a
big surprise coming from `bevy_reflect`, this implementation could
actually still work by swapping `Reflect` out with `Any`. Of course,
that makes working with the arguments and return values a bit harder.
4. Generic functions are not supported (unless they have been manually
monomorphized)

And general, reflection gotchas:

1. `&str` does not implement `Reflect`. Rather, `&'static str`
implements `Reflect` (the same is true for `&Path` and similar types).
This means that `&'static str` is considered an "owned" value for the
sake of generating arguments. Additionally, arguments and return types
containing `&str` will assume it's `&'static str`, which is almost never
the desired behavior. In these cases, the only solution (I believe) is
to use `&String` instead.

### Followup Work

This PR is the first of two PRs I intend to work on. The second PR will
aim to integrate this new function reflection system into the existing
reflection traits and `TypeInfo`. The goal would be to register and call
a reflected type's methods dynamically.

I chose not to do that in this PR since the diff is already quite large.
I also want the discussion for both PRs to be focused on their own
implementation.

Another followup I'd like to do is investigate allowing common container
types as a return type, such as `Option<&[mut] T>` and `Result<&[mut] T,
E>`. This would allow even more functions to opt into this system. I
chose to not include it in this one, though, for the same reasoning as
previously mentioned.

### Alternatives

One alternative I had considered was adding a macro to convert any
function into a reflection-based counterpart. The idea would be that a
struct that wraps the function would be created and users could specify
which arguments and return values should be `Reflect`. It could then be
called via a new `Function` trait.

I think that could still work, but it will be a fair bit more involved,
requiring some slightly more complex parsing. And it of course is a bit
more work for the user, since they need to create the type via macro
invocation.

It also makes registering these functions onto a type a bit more
complicated (depending on how it's implemented).

For now, I think this is a fairly simple, yet powerful solution that
provides the least amount of friction for users.

---

## Showcase

Bevy now adds support for storing and calling functions dynamically
using reflection!

```rust
// 1. Take a standard Rust function
fn add(left: i32, right: i32) -> i32 {
  left + right
}

// 2. Convert it into a type-erased `DynamicFunction` using the `IntoFunction` trait
let mut function: DynamicFunction = add.into_function();
// 3. Define your arguments from reflected values
let args: ArgList = ArgList::new().push_owned(2_i32).push_owned(2_i32);
// 4. Call the function with your arguments
let result: Return = function.call(args).unwrap();
// 5. Extract the return value
let value: Box<dyn Reflect> = result.unwrap_owned();
assert_eq!(value.take::<i32>().unwrap(), 4);
```

## Changelog

#### TL;DR

- Added support for function reflection
- Added a new `Function Reflection` example:
ba727898f2/examples/reflection/function_reflection.rs (L1-L157)

#### Details

Added the following items:

- `ArgError` enum
- `ArgId` enum
- `ArgInfo` struct
- `ArgList` struct
- `Arg` enum
- `DynamicFunction` struct
- `FromArg` trait (derived with `derive(Reflect)`)
- `FunctionError` enum
- `FunctionInfo` struct
- `FunctionResult` alias
- `GetOwnership` trait (derived with `derive(Reflect)`)
- `IntoFunction` trait (with blanket implementation)
- `IntoReturn` trait (derived with `derive(Reflect)`)
- `Ownership` enum
- `ReturnInfo` struct
- `Return` enum

---------

Co-authored-by: Periwink <charlesbour@gmail.com>
2024-07-01 13:49:08 +00:00
Gino Valente
53910e07ae
bevy_reflect: Improve reflection serialization error messages (#13867)
# Objective

The error messages that appear when a value cannot be serialized or
deserialized via reflection could be slightly improved.

When one of these operations fails, some users are confused about how to
resolve the issue. I've spoken with a few who didn't know they could
register `ReflectSerialize` themselves. We should try to clarify this to
some degree in the error messages.

## Solution

Add some more detail to the error messages.

For example, replacing this:

```
Type 'core::ops::RangeInclusive<f32>' did not register ReflectSerialize
```

with this:

```
Type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data`
```

I also added a separate error message if the type was not registered in
the type registry at all:

```
Type `core::ops::RangeInclusive<f32>` is not registered in the type registry
```

## Testing

You can test locally by running:

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

---

## Changelog

- Added error message for missing type registration when serializing
reflect data
- Changed error message for missing `ReflectSerialize` registration when
serializing reflect data
- Changed error message for missing `ReflectDeserialize` registration
when deserializing reflect data
2024-06-17 18:13:46 +00:00
Jan Hohenheim
6273227e09
Fix lints introduced in Rust beta 1.80 (#13899)
Resolves #13895

Mostly just involves being more explicit about which parts of the docs
belong to a list and which begin a new paragraph.
- found a few docs that were malformed because of exactly this, so I
fixed that by introducing a paragraph
- added indentation to nearly all multiline lists
- fixed a few minor typos
- added `#[allow(dead_code)]` to types that are needed to test
annotations but are never constructed
([here](https://github.com/bevyengine/bevy/pull/13899/files#diff-b02b63604e569c8577c491e7a2030d456886d8f6716eeccd46b11df8aac75dafR1514)
and
[here](https://github.com/bevyengine/bevy/pull/13899/files#diff-b02b63604e569c8577c491e7a2030d456886d8f6716eeccd46b11df8aac75dafR1523))
- verified that  `cargo +beta run -p ci -- lints` passes
- verified that `cargo +beta run -p ci -- test` passes
2024-06-17 17:22:01 +00:00
Wuketuke
d45bcfd043
improved the error message by insert_boxed (issue #13646) (again) (#13706)
previously I worked on fixing issue #13646, back when the error message
did not include the type at all.
But that error message had room for improvement, so I included the
feedback of @alice-i-cecile and @MrGVSV.
The error message will now read `the given key (of type
bevy_reflect::tests::Foo) does not support hashing` or 'the given key
(of type bevy_reflect::DynamicStruct) does not support hashing' in case
of a dynamic struct that represents a hashable struct

i also added a new unit test for this new behaviour
(`reflect_map_no_hash_dynamic`).
Fixes #13646 (again)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-06-07 20:56:16 +00:00
Wuketuke
2eb9d5cc38
hashing error in bevy_reflect now includes the type (bevyengine#13646) (#13691)
# Objective
If you try to add an object to the hashmap that is not capable of
hashing, the program panics. For easier debugging, the type for that
object should be included in the error message.

Fixes #13646.

## Solution
initially i tried calling std::any::type_name_of_val. this had the
problem that it would print something like dyn Box<dyn Reflect>, not
helpful. But since these objects all implement Reflect, i used
Reflect::type_path() instead. Previously, the error message was part of
a constant called HASH_ERROR. i changed that to a macro called
hash_error to print the type of that object more easily

## Testing
i adapted the unit test reflect_map_no_hash to expect the type in that
panic aswell

since this is my first contribution, please let me know if i have done
everything properly
2024-06-05 19:41:23 +00:00
Alice Cecile
ec7b3490f6
Add on_unimplemented Diagnostics to Most Public Traits (#13347) (#13662)
# Objective

- #13414 did not have the intended effect.
- #13404 is still blocked

## Solution

- Re-adds #13347.

Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Co-authored-by: Jamie Ridding <Themayu@users.noreply.github.com>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-06-04 00:31:34 +00:00
Olle Lukowski
8c7f73ab81
Move bevy_math Reflect impls (#13520)
# Objective

Fixes #13456 

## Solution

Moved `bevy_math`'s `Reflect` impls from `bevy_reflect` to `bevy_math`.


### Quick note
I accidentally used the same commit message while resolving a merge
conflict (first time I had to resolve a conflict). Sorry about that.
2024-05-27 14:15:22 +00:00
Salvador Carvalhinho
7d843e0c08
Implement Rhombus 2D primitive. (#13501)
# Objective

- Create a new 2D primitive, Rhombus, also knows as "Diamond Shape"
- Simplify the creation and handling of isometric projections
- Extend Bevy's arsenal of 2D primitives

## Testing

- New unit tests created in bevy_math/ primitives and bev_math/ bounding
- Tested translations, rotations, wireframe, bounding sphere, aabb and
creation parameters

---------

Co-authored-by: Luís Figueiredo <luispcfigueiredo@tecnico.ulisboa.pt>
2024-05-26 15:27:57 +00:00
Gino Valente
faf003fc9d
bevy_reflect: enum_utility cleanup (#13424)
# Objective

The `enum_utility` module contains the `get_variant_constructors`
function, which is used to generate token streams for constructing
enums. It's used for the `FromReflect::from_reflect` implementation and
the `Reflect::try_apply` implementation.

Due to the complexity of enums, this function is understandably a little
messy and difficult to extend.

## Solution

Clean up the `enum_utility` module.

Now "clean" is a bit subjective. I believe my solution is "cleaner" in
that the logic to generate the tokens are strictly coupled with the
intended usage. Because of this, `try_apply` is also no longer strictly
coupled with `from_reflect`.

This makes it easier to extend with new functionality, which is
something I'm doing in a future unrelated PR that I have based off this
one.

## Testing

There shouldn't be any testing required other than ensuring that the
project still builds and that CI passes.
2024-05-22 21:18:57 +00:00
Gino Valente
5db52663b3
bevy_reflect: Custom attributes (#11659)
# Objective

As work on the editor starts to ramp up, it might be nice to start
allowing types to specify custom attributes. These can be used to
provide certain functionality to fields, such as ranges or controlling
how data is displayed.

A good example of this can be seen in
[`bevy-inspector-egui`](https://github.com/jakobhellermann/bevy-inspector-egui)
with its
[`InspectorOptions`](https://docs.rs/bevy-inspector-egui/0.22.1/bevy_inspector_egui/struct.InspectorOptions.html):

```rust
#[derive(Reflect, Default, InspectorOptions)]
#[reflect(InspectorOptions)]
struct Slider {
    #[inspector(min = 0.0, max = 1.0)]
    value: f32,
}
```

Normally, as demonstrated in the example above, these attributes are
handled by a derive macro and stored in a corresponding `TypeData`
struct (i.e. `ReflectInspectorOptions`).

Ideally, we would have a good way of defining this directly via
reflection so that users don't need to create and manage a whole proc
macro just to allow these sorts of attributes.

And note that this doesn't have to just be for inspectors and editors.
It can be used for things done purely on the code side of things.

## Solution

Create a new method for storing attributes on fields via the `Reflect`
derive.

These custom attributes are stored in type info (e.g. `NamedField`,
`StructInfo`, etc.).

```rust
#[derive(Reflect)]
struct Slider {
    #[reflect(@0.0..=1.0)]
    value: f64,
}

let TypeInfo::Struct(info) = Slider::type_info() else {
    panic!("expected struct info");
};

let field = info.field("value").unwrap();

let range = field.get_attribute::<RangeInclusive<f64>>().unwrap();
assert_eq!(*range, 0.0..=1.0);
```

## TODO

- [x] ~~Bikeshed syntax~~ Went with a type-based approach, prefixed by
`@` for ease of parsing and flexibility
- [x] Add support for custom struct/tuple struct field attributes
- [x] Add support for custom enum variant field attributes
- [x] ~~Add support for custom enum variant attributes (maybe?)~~ ~~Will
require a larger refactor. Can be saved for a future PR if we really
want it.~~ Actually, we apparently still have support for variant
attributes despite not using them, so it was pretty easy to add lol.
- [x] Add support for custom container attributes
- [x] Allow custom attributes to store any reflectable value (not just
`Lit`)
- [x] ~~Store attributes in registry~~ This PR used to store these in
attributes in the registry, however, it has since switched over to
storing them in type info
- [x] Add example

## Bikeshedding

> [!note]
> This section was made for the old method of handling custom
attributes, which stored them by name (i.e. `some_attribute = 123`). The
PR has shifted away from that, to a more type-safe approach.
>
> This section has been left for reference.

There are a number of ways we can syntactically handle custom
attributes. Feel free to leave a comment on your preferred one! Ideally
we want one that is clear, readable, and concise since these will
potentially see _a lot_ of use.

Below is a small, non-exhaustive list of them. Note that the
`skip_serializing` reflection attribute is added to demonstrate how each
case plays with existing reflection attributes.

<details>
<summary>List</summary>

##### 1. `@(name = value)`

> The `@` was chosen to make them stand out from other attributes and
because the "at" symbol is a subtle pneumonic for "attribute". Of
course, other symbols could be used (e.g. `$`, `#`, etc.).

```rust
#[derive(Reflect)]
struct Slider {
    #[reflect(@(min = 0.0, max = 1.0), skip_serializing)]
    #[[reflect(@(bevy_editor::hint = "Range: 0.0 to 1.0"))]
    value: f32,
}
```

##### 2. `@name = value`

> This is my personal favorite.

```rust
#[derive(Reflect)]
struct Slider {
    #[reflect(@min = 0.0, @max = 1.0, skip_serializing)]
    #[[reflect(@bevy_editor::hint = "Range: 0.0 to 1.0")]
    value: f32,
}
```

##### 3. `custom_attr(name = value)`

> `custom_attr` can be anything. Other possibilities include `with` or
`tag`.

```rust
#[derive(Reflect)]
struct Slider {
    #[reflect(custom_attr(min = 0.0, max = 1.0), skip_serializing)]
    #[[reflect(custom_attr(bevy_editor::hint = "Range: 0.0 to 1.0"))]
    value: f32,
}
```

##### 4. `reflect_attr(name = value)`

```rust
#[derive(Reflect)]
struct Slider {
    #[reflect(skip_serializing)]
    #[reflect_attr(min = 0.0, max = 1.0)]
    #[[reflect_attr(bevy_editor::hint = "Range: 0.0 to 1.0")]
    value: f32,
}
```

</details>

---

## Changelog

- Added support for custom attributes on reflected types (i.e.
`#[reflect(@Foo::new("bar")]`)
2024-05-20 19:30:21 +00:00
Alice Cecile
ee6dfd35c9
Revert "Add on_unimplemented Diagnostics to Most Public Traits" (#13413)
# Objective

- Rust 1.78 breaks all Android support, see
https://github.com/bevyengine/bevy/issues/13331
- We should not bump the MSRV to 1.78 until that's resolved in #13366.

## Solution

- Temporarily revert https://github.com/bevyengine/bevy/pull/13347

Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
2024-05-17 17:00:43 +00:00
Zachary Harrold
11f0a2dcde
Add on_unimplemented Diagnostics to Most Public Traits (#13347)
# Objective

- Fixes #12377

## Solution

Added simple `#[diagnostic::on_unimplemented(...)]` attributes to some
critical public traits providing a more approachable initial error
message. Where appropriate, a `note` is added indicating that a `derive`
macro is available.

## Examples

<details>
<summary>Examples hidden for brevity</summary>

Below is a collection of examples showing the new error messages
produced by this change. In general, messages will start with a more
Bevy-centric error message (e.g., _`MyComponent` is not a `Component`_),
and a note directing the user to an available derive macro where
appropriate.

### Missing `#[derive(Resource)]`

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

struct MyResource;

fn main() {
    App::new()
        .insert_resource(MyResource)
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `MyResource` is not a `Resource`
   --> examples/app/empty.rs:7:26
    |
7   |         .insert_resource(MyResource)
    |          --------------- ^^^^^^^^^^ invalid `Resource`
    |          |
    |          required by a bound introduced by this call
    |
    = help: the trait `Resource` is not implemented for `MyResource`       
    = note: consider annotating `MyResource` with `#[derive(Resource)]`    
    = help: the following other types implement trait `Resource`:
              AccessibilityRequested
              ManageAccessibilityUpdates
              bevy::bevy_a11y::Focus
              DiagnosticsStore
              FrameCount
              bevy::prelude::State<S>
              SystemInfo
              bevy::prelude::Axis<T>
            and 141 others
note: required by a bound in `bevy::prelude::App::insert_resource`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:419:31
    |
419 |     pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
    |                               ^^^^^^^^ required by this bound in `App::insert_resource`
```

</details>

### Putting A `QueryData` in a `QueryFilter` Slot

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

#[derive(Component)]
struct A;

#[derive(Component)]
struct B;

fn my_system(_query: Query<&A, &B>) {}

fn main() {
    App::new()
        .add_systems(Update, my_system)
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `&B` is not a valid `Query` filter
   --> examples/app/empty.rs:9:22
    |
9   | fn my_system(_query: Query<&A, &B>) {}
    |                      ^^^^^^^^^^^^^ invalid `Query` filter
    |
    = help: the trait `QueryFilter` is not implemented for `&B`
    = help: the following other types implement trait `QueryFilter`:
              With<T>
              Without<T>
              bevy::prelude::Or<()>
              bevy::prelude::Or<(F0,)>
              bevy::prelude::Or<(F0, F1)>
              bevy::prelude::Or<(F0, F1, F2)>
              bevy::prelude::Or<(F0, F1, F2, F3)>
              bevy::prelude::Or<(F0, F1, F2, F3, F4)>
            and 28 others
note: required by a bound in `bevy::prelude::Query`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_ecs\src\system\query.rs:349:51
    |
349 | pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = ()> {
    |                                                   ^^^^^^^^^^^ required by this bound in `Query`
```

</details>

### Missing `#[derive(Component)]`

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

struct A;

fn my_system(mut commands: Commands) {
    commands.spawn(A);
}

fn main() {
    App::new()
        .add_systems(Startup, my_system)
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `A` is not a `Bundle`
   --> examples/app/empty.rs:6:20
    |
6   |     commands.spawn(A);
    |              ----- ^ invalid `Bundle`
    |              |
    |              required by a bound introduced by this call
    |
    = help: the trait `bevy::prelude::Component` is not implemented for `A`, which is required by `A: Bundle`
    = note: consider annotating `A` with `#[derive(Component)]` or `#[derive(Bundle)]`
    = help: the following other types implement trait `Bundle`:
              TransformBundle
              SceneBundle
              DynamicSceneBundle
              AudioSourceBundle<Source>
              SpriteBundle
              SpriteSheetBundle
              Text2dBundle
              MaterialMesh2dBundle<M>
            and 34 others
    = note: required for `A` to implement `Bundle`
note: required by a bound in `bevy::prelude::Commands::<'w, 's>::spawn`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_ecs\src\system\commands\mod.rs:243:21
    |
243 |     pub fn spawn<T: Bundle>(&mut self, bundle: T) -> EntityCommands {
    |                     ^^^^^^ required by this bound in `Commands::<'w, 's>::spawn`
```

</details>

### Missing `#[derive(Asset)]`

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

struct A;

fn main() {
    App::new()
        .init_asset::<A>()
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `A` is not an `Asset`
   --> examples/app/empty.rs:7:23
    |
7   |         .init_asset::<A>()
    |          ----------   ^ invalid `Asset`
    |          |
    |          required by a bound introduced by this call
    |
    = help: the trait `Asset` is not implemented for `A`
    = note: consider annotating `A` with `#[derive(Asset)]`
    = help: the following other types implement trait `Asset`:
              Font
              AnimationGraph
              DynamicScene
              Scene
              AudioSource
              Pitch
              bevy::bevy_gltf::Gltf
              GltfNode
            and 17 others
note: required by a bound in `init_asset`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_asset\src\lib.rs:307:22
    |
307 |     fn init_asset<A: Asset>(&mut self) -> &mut Self;
    |                      ^^^^^ required by this bound in `AssetApp::init_asset`
```

</details>

### Mismatched Input and Output on System Piping

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

fn producer() -> u32 {
    123
}

fn consumer(_: In<u16>) {}

fn main() {
    App::new()
        .add_systems(Update, producer.pipe(consumer))
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `fn(bevy::prelude::In<u16>) {consumer}` is not a valid system with input `u32` and output `_`
   --> examples/app/empty.rs:11:44
    |
11  |         .add_systems(Update, producer.pipe(consumer))
    |                                       ---- ^^^^^^^^ invalid system
    |                                       |
    |                                       required by a bound introduced by this call
    |
    = help: the trait `bevy::prelude::IntoSystem<u32, _, _>` is not implemented for fn item `fn(bevy::prelude::In<u16>) {consumer}`
    = note: expecting a system which consumes `u32` and produces `_`
note: required by a bound in `pipe`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_ecs\src\system\mod.rs:168:12
    |
166 |     fn pipe<B, Final, MarkerB>(self, system: B) -> PipeSystem<Self::System, B::System>
    |        ---- required by a bound in this associated function
167 |     where
168 |         B: IntoSystem<Out, Final, MarkerB>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `IntoSystem::pipe`
```

</details>

### Missing Reflection

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

#[derive(Component)]
struct MyComponent;

fn main() {
    App::new()
        .register_type::<MyComponent>()
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `MyComponent` does not provide type registration information
   --> examples/app/empty.rs:8:26
    |
8   |         .register_type::<MyComponent>()
    |          -------------   ^^^^^^^^^^^ the trait `GetTypeRegistration` is not implemented for `MyComponent`
    |          |
    |          required by a bound introduced by this call
    |
    = note: consider annotating `MyComponent` with `#[derive(Reflect)]`
    = help: the following other types implement trait `GetTypeRegistration`:
              bool
              char
              isize
              i8
              i16
              i32
              i64
              i128
            and 443 others
note: required by a bound in `bevy::prelude::App::register_type`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:619:29
    |
619 |     pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `App::register_type`
```

</details>

### Missing `#[derive(States)]` Implementation

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
enum AppState {
    #[default]
    Menu,
    InGame {
        paused: bool,
        turbo: bool,
    },
}

fn main() {
    App::new()
        .init_state::<AppState>()
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: the trait bound `AppState: FreelyMutableState` is not satisfied
   --> examples/app/empty.rs:15:23
    |
15  |         .init_state::<AppState>()
    |          ----------   ^^^^^^^^ the trait `FreelyMutableState` is not implemented for `AppState`
    |          |
    |          required by a bound introduced by this call
    |
    = note: consider annotating `AppState` with `#[derive(States)]`
note: required by a bound in `bevy::prelude::App::init_state`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:282:26
    |
282 |     pub fn init_state<S: FreelyMutableState + FromWorld>(&mut self) -> &mut Self {
    |                          ^^^^^^^^^^^^^^^^^^ required by this bound in `App::init_state`
```

</details>

### Adding a `System` with Unhandled Output

<details>
<summary>Example Code</summary>

```rust
use bevy::prelude::*;

fn producer() -> u32 {
    123
}

fn main() {
    App::new()
        .add_systems(Update, consumer)
        .run();
}
```

</details>

<details>
<summary>Error Generated</summary>

```error
error[E0277]: `fn() -> u32 {producer}` does not describe a valid system configuration
   --> examples/app/empty.rs:9:30
    |
9   |         .add_systems(Update, producer)
    |          -----------         ^^^^^^^^ invalid system configuration
    |          |
    |          required by a bound introduced by this call
    |
    = help: the trait `IntoSystem<(), (), _>` is not implemented for fn item `fn() -> u32 {producer}`, which is required by `fn() -> u32 {producer}: IntoSystemConfigs<_>`
    = help: the following other types implement trait `IntoSystemConfigs<Marker>`:
              <Box<(dyn bevy::prelude::System<In = (), Out = ()> + 'static)> as IntoSystemConfigs<()>>
              <NodeConfigs<Box<(dyn bevy::prelude::System<In = (), Out = ()> + 'static)>> as IntoSystemConfigs<()>>
              <(S0,) as IntoSystemConfigs<(SystemConfigTupleMarker, P0)>>
              <(S0, S1) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1)>>
              <(S0, S1, S2) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2)>>
              <(S0, S1, S2, S3) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2, P3)>>
              <(S0, S1, S2, S3, S4) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2, P3, P4)>>
              <(S0, S1, S2, S3, S4, S5) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2, P3, P4, P5)>>
            and 14 others
    = note: required for `fn() -> u32 {producer}` to implement `IntoSystemConfigs<_>`
note: required by a bound in `bevy::prelude::App::add_systems`
   --> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:342:23
    |
339 |     pub fn add_systems<M>(
    |            ----------- required by a bound in this associated function
...
342 |         systems: impl IntoSystemConfigs<M>,
    |                       ^^^^^^^^^^^^^^^^^^^^ required by this bound in `App::add_systems`
```

</details>
</details>

## Testing

CI passed locally.

## Migration Guide

Upgrade to version 1.78 (or higher) of Rust.

## Future Work

- Currently, hints are not supported in this diagnostic. Ideally,
suggestions like _"consider using ..."_ would be in a hint rather than a
note, but that is the best option for now.
- System chaining and other `all_tuples!(...)`-based traits have bad
error messages due to the slightly different error message format.

---------

Co-authored-by: Jamie Ridding <Themayu@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-05-17 00:49:05 +00:00
Ben Harper
be03ba1b68
Add reflect impls for bevy_math curve structs (#13348)
# Objective

Fixes #13189

## Solution

To add the reflect impls I needed to make all the struct fields pub. I
don't think there's any harm for these types, but just a note for
review.

---------

Co-authored-by: Ben Harper <ben@tukom.org>
2024-05-16 17:59:56 +00:00
Brezak
cbda71c2b3
Determine msrv for every standalone bevy_* crate. (#13211)
# Objective

As was pointed out in #13183, `bevy_mikktspace` is missing it's msrv
from it `Cargo.toml`. This promted me to check the msrv of every
`bevy_*` crate. Closes #13183.

## Solution

- Call `cargo check` with different rust versions on every bevy crate
until it doesn't complain.
- Write down the rust version `cargo check` started working.

## Testing

- Install `cargo-msrv`.
- Run `cargo msrv verify`.
- Rejoice.

---

## Changelog

Every published bevy crate now specifies a MSRV. If your rust toolchain
isn't at least version `1.77.0` You'll likely not be able to compile
most of bevy.

## Migration Guide

If your rust toolchain is bellow version`1.77.0, update.
2024-05-13 18:26:41 +00:00
rmsthebest
278380394f
Avoid bevy_reflect::List::iter wrapping in release mode (#13271)
# Objective
Fixes  #13230

## Solution
Uses solution described in  #13230
They mention a worry about adding a branch, but I'm not sure there is
one.

This code
```Rust
#[no_mangle]
pub fn next_if_some(num: i32, b: Option<bool>) -> i32 {
    num + b.is_some() as i32
}
```
produces this assembly with opt-level 3
```asm
next_if_some:
        xor     eax, eax
        cmp     sil, 2
        setne   al
        add     eax, edi
        ret
```

## Testing
Added test from #13230, tagged it as ignore as it is only useful in
release mode and very slow if you accidentally invoke it in debug mode.

---

## Changelog
Iterationg of ListIter will no longer overflow and wrap around

## Migration Guide
2024-05-12 15:01:05 +00:00
Gino Valente
705c144259
bevy_reflect: Remove ContainerAttributes::merge (#13303)
# Objective

Unblocks #11659.

Currently the `Reflect` derive macro has to go through a merge process
for each `#[reflect]`/`#[reflet_value]` attribute encountered on a
container type.

Not only is this a bit inefficient, but it also has a soft requirement
that we can compare attributes such that an error can be thrown on
duplicates, invalid states, etc.

While working on #11659 this proved to be challenging due to the fact
that `syn` types don't implement `PartialEq` or `Hash` without enabling
the `extra-traits` feature.

Ideally, we wouldn't have to enable another feature just to accommodate
this one use case.

## Solution

Removed `ContainerAttributes::merge`.

This was a fairly simple change as we could just have the parsing
functions take `&mut self` instead of returning `Self`.

## Testing

CI should build as there should be no user-facing change.
2024-05-09 18:17:54 +00:00
Brezak
9c4ac7c297
Finish the work on try_apply (#12646)
# Objective

Finish the `try_apply` implementation started in #6770 by @feyokorenhof.
Supersedes and closes #6770. Closes #6182

## Solution

Add `try_apply` to `Reflect` and implement it in all the places that
implement `Reflect`.

---

## Changelog

Added `try_apply` to `Reflect`.

---------

Co-authored-by: Feyo Korenhof <feyokorenhof@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-05-08 14:26:01 +00:00
BD103
22305acf66
Rename bevy_reflect_derive folder to derive (#13269)
# Objective

- Some of the "large" crates have sub-crates, usually for things such as
macros.
- For an example, see [`bevy_ecs_macros` at
`bevy_ecs/macros`](4f9f987099/crates/bevy_ecs/macros).
- The one crate that does not follow this convention is
[`bevy_reflect_derive`](4f9f987099/crates/bevy_reflect/bevy_reflect_derive),
which is in the `bevy_reflect/bevy_reflect_derive` folder and not
`bevy_reflect/derive` or `bevy_reflect/macros`.

## Solution

- Rename folder `bevy_reflect_derive` to `derive`.
- I chose to use `derive` instead of `macros` because the crate name
itself ends in `_derive`. (One of only two crates to actually use this
convention, funnily enough.)

## Testing

- Build and test `bevy_reflect` and `bevy_reflect_derive`.
- Apply the following patch to `publish.sh` to run it in `--dry-run`
mode, to test that the path has been successfully updated:
- If you have any security concerns about applying random diffs, feel
free to skip this step. Worst case scenario it fails and Cart has to
manually publish a few crates.

```bash
# Apply patch to make `publish.sh` *not* actually publish anything.
git apply path/to/foo.patch
# Make `publish.sh` executable.
chmod +x tools/publish.sh
# Execute `publish.sh`.
./tools/publish.sh
```

```patch
diff --git a/tools/publish.sh b/tools/publish.sh
index b020bad28..fbcc09281 100644
--- a/tools/publish.sh
+++ b/tools/publish.sh
@@ -49,7 +49,7 @@ crates=(
 
 if [ -n "$(git status --porcelain)" ]; then
     echo "You have local changes!"
-    exit 1
+    # exit 1
 fi
 
 pushd crates
@@ -61,15 +61,15 @@ do
   cp ../LICENSE-APACHE "$crate"
   pushd "$crate"
   git add LICENSE-MIT LICENSE-APACHE
-  cargo publish --no-verify --allow-dirty
+  cargo publish --no-verify --allow-dirty --dry-run
   popd
-  sleep 20
+  # sleep 20
 done
 
 popd
 
 echo "Publishing root crate"
-cargo publish --allow-dirty
+cargo publish --allow-dirty --dry-run
 
 echo "Cleaning local state"
 git reset HEAD --hard
```

---

## Changelog

- Moved `bevy_reflect_derive` from
`crates/bevy_reflect/bevy_reflect_derive` to
`crates/bevy_reflect/derive`.
2024-05-07 07:55:32 +00:00
Brezak
423a4732c3
Update compile test to use ui_test 0.23 (#13245)
# Objective

Closes #13241

## Solution

Update test utils to use `ui_test` 0.23.0.

## Testing

- Run compile tests for bevy_ecs.

cc @BD103
2024-05-05 22:17:56 +00:00
BD103
bdb4899978
Move compile fail tests (#13196)
# Objective

- Follow-up of #13184 :)
- We use `ui_test` to test compiler errors for our custom macros.
- There are four crates related to compile fail tests
- `bevy_ecs_compile_fail_tests`, `bevy_macros_compile_fail_tests`, and
`bevy_reflect_compile_fail_tests`, which actually test the macros.
-
[`bevy_compile_test_utils`](64c1c65783/crates/bevy_compile_test_utils),
which provides helpers and common patterns for these tests.
- All of these crates reside within the `crates` directory.
- This can be confusing, especially for newcomers. All of the other
folders in `crates` are actual published libraries, except for these 4.

## Solution

- Move all compile fail tests to a `compile_fail` folder under their
corresponding crate.
- E.g. `crates/bevy_ecs_compile_fail_tests` would be moved to
`crates/bevy_ecs/compile_fail`.
- Move `bevy_compile_test_utils` to `tools/compile_fail_utils`.

There are a few benefits to this approach:

1. An internal testing detail is less intrusive (and confusing) for
those who just want to browse the public Bevy interface.
2. Follows a pre-existing approach of organizing related crates inside a
larger crate's folder.
   - See `bevy_gizmos/macros` for an example.
4. Makes consistent the terms `compile_test`, `compile_fail`, and
`compile_fail_test` in code. It's all just `compile_fail` now, because
we are specifically testing the error messages on compiler failures.
- To be clear it can still be referred to by these terms in comments and
speech, just the names of the crates and the CI command are now
consistent.

## Testing

Run the compile fail CI command:

```shell
cargo run -p ci -- compile-fail
```

If it still passes, then my refactor was successful.
2024-05-03 13:35:21 +00:00
BD103
e357b63448
Add README.md to all crates (#13184)
# Objective

- `README.md` is a common file that usually gives an overview of the
folder it is in.
- When on <https://crates.io>, `README.md` is rendered as the main
description.
- Many crates in this repository are lacking `README.md` files, which
makes it more difficult to understand their purpose.

<img width="1552" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/78ebf91d-b0c4-4b18-9874-365d6310640f">

- There are also a few inconsistencies with `README.md` files that this
PR and its follow-ups intend to fix.

## Solution

- Create a `README.md` file for all crates that do not have one.
- This file only contains the title of the crate (underscores removed,
proper capitalization, acronyms expanded) and the <https://shields.io>
badges.
- Remove the `readme` field in `Cargo.toml` for `bevy` and
`bevy_reflect`.
- This field is redundant because [Cargo automatically detects
`README.md`
files](https://doc.rust-lang.org/cargo/reference/manifest.html#the-readme-field).
The field is only there if you name it something else, like `INFO.md`.
- Fix capitalization of `bevy_utils`'s `README.md`.
- It was originally `Readme.md`, which is inconsistent with the rest of
the project.
- I created two commits renaming it to `README.md`, because Git appears
to be case-insensitive.
- Expand acronyms in title of `bevy_ptr` and `bevy_utils`.
- In the commit where I created all the new `README.md` files, I
preferred using expanded acronyms in the titles. (E.g. "Bevy Developer
Tools" instead of "Bevy Dev Tools".)
- This commit changes the title of existing `README.md` files to follow
the same scheme.
- I do not feel strongly about this change, please comment if you
disagree and I can revert it.
- Add <https://shields.io> badges to `bevy_time` and `bevy_transform`,
which are the only crates currently lacking them.

---

## Changelog

- Added `README.md` files to all crates missing it.
2024-05-02 18:56:00 +00:00
Martín Maita
32cd0c5dc1
Update glam version requirement from 0.25 to 0.27 (#12757)
# Objective

- Update glam version requirement to latest version.

## Solution

- Updated `glam` version requirement from 0.25 to 0.27.
- Updated `encase` and `encase_derive_impl` version requirement from 0.7
to 0.8.
- Updated `hexasphere` version requirement from 10.0 to 12.0.
- Breaking changes from glam changelog:
- [0.26.0] Minimum Supported Rust Version bumped to 1.68.2 for impl
From<bool> for {f32,f64} support.
- [0.27.0] Changed implementation of vector fract method to match the
Rust implementation instead of the GLSL implementation, that is self -
self.trunc() instead of self - self.floor().

---

## Migration Guide

- When using `glam` exports, keep in mind that `vector` `fract()` method
now matches Rust implementation (that is `self - self.trunc()` instead
of `self - self.floor()`). If you want to use the GLSL implementation
you should now use `fract_gl()`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-05-02 18:42:34 +00:00
Marcel Müller
6d25545c51
Implement Reflect for Result<T, E> as enum (#13182)
# Objective

- Make `Result<T, E>` implement Reflect such that it is an Enum rather
than a Value
- Fixes #13178

## Solution

- Use the correct macro

## Testing

- Did you test these changes? 

I tried it out locally, and it does what it says on the tin. Not sure
how to test it in context of the crate?


---

## Changelog

### Changed

- Result now uses `ReflectKind::Enum` rather than `ReflectKind::Value`,
allowing for inspection of its constituents

## Migration Guide

`Result<T, E>` has had its `Reflect` implementation changed to align it
with `Option<T>` and its intended semantics: A carrier of either an `Ok`
or `Err` value, and the ability to access it. To achieve this it is no
longer a `ReflectKind::Value` but rather a `ReflectKind::Enum` and as
such carries these changes with it:

For `Result<T, E>`
- Both `T` and `E` no longer require to be `Clone` and now require to be
`FromReflect`
- `<Result<T, E> as Reflect>::reflect_*` now returns a
`ReflectKind::Enum`, so any code that previously relied on it being a
`Value` kind will have to be adapted.
- `Result<T, E>` now implements `Enum`

Since the migration is highly dependent on the previous usage, no
automatic upgrade path can be given.

Signed-off-by: Marcel Müller <neikos@neikos.email>
2024-05-02 18:28:24 +00:00
Mateusz Wachowiak
64b987921c
iter_with_data (#13102)
# Objective

- Provide a way to iterate over the registered TypeData.

## Solution

- a new method on the `TypeRegistry` that iterates over
`TypeRegistrations` with theirs `TypeData`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-04-26 02:09:34 +00:00
targrub
8316166622
Fix uses of "it's" vs "its". (#13033)
Grammar changes only.
2024-04-19 18:17:31 +00:00
andristarr
2b3e3341d6
separating finite and infinite 3d planes (#12426)
# Objective

Fixes #12388

## Solution

- Removing the plane3d and adding rect3d primitive mesh
2024-04-18 14:13:22 +00:00
Robert Walter
2532447dcb
impl Reflect for EntityHashSet (#12971)
`EntityHashSet` doesn't seem to implement `Reflect` which seems weird!
Especially since `EntityHashMap` implements `Reflect`.

This PR just added an extra `impl_reflect_value!` for `EntityHashSet`
and this seems to do the trick.

I left out doing the same for `StableHashSet` since it's marked as
deprecated.

---

I'm really wondering what was the issue here. If anyone can explain why
`EntityHashSet` can't use the `Reflect` impl of `bevy_utils::HashSet`
similar to how it's the case with the `...HashMap`s I'd be interested!
2024-04-16 02:48:03 +00:00
BD103
7b8d502083
Fix beta lints (#12980)
# Objective

- Fixes #12976

## Solution

This one is a doozy.

- Run `cargo +beta clippy --workspace --all-targets --all-features` and
fix all issues
- This includes:
- Moving inner attributes to be outer attributes, when the item in
question has both inner and outer attributes
  - Use `ptr::from_ref` in more scenarios
- Extend the valid idents list used by `clippy:doc_markdown` with more
names
  - Use `Clone::clone_from` when possible
  - Remove redundant `ron` import
  - Add backticks to **so many** identifiers and items
    - I'm sorry whoever has to review this

---

## Changelog

- Added links to more identifiers in documentation.
2024-04-16 02:46:46 +00:00
BD103
aa2ebbb43f
Fix some nightly Clippy lints (#12927)
# Objective

- I daily drive nightly Rust when developing Bevy, so I notice when new
warnings are raised by `cargo check` and Clippy.
- `cargo +nightly clippy` raises a few of these new warnings.

## Solution

- Fix most warnings from `cargo +nightly clippy`
- I skipped the docs-related warnings because some were covered by
#12692.
- Use `Clone::clone_from` in applicable scenarios, which can sometimes
avoid an extra allocation.
- Implement `Default` for structs that have a `pub const fn new() ->
Self` method.
- Fix an occurrence where generic constraints were defined in both `<C:
Trait>` and `where C: Trait`.
  - Removed generic constraints that were implied by the `Bundle` trait.

---

## Changelog

- `BatchingStrategy`, `NonGenericTypeCell`, and `GenericTypeCell` now
implement `Default`.
2024-04-13 02:05:38 +00:00
Matty
c8aa3ac7d1
Meshing for Annulus primitive (#12734)
# Objective

Related to #10572 
Allow the `Annulus` primitive to be meshed.

## Solution

We introduce a `Meshable` structure, `AnnulusMeshBuilder`, which allows
the `Annulus` primitive to be meshed, leaving optional configuration of
the number of angular sudivisions to the user. Here is a picture of the
annulus's UV-mapping:
<img width="1440" alt="Screenshot 2024-03-26 at 10 39 48 AM"
src="https://github.com/bevyengine/bevy/assets/2975848/b170291d-cba7-441b-90ee-2ad6841eaedb">

Other features are essentially identical to the implementations for
`Circle`/`Ellipse`.

---

## Changelog

- Introduced `AnnulusMeshBuilder`
- Implemented `Meshable` for `Annulus` with `Output =
AnnulusMeshBuilder`
- Implemented `From<Annulus>` and `From<AnnulusMeshBuilder>` for `Mesh`
- Added `impl_reflect!` declaration for `Annulus` and `Triangle3d` in
`bevy_reflect`

---

## Discussion

### Design considerations

The only interesting wrinkle here is that the existing UV-mapping of
`Ellipse` (and hence of `Circle` and `RegularPolygon`) is non-radial
(it's skew-free, created by situating the mesh in a bounding rectangle),
so the UV-mapping of `Annulus` doesn't limit to that of `Circle` as its
inner radius tends to zero, for instance. I don't see this as a real
issue for `Annulus`, which should almost certainly have this kind of
UV-mapping, but I think we ought to at least consider allowing mesh
configuration for `Circle`/`Ellipse` that performs radial UV-mapping
instead. (In these cases in particular, it would be especially easy,
since we wouldn't need a different parameter set in the builder.)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-04-01 21:55:49 +00:00
Jakub Marcowski
20ee56e719
Add Tetrahedron primitive to bevy_math::primitives (#12688)
# Objective

- #10572

There is no 3D primitive available for the common shape of a tetrahedron
(3-simplex).

## Solution

This PR introduces a new type to the existing math primitives:

- `Tetrahedron`: a polyhedron composed of four triangular faces, six
straight edges, and four vertices

---

## Changelog

### Added

- `Tetrahedron` primitive to the `bevy_math` crate
- `Tetrahedron` tests (`area`, `volume` methods)
- `impl_reflect!` declaration for `Tetrahedron` in the `bevy_reflect`
crate
2024-04-01 21:53:12 +00:00
BD103
84363f2fab
Remove redundant imports (#12817)
# Objective

- There are several redundant imports in the tests and examples that are
not caught by CI because additional flags need to be passed.

## Solution

- Run `cargo check --workspace --tests` and `cargo check --workspace
--examples`, then fix all warnings.
- Add `test-check` to CI, which will be run in the check-compiles job.
This should catch future warnings for tests. Examples are already
checked, but I'm not yet sure why they weren't caught.

## Discussion

- Should the `--tests` and `--examples` flags be added to CI, so this is
caught in the future?
- If so, #12818 will need to be merged first. It was also a warning
raised by checking the examples, but I chose to split off into a
separate PR.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-04-01 19:59:08 +00:00
James Liu
56bcbb0975
Forbid unsafe in most crates in the engine (#12684)
# Objective
Resolves #3824. `unsafe` code should be the exception, not the norm in
Rust. It's obviously needed for various use cases as it's interfacing
with platforms and essentially running the borrow checker at runtime in
the ECS, but the touted benefits of Bevy is that we are able to heavily
leverage Rust's safety, and we should be holding ourselves accountable
to that by minimizing our unsafe footprint.

## Solution
Deny `unsafe_code` workspace wide. Add explicit exceptions for the
following crates, and forbid it in almost all of the others.

* bevy_ecs - Obvious given how much unsafe is needed to achieve
performant results
* bevy_ptr - Works with raw pointers, even more low level than bevy_ecs.
 * bevy_render - due to needing to integrate with wgpu
 * bevy_window - due to needing to integrate with raw_window_handle
* bevy_utils - Several unsafe utilities used by bevy_ecs. Ideally moved
into bevy_ecs instead of made publicly usable.
 * bevy_reflect - Required for the unsafe type casting it's doing.
 * bevy_transform - for the parallel transform propagation
 * bevy_gizmos  - For the SystemParam impls it has.
* bevy_assets - To support reflection. Might not be required, not 100%
sure yet.
* bevy_mikktspace - due to being a conversion from a C library. Pending
safe rewrite.
* bevy_dynamic_plugin - Inherently unsafe due to the dynamic loading
nature.

Several uses of unsafe were rewritten, as they did not need to be using
them:

* bevy_text - a case of `Option::unchecked` could be rewritten as a
normal for loop and match instead of an iterator.
* bevy_color - the Pod/Zeroable implementations were replaceable with
bytemuck's derive macros.
2024-03-27 03:30:08 +00:00
Gino Valente
0265436fff
bevy_reflect: Rename UntypedReflectDeserializer to ReflectDeserializer (#12721)
# Objective

We have `ReflectSerializer` and `TypedReflectSerializer`. The former is
the one users will most often use since the latter takes a bit more
effort to deserialize.

However, our deserializers are named `UntypedReflectDeserializer` and
`TypedReflectDeserializer`. There is no obvious indication that
`UntypedReflectDeserializer` must be used with `ReflectSerializer` since
the names don't quite match up.

## Solution

Rename `UntypedReflectDeserializer` back to `ReflectDeserializer`
(initially changed as part of #5723).

Also update the docs for both deserializers (as they were pretty out of
date) and include doc examples.

I also updated the docs for the serializers, too, just so that
everything is consistent.

---

## Changelog

- Renamed `UntypedReflectDeserializer` to `ReflectDeserializer`
- Updated docs for `ReflectDeserializer`, `TypedReflectDeserializer`,
`ReflectSerializer`, and `TypedReflectSerializer`

## Migration Guide

`UntypedReflectDeserializer` has been renamed to `ReflectDeserializer`.
Usages will need to be updated accordingly.

```diff
- let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
+ let reflect_deserializer = ReflectDeserializer::new(&registry);
```
2024-03-26 19:58:29 +00:00
James Liu
f096ad4155
Set the logo and favicon for all of Bevy's published crates (#12696)
# Objective
Currently the built docs only shows the logo and favicon for the top
level `bevy` crate. This makes views like
https://docs.rs/bevy_ecs/latest/bevy_ecs/ look potentially unrelated to
the project at first glance.

## Solution
Reproduce the docs attributes for every crate that Bevy publishes.

Ideally this would be done with some workspace level Cargo.toml control,
but AFAICT, such support does not exist.
2024-03-25 18:52:50 +00:00
Ame
72c51cdab9
Make feature(doc_auto_cfg) work (#12642)
# Objective

- In #12366 `![cfg_attr(docsrs, feature(doc_auto_cfg))] `was added. But
to apply it it needs `--cfg=docsrs` in rustdoc-args.


## Solution

- Apply `--cfg=docsrs` to all crates and CI.

I also added `[package.metadata.docs.rs]` to all crates to avoid adding
code behind a feature and forget adding the metadata.

Before:

![Screenshot 2024-03-22 at 00 51
57](https://github.com/bevyengine/bevy/assets/104745335/6a9dfdaa-8710-4784-852b-5f9b74e3522c)

After:
![Screenshot 2024-03-22 at 00 51
32](https://github.com/bevyengine/bevy/assets/104745335/c5bd6d8e-8ddb-45b3-b844-5ecf9f88961c)
2024-03-23 02:22:52 +00:00
Jacques Schutte
fdf2ea7cc5
reflect: remove manual Reflect impls which could be handled by macros (#12596)
# Objective

* Adopted #12025 to fix merge conflicts
* In some cases we used manual impls for certain types, though they are
(at least, now) unnecessary.

## Solution

* Use macros and reflecting-by-value to avoid this clutter.
* Though there were linker issues with Reflect and the CowArc in
AssetPath (see https://github.com/bevyengine/bevy/issues/9747), I
checked these are resolved by using #[reflect_value].

---------

Co-authored-by: soqb <cb.setho@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: James Liu <contact@jamessliu.com>
2024-03-23 01:45:00 +00:00
Charles Bournhonesque
ea6540dc41
add reflect for BinaryHeap (#12503)
# Objective
I wanted to have reflection for BinaryHeap for a personal project.

I'm running into some issues:
- I wanted to represent BinaryHeap as a reflect::List type since it's
essentially a wrapper around a Vec, however there's no public way to
access the underlying Vec, which makes it hard to implement the
reflect::List methods. I have omitted the reflect::List methods for
now.. I'm not sure if that's a blocker?
- what would be the alternatives? Simply not implement `reflect::List`?
It is possible to implement `FromReflect` without it. Would the type be
`Struct` then?

---------

Co-authored-by: Charles Bournhonesque <cbournhonesque@snapchat.com>
2024-03-17 22:24:04 +00:00
Charles Bournhonesque
24b319f6ec
Add reflect for type id (#12495)
# Objective

Add reflect for `std::any::TypeId`.

I couldn't add ReflectSerialize/ReflectDeserialize for it, it was giving
me an error. I don't really understand why, since it works for
`std::path::PathBuf`.

Co-authored-by: Charles Bournhonesque <cbournhonesque@snapchat.com>
2024-03-15 17:43:26 +00:00
Peter Hayman
d3e44325b4
Fix: deserialize DynamicEnum using index (#12464)
# Objective

- Addresses #12462
- When we serialize an enum, deserialize it, then reserialize it, the
correct variant should be selected.

## Solution

- Change `dynamic_enum.set_variant` to
`dynamic_enum.set_variant_with_index` in `EnumVisitor`
2024-03-14 05:15:20 +00:00
Gino Valente
4c47e31be6
bevy_reflect: Remove U32Visitor (#12433)
# Objective

The `U32Visitor` struct has been unused since its introduction in #6140.
It's made itself known now by causing a recent [CI
failure](https://github.com/bevyengine/bevy/actions/runs/8243333274/job/22543736624).

## Solution

Remove the unused `U32Visitor` struct.

Also removed `PrepassLightsViewFlush` as it was causing a [similar CI
failure](https://github.com/bevyengine/bevy/actions/runs/8243838066/job/22545103746?pr=12433#step:6:269)
on this PR.
2024-03-12 06:19:29 +00:00
Joona Aalto
f89af0567b
Add Rotation2d (#11658)
# Objective

Rotating vectors is a very common task. It is required for a variety of
things both within Bevy itself and in many third party plugins, for
example all over physics and collision detection, and for things like
Bevy's bounding volumes and several gizmo implementations.

For 3D, we can do this using a `Quat`, but for 2D, we do not have a
clear and efficient option. `Mat2` can be used for rotating vectors if
created using `Mat2::from_angle`, but this is not obvious to many users,
it doesn't have many rotation helpers, and the type does not give any
guarantees that it represents a valid rotation.

We should have a proper type for 2D rotations. In addition to allowing
for potential optimization, it would allow us to have a consistent and
explicitly documented representation used throughout the engine, i.e.
counterclockwise and in radians.

## Representation

The mathematical formula for rotating a 2D vector is the following:

```
new_x = x * cos - y * sin
new_y = x * sin + y * cos
```

Here, `sin` and `cos` are the sine and cosine of the rotation angle.
Computing these every time when a vector needs to be rotated can be
expensive, so the rotation shouldn't be just an `f32` angle. Instead, it
is often more efficient to represent the rotation using the sine and
cosine of the angle instead of storing the angle itself. This can be
freely passed around and reused without unnecessary computations.

The two options are either a 2x2 rotation matrix or a unit complex
number where the cosine is the real part and the sine is the imaginary
part. These are equivalent for the most part, but the unit complex
representation is a bit more memory efficient (two `f32`s instead of
four), so I chose that. This is like Nalgebra's
[`UnitComplex`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.UnitComplex.html)
type, which can be used for the
[`Rotation2`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.Rotation2.html)
type.

## Implementation

Add a `Rotation2d` type represented as a unit complex number:

```rust
/// A counterclockwise 2D rotation in radians.
///
/// The rotation angle is wrapped to be within the `]-pi, pi]` range.
pub struct Rotation2d {
    /// The cosine of the rotation angle in radians.
    ///
    /// This is the real part of the unit complex number representing the rotation.
    pub cos: f32,
    /// The sine of the rotation angle in radians.
    ///
    /// This is the imaginary part of the unit complex number representing the rotation.
    pub sin: f32,
}
```

Using it is similar to using `Quat`, but in 2D:

```rust
let rotation = Rotation2d::radians(PI / 2.0);

// Rotate vector (also works on Direction2d!)
assert_eq!(rotation * Vec2::X, Vec2::Y);

// Get angle as degrees
assert_eq!(rotation.as_degrees(), 90.0);

// Getting sin and cos is free
let (sin, cos) = rotation.sin_cos();

// "Subtract" rotations
let rotation2 = Rotation2d::FRAC_PI_4; // there are constants!
let diff = rotation * rotation2.inverse();
assert_eq!(diff.as_radians(), PI / 4.0);

// This is equivalent to the above
assert_eq!(rotation2.angle_between(rotation), PI / 4.0);

// Lerp
let rotation1 = Rotation2d::IDENTITY;
let rotation2 = Rotation2d::FRAC_PI_2;
let result = rotation1.lerp(rotation2, 0.5);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_4);

// Slerp
let rotation1 = Rotation2d::FRAC_PI_4);
let rotation2 = Rotation2d::degrees(-180.0); // we can use degrees too!
let result = rotation1.slerp(rotation2, 1.0 / 3.0);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_2);
```

There's also a `From<f32>` implementation for `Rotation2d`, which means
that methods can still accept radians as floats if the argument uses
`impl Into<Rotation2d>`. This means that adding `Rotation2d` shouldn't
even be a breaking change.

---

## Changelog

- Added `Rotation2d`
- Bounding volume methods now take an `impl Into<Rotation2d>`
- Gizmo methods with rotation now take an `impl Into<Rotation2d>`

## Future use cases

- Collision detection (a type like this is quite essential considering
how common vector rotations are)
- `Transform` helpers (e.g. return a 2D rotation about the Z axis from a
`Transform`)
- The rotation used for `Transform2d` (#8268)
- More gizmos, maybe meshes... everything in 2D that uses rotation

---------

Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Robert Walter <robwalter96@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-03-11 19:11:57 +00:00