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
|
|
|
}
|