Suppress the `clippy::type_complexity` lint (#8313)
# Objective
The clippy lint `type_complexity` is known not to play well with bevy.
It frequently triggers when writing complex queries, and taking the
lint's advice of using a type alias almost always just obfuscates the
code with no benefit. Because of this, this lint is currently ignored in
CI, but unfortunately it still shows up when viewing bevy code in an
IDE.
As someone who's made a fair amount of pull requests to this repo, I
will say that this issue has been a consistent thorn in my side. Since
bevy code is filled with spurious, ignorable warnings, it can be very
difficult to spot the *real* warnings that must be fixed -- most of the
time I just ignore all warnings, only to later find out that one of them
was real after I'm done when CI runs.
## Solution
Suppress this lint in all bevy crates. This was previously attempted in
#7050, but the review process ended up making it more complicated than
it needs to be and landed on a subpar solution.
The discussion in https://github.com/rust-lang/rust-clippy/pull/10571
explores some better long-term solutions to this problem. Since there is
no timeline on when these solutions may land, we should resolve this
issue in the meantime by locally suppressing these lints.
### Unresolved issues
Currently, these lints are not suppressed in our examples, since that
would require suppressing the lint in every single source file. They are
still ignored in CI.
2023-04-06 21:27:36 +00:00
|
|
|
#![allow(clippy::type_complexity)]
|
|
|
|
|
2020-01-21 11:15:28 +00:00
|
|
|
extern crate proc_macro;
|
|
|
|
|
2020-06-04 03:08:20 +00:00
|
|
|
mod app_plugin;
|
2020-11-12 21:26:48 +00:00
|
|
|
mod bevy_main;
|
bevy_derive: Add derives for `Deref` and `DerefMut` (#4328)
# Objective
A common pattern in Rust is the [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). This is an especially useful pattern in Bevy as it allows us to give common/foreign types different semantics (such as allowing it to implement `Component` or `FromWorld`) or to simply treat them as a "new type" (clever). For example, it allows us to wrap a common `Vec<String>` and do things like:
```rust
#[derive(Component)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().0.push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
> We could then define another struct that wraps `Vec<String>` without anything clashing in the query.
However, one of the worst parts of this pattern is the ugly `.0` we have to write in order to access the type we actually care about. This is why people often implement `Deref` and `DerefMut` in order to get around this.
Since it's such a common pattern, especially for Bevy, it makes sense to add a derive macro to automatically add those implementations.
## Solution
Added a derive macro for `Deref` and another for `DerefMut` (both exported into the prelude). This works on all structs (including tuple structs) as long as they only contain a single field:
```rust
#[derive(Deref)]
struct Foo(String);
#[derive(Deref, DerefMut)]
struct Bar {
name: String,
}
```
This allows us to then remove that pesky `.0`:
```rust
#[derive(Component, Deref, DerefMut)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
### Alternatives
There are other alternatives to this such as by using the [`derive_more`](https://crates.io/crates/derive_more) crate. However, it doesn't seem like we need an entire crate just yet since we only need `Deref` and `DerefMut` (for now).
### Considerations
One thing to consider is that the Rust std library recommends _not_ using `Deref` and `DerefMut` for things like this: "`Deref` should only be implemented for smart pointers to avoid confusion" ([reference](https://doc.rust-lang.org/std/ops/trait.Deref.html)). Personally, I believe it makes sense to use it in the way described above, but others may disagree.
### Additional Context
Discord: https://discord.com/channels/691052431525675048/692572690833473578/956648422163746827 (controversiality discussed [here](https://discord.com/channels/691052431525675048/692572690833473578/956711911481835630))
---
## Changelog
- Add `Deref` derive macro (exported to prelude)
- Add `DerefMut` derive macro (exported to prelude)
- Updated most newtypes in examples to use one or both derives
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-03-29 02:10:06 +00:00
|
|
|
mod derefs;
|
2021-04-21 23:46:54 +00:00
|
|
|
mod enum_variant_meta;
|
2020-05-04 00:54:16 +00:00
|
|
|
|
2021-08-24 06:37:28 +00:00
|
|
|
use bevy_macro_utils::{derive_label, BevyManifest};
|
2020-01-19 10:02:12 +00:00
|
|
|
use proc_macro::TokenStream;
|
2021-08-24 06:37:28 +00:00
|
|
|
use quote::format_ident;
|
2020-03-18 23:06:33 +00:00
|
|
|
|
2022-04-27 19:08:11 +00:00
|
|
|
/// Generates a dynamic plugin entry point function for the given `Plugin` type.
|
2020-08-08 03:22:17 +00:00
|
|
|
#[proc_macro_derive(DynamicPlugin)]
|
2020-08-09 23:13:04 +00:00
|
|
|
pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
|
2020-08-08 03:22:17 +00:00
|
|
|
app_plugin::derive_dynamic_plugin(input)
|
2020-06-15 19:47:35 +00:00
|
|
|
}
|
2020-10-18 20:48:15 +00:00
|
|
|
|
bevy_derive: Add derives for `Deref` and `DerefMut` (#4328)
# Objective
A common pattern in Rust is the [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). This is an especially useful pattern in Bevy as it allows us to give common/foreign types different semantics (such as allowing it to implement `Component` or `FromWorld`) or to simply treat them as a "new type" (clever). For example, it allows us to wrap a common `Vec<String>` and do things like:
```rust
#[derive(Component)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().0.push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
> We could then define another struct that wraps `Vec<String>` without anything clashing in the query.
However, one of the worst parts of this pattern is the ugly `.0` we have to write in order to access the type we actually care about. This is why people often implement `Deref` and `DerefMut` in order to get around this.
Since it's such a common pattern, especially for Bevy, it makes sense to add a derive macro to automatically add those implementations.
## Solution
Added a derive macro for `Deref` and another for `DerefMut` (both exported into the prelude). This works on all structs (including tuple structs) as long as they only contain a single field:
```rust
#[derive(Deref)]
struct Foo(String);
#[derive(Deref, DerefMut)]
struct Bar {
name: String,
}
```
This allows us to then remove that pesky `.0`:
```rust
#[derive(Component, Deref, DerefMut)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
### Alternatives
There are other alternatives to this such as by using the [`derive_more`](https://crates.io/crates/derive_more) crate. However, it doesn't seem like we need an entire crate just yet since we only need `Deref` and `DerefMut` (for now).
### Considerations
One thing to consider is that the Rust std library recommends _not_ using `Deref` and `DerefMut` for things like this: "`Deref` should only be implemented for smart pointers to avoid confusion" ([reference](https://doc.rust-lang.org/std/ops/trait.Deref.html)). Personally, I believe it makes sense to use it in the way described above, but others may disagree.
### Additional Context
Discord: https://discord.com/channels/691052431525675048/692572690833473578/956648422163746827 (controversiality discussed [here](https://discord.com/channels/691052431525675048/692572690833473578/956711911481835630))
---
## Changelog
- Add `Deref` derive macro (exported to prelude)
- Add `DerefMut` derive macro (exported to prelude)
- Updated most newtypes in examples to use one or both derives
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-03-29 02:10:06 +00:00
|
|
|
/// Implements [`Deref`] for _single-item_ structs. This is especially useful when
|
|
|
|
/// utilizing the [newtype] pattern.
|
|
|
|
///
|
|
|
|
/// If you need [`DerefMut`] as well, consider using the other [derive] macro alongside
|
|
|
|
/// this one.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bevy_derive::Deref;
|
|
|
|
///
|
|
|
|
/// #[derive(Deref)]
|
|
|
|
/// struct MyNewtype(String);
|
|
|
|
///
|
|
|
|
/// let foo = MyNewtype(String::from("Hello"));
|
|
|
|
/// assert_eq!(5, foo.len());
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [`Deref`]: std::ops::Deref
|
|
|
|
/// [newtype]: https://doc.rust-lang.org/rust-by-example/generics/new_types.html
|
|
|
|
/// [`DerefMut`]: std::ops::DerefMut
|
|
|
|
/// [derive]: crate::derive_deref_mut
|
|
|
|
#[proc_macro_derive(Deref)]
|
|
|
|
pub fn derive_deref(input: TokenStream) -> TokenStream {
|
|
|
|
derefs::derive_deref(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Implements [`DerefMut`] for _single-item_ structs. This is especially useful when
|
|
|
|
/// utilizing the [newtype] pattern.
|
|
|
|
///
|
|
|
|
/// [`DerefMut`] requires a [`Deref`] implementation. You can implement it manually or use
|
|
|
|
/// Bevy's [derive] macro for convenience.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bevy_derive::{Deref, DerefMut};
|
|
|
|
///
|
|
|
|
/// #[derive(Deref, DerefMut)]
|
|
|
|
/// struct MyNewtype(String);
|
|
|
|
///
|
|
|
|
/// let mut foo = MyNewtype(String::from("Hello"));
|
|
|
|
/// foo.push_str(" World!");
|
|
|
|
/// assert_eq!("Hello World!", *foo);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [`DerefMut`]: std::ops::DerefMut
|
|
|
|
/// [newtype]: https://doc.rust-lang.org/rust-by-example/generics/new_types.html
|
|
|
|
/// [`Deref`]: std::ops::Deref
|
|
|
|
/// [derive]: crate::derive_deref
|
|
|
|
#[proc_macro_derive(DerefMut)]
|
|
|
|
pub fn derive_deref_mut(input: TokenStream) -> TokenStream {
|
|
|
|
derefs::derive_deref_mut(input)
|
|
|
|
}
|
|
|
|
|
2020-11-12 21:26:48 +00:00
|
|
|
#[proc_macro_attribute]
|
|
|
|
pub fn bevy_main(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
|
bevy_main::bevy_main(attr, item)
|
|
|
|
}
|
2021-04-21 23:46:54 +00:00
|
|
|
|
2021-05-19 19:03:36 +00:00
|
|
|
#[proc_macro_derive(EnumVariantMeta)]
|
2021-04-21 23:46:54 +00:00
|
|
|
pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
|
|
|
|
enum_variant_meta::derive_enum_variant_meta(input)
|
|
|
|
}
|
2021-08-24 06:37:28 +00:00
|
|
|
|
Add attribute to ignore fields of derived labels (#5366)
# Objective
Fixes #5362
## Solution
Add the attribute `#[label(ignore_fields)]` for `*Label` types.
```rust
#[derive(SystemLabel)]
pub enum MyLabel {
One,
// Previously this was not allowed since labels cannot contain data.
#[system_label(ignore_fields)]
Two(PhantomData<usize>),
}
```
## Notes
This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example:
```rust
#[derive(SystemLabel, PartialEq, Eq)]
#[system_label(ignore_fields)]
pub struct Foo(usize);
```
If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a `Foo`, the derive will incorrectly compare the inner fields. I see a few solutions
1. Do nothing. This is technically intended behavior, but I think we should do our best to prevent footguns.
2. Generate impls of `PartialEq` and `Eq` along with the `#[derive(Label)]` macros. This is a breaking change as it requires all users to remove these derives from their types.
3. Only allow `PhantomData` to be used with `ignore_fields` -- seems needlessly prescriptive.
---
## Changelog
* Added the `ignore_fields` attribute to the derive macros for `*Label` types.
* Added an example showing off different forms of the derive macro.
<!--
## Migration Guide
> This section is optional. If there are no breaking changes, you can delete this section.
- If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes
- Simply adding new functionality is not a breaking change.
- Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change.
-->
2022-07-19 05:21:19 +00:00
|
|
|
/// Generates an impl of the `AppLabel` trait.
|
|
|
|
///
|
|
|
|
/// This works only for unit structs, or enums with only unit variants.
|
|
|
|
/// You may force a struct or variant to behave as if it were fieldless with `#[app_label(ignore_fields)]`.
|
|
|
|
#[proc_macro_derive(AppLabel, attributes(app_label))]
|
2021-08-24 06:37:28 +00:00
|
|
|
pub fn derive_app_label(input: TokenStream) -> TokenStream {
|
|
|
|
let input = syn::parse_macro_input!(input as syn::DeriveInput);
|
|
|
|
let mut trait_path = BevyManifest::default().get_path("bevy_app");
|
|
|
|
trait_path.segments.push(format_ident!("AppLabel").into());
|
Add attribute to ignore fields of derived labels (#5366)
# Objective
Fixes #5362
## Solution
Add the attribute `#[label(ignore_fields)]` for `*Label` types.
```rust
#[derive(SystemLabel)]
pub enum MyLabel {
One,
// Previously this was not allowed since labels cannot contain data.
#[system_label(ignore_fields)]
Two(PhantomData<usize>),
}
```
## Notes
This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example:
```rust
#[derive(SystemLabel, PartialEq, Eq)]
#[system_label(ignore_fields)]
pub struct Foo(usize);
```
If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a `Foo`, the derive will incorrectly compare the inner fields. I see a few solutions
1. Do nothing. This is technically intended behavior, but I think we should do our best to prevent footguns.
2. Generate impls of `PartialEq` and `Eq` along with the `#[derive(Label)]` macros. This is a breaking change as it requires all users to remove these derives from their types.
3. Only allow `PhantomData` to be used with `ignore_fields` -- seems needlessly prescriptive.
---
## Changelog
* Added the `ignore_fields` attribute to the derive macros for `*Label` types.
* Added an example showing off different forms of the derive macro.
<!--
## Migration Guide
> This section is optional. If there are no breaking changes, you can delete this section.
- If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes
- Simply adding new functionality is not a breaking change.
- Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change.
-->
2022-07-19 05:21:19 +00:00
|
|
|
derive_label(input, &trait_path, "app_label")
|
2021-08-24 06:37:28 +00:00
|
|
|
}
|