Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reflection: replace impl_reflect_struct with impl_reflect #11437

Merged
merged 8 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
//! the derive helper attribute for `Reflect`, which looks like:
//! `#[reflect(PartialEq, Default, ...)]` and `#[reflect_value(PartialEq, Default, ...)]`.

use crate::derive_data::ReflectTraitToImpl;
use crate::utility;
use bevy_macro_utils::fq_std::{FQAny, FQOption};
use proc_macro2::{Ident, Span};
use quote::quote_spanned;
use syn::parse::{Parse, ParseStream};
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
Expand Down Expand Up @@ -217,7 +218,7 @@ pub(crate) struct ReflectTraits {
impl ReflectTraits {
pub fn from_metas(
metas: Punctuated<Meta, Comma>,
is_from_reflect_derive: bool,
trait_: ReflectTraitToImpl,
) -> Result<Self, syn::Error> {
let mut traits = ReflectTraits::default();
for meta in &metas {
Expand Down Expand Up @@ -294,7 +295,7 @@ impl ReflectTraits {
// Override `lit` if this is a `FromReflect` derive.
// This typically means a user is opting out of the default implementation
// from the `Reflect` derive and using the `FromReflect` derive directly instead.
is_from_reflect_derive
(trait_ == ReflectTraitToImpl::FromReflect)
.then(|| LitBool::new(true, Span::call_site()))
.unwrap_or_else(|| lit.clone())
})?);
Expand All @@ -311,6 +312,10 @@ impl ReflectTraits {
Ok(traits)
}

pub fn parse(input: ParseStream, trait_: ReflectTraitToImpl) -> syn::Result<Self> {
ReflectTraits::from_metas(Punctuated::parse_terminated(input)?, trait_)
}

/// Returns true if the given reflected trait name (i.e. `ReflectDefault` for `Default`)
/// is registered for this type.
pub fn contains(&self, name: &str) -> bool {
Expand Down Expand Up @@ -418,12 +423,6 @@ impl ReflectTraits {
}
}

impl Parse for ReflectTraits {
fn parse(input: ParseStream) -> syn::Result<Self> {
ReflectTraits::from_metas(Punctuated::<Meta, Comma>::parse_terminated(input)?, false)
}
}

/// Adds an identifier to a vector of identifiers if it is not already present.
///
/// Returns an error if the identifier already exists in the list.
Expand Down
54 changes: 51 additions & 3 deletions crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::fmt;

use crate::container_attributes::{FromReflectAttrs, ReflectTraits};
use crate::field_attributes::{parse_field_attrs, ReflectFieldAttr};
use crate::type_path::parse_path_no_leading_colon;
Expand Down Expand Up @@ -140,10 +142,46 @@ enum ReflectMode {
Value,
}

/// How the macro was invoked.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum ReflectImplSource {
ImplRemoteType,
DeriveLocalType,
}

/// Which trait the macro explicitly implements.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum ReflectTraitToImpl {
Reflect,
FromReflect,
TypePath,
}

/// The provenance of a macro invocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) struct ReflectProvenance {
pub source: ReflectImplSource,
pub trait_: ReflectTraitToImpl,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bikeshed: Rather than having to add the _ suffix, maybe we could rename this to trait_target (maybe even renaming ReflectTraitToImpl to ReflectTraitTarget) or trait_to_impl or something similar.

}

impl fmt::Display for ReflectProvenance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::{ReflectImplSource as S, ReflectTraitToImpl as T};
let str = match (self.source, self.trait_) {
(S::ImplRemoteType, T::Reflect) => "`impl_reflect`",
(S::DeriveLocalType, T::Reflect) => "`#[derive(Reflect)]`",
(S::DeriveLocalType, T::FromReflect) => "`#[derive(FromReflect)]`",
(S::DeriveLocalType, T::TypePath) => "`#[derive(TypePath)]`",
(S::ImplRemoteType, T::FromReflect | T::TypePath) => unreachable!(),
};
f.write_str(str)
}
}

impl<'a> ReflectDerive<'a> {
pub fn from_input(
input: &'a DeriveInput,
is_from_reflect_derive: bool,
provenance: ReflectProvenance,
) -> Result<Self, syn::Error> {
let mut traits = ReflectTraits::default();
// Should indicate whether `#[reflect_value]` was used.
Expand All @@ -169,7 +207,7 @@ impl<'a> ReflectDerive<'a> {
reflect_mode = Some(ReflectMode::Normal);
let new_traits = ReflectTraits::from_metas(
meta_list.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)?,
is_from_reflect_derive,
provenance.trait_,
)?;
traits.merge(new_traits)?;
}
Expand All @@ -184,7 +222,7 @@ impl<'a> ReflectDerive<'a> {
reflect_mode = Some(ReflectMode::Value);
let new_traits = ReflectTraits::from_metas(
meta_list.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)?,
is_from_reflect_derive,
provenance.trait_,
)?;
traits.merge(new_traits)?;
}
Expand Down Expand Up @@ -264,6 +302,16 @@ impl<'a> ReflectDerive<'a> {

let meta = ReflectMeta::new(type_path, traits);

if provenance.source == ReflectImplSource::ImplRemoteType
&& meta.traits.type_path_attrs().should_auto_derive()
soqb marked this conversation as resolved.
Show resolved Hide resolved
&& !meta.type_path().has_custom_path()
{
return Err(syn::Error::new(
meta.type_path().span(),
format!("a #[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"] attribute must be specified when using {provenance}")
));
Comment on lines +303 to +306
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

}

#[cfg(feature = "documentation")]
let meta = meta.with_docs(doc);

Expand Down
Loading
Loading