2023-10-02 00:22:57 +00:00
|
|
|
//! This module contains unit structs that should be used inside `quote!` and `spanned_quote!`
|
|
|
|
//! using the variable interpolation syntax in place of their equivalent structs and traits
|
|
|
|
//! present in `std`.
|
|
|
|
//!
|
|
|
|
//! To create hygienic proc macros, all the names must be its fully qualified form. These
|
|
|
|
//! unit structs help us to not specify the fully qualified name every single time.
|
2022-12-05 23:39:44 +00:00
|
|
|
//!
|
|
|
|
//! # Example
|
|
|
|
//! Instead of writing this:
|
2024-01-01 16:50:56 +00:00
|
|
|
//! ```
|
|
|
|
//! # use quote::quote;
|
2022-12-05 23:39:44 +00:00
|
|
|
//! quote!(
|
|
|
|
//! fn get_id() -> Option<i32> {
|
|
|
|
//! Some(0)
|
|
|
|
//! }
|
2024-01-01 16:50:56 +00:00
|
|
|
//! );
|
2022-12-05 23:39:44 +00:00
|
|
|
//! ```
|
|
|
|
//! Or this:
|
2024-01-01 16:50:56 +00:00
|
|
|
//! ```
|
|
|
|
//! # use quote::quote;
|
2022-12-05 23:39:44 +00:00
|
|
|
//! quote!(
|
|
|
|
//! fn get_id() -> ::core::option::Option<i32> {
|
|
|
|
//! ::core::option::Option::Some(0)
|
|
|
|
//! }
|
2024-01-01 16:50:56 +00:00
|
|
|
//! );
|
2022-12-05 23:39:44 +00:00
|
|
|
//! ```
|
|
|
|
//! We should write this:
|
2024-01-01 16:50:56 +00:00
|
|
|
//! ```
|
|
|
|
//! use bevy_macro_utils::fq_std::FQOption;
|
|
|
|
//! # use quote::quote;
|
2022-12-05 23:39:44 +00:00
|
|
|
//!
|
|
|
|
//! quote!(
|
|
|
|
//! fn get_id() -> #FQOption<i32> {
|
|
|
|
//! #FQOption::Some(0)
|
|
|
|
//! }
|
2024-01-01 16:50:56 +00:00
|
|
|
//! );
|
2022-12-05 23:39:44 +00:00
|
|
|
//! ```
|
|
|
|
|
|
|
|
use proc_macro2::TokenStream;
|
|
|
|
use quote::{quote, ToTokens};
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`std::any::Any`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQAny;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Box`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQBox;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Clone`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQClone;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Default`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQDefault;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Option`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQOption;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Result`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQResult;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Send`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQSend;
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Fully Qualified (FQ) short name for [`Sync`]
|
2023-10-02 00:22:57 +00:00
|
|
|
pub struct FQSync;
|
2022-12-05 23:39:44 +00:00
|
|
|
|
|
|
|
impl ToTokens for FQAny {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::any::Any).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for FQBox {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::std::boxed::Box).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for FQClone {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::clone::Clone).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for FQDefault {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::default::Default).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for FQOption {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::option::Option).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for FQResult {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::result::Result).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
Enable deriving Reflect on structs with generic types (#7364)
# Objective
I recently had an issue, where I have a struct:
```
struct Property {
inner: T
}
```
that I use as a wrapper for internal purposes.
I don't want to update my struct definition to
```
struct Property<T: Reflect>{
inner: T
}
```
because I still want to be able to build `Property<T>` for types `T` that are not `Reflect`. (and also because I don't want to update my whole code base with `<T: Reflect>` bounds)
I still wanted to have reflection on it (for `bevy_inspector_egui`), but adding `derive(Reflect)` fails with the error:
`T cannot be sent between threads safely. T needs to implement Sync.`
I believe that `bevy_reflect` should adopt the model of other derives in the case of generics, which is to add the `Reflect` implementation only if the generics also implement `Reflect`. (That is the behaviour of other macros such as `derive(Clone)` or `derive(Debug)`.
It's also the current behavior of `derive(FromReflect)`.
Basically doing something like:
```
impl<T> Reflect for Foo<T>
where T: Reflect
```
## Solution
- I updated the derive macros for `Structs` and `TupleStructs` to add extra `where` bounds.
- Every type that is reflected will need a `T: Reflect` bound
- Ignored types will need a `T: 'static + Send + Sync` bound. Here's the reason. For cases like this:
```
#[derive(Reflect)]
struct Foo<T, U>{
a: T
#[reflect(ignore)]
b: U
}
```
I had to add the bound `'static + Send + Sync` to ignored generics like `U`.
The reason is that we want `Foo<T, U>` to be `Reflect: 'static + Send + Sync`, so `Foo<T, U>` must be able to implement those auto-traits. `Foo<T, U>` will only implement those auto-traits if every generic type implements them, including ignored types.
This means that the previously compile-fail case now compiles:
```
#[derive(Reflect)]
struct Foo<'a> {
#[reflect(ignore)]
value: &'a str,
}
```
But `Foo<'a>` will only be useable in the cases where `'a: 'static` and panic if we don't have `'a: 'static`, which is what we want (nice bonus from this PR ;) )
---
## Changelog
> This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section.
### Added
Possibility to add `derive(Reflect)` to structs and enums that contain generic types, like so:
```
#[derive(Reflect)]
struct Foo<T>{
a: T
}
```
Reflection will only be available if the generic type T also implements `Reflect`.
(previously, this would just return a compiler error)
2023-01-28 00:12:06 +00:00
|
|
|
|
|
|
|
impl ToTokens for FQSend {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::marker::Send).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for FQSync {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
|
quote!(::core::marker::Sync).to_tokens(tokens);
|
|
|
|
}
|
|
|
|
}
|