mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
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.
This commit is contained in:
parent
42ba9dfaea
commit
705c144259
3 changed files with 45 additions and 101 deletions
|
@ -92,24 +92,6 @@ impl FromReflectAttrs {
|
|||
.map(|lit| lit.value())
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Merges this [`FromReflectAttrs`] with another.
|
||||
pub fn merge(&mut self, other: FromReflectAttrs) -> Result<(), syn::Error> {
|
||||
if let Some(new) = other.auto_derive {
|
||||
if let Some(existing) = &self.auto_derive {
|
||||
if existing.value() != new.value() {
|
||||
return Err(syn::Error::new(
|
||||
new.span(),
|
||||
format!("`{FROM_REFLECT_ATTR}` already set to {}", existing.value()),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
self.auto_derive = Some(new);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of attributes used for deriving `TypePath` via the `Reflect` derive.
|
||||
|
@ -133,24 +115,6 @@ impl TypePathAttrs {
|
|||
.map(|lit| lit.value())
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Merges this [`TypePathAttrs`] with another.
|
||||
pub fn merge(&mut self, other: TypePathAttrs) -> Result<(), syn::Error> {
|
||||
if let Some(new) = other.auto_derive {
|
||||
if let Some(existing) = &self.auto_derive {
|
||||
if existing.value() != new.value() {
|
||||
return Err(syn::Error::new(
|
||||
new.span(),
|
||||
format!("`{TYPE_PATH_ATTR}` already set to {}", existing.value()),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
self.auto_derive = Some(new);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of traits that have been registered for a reflected type.
|
||||
|
@ -231,14 +195,16 @@ impl ContainerAttributes {
|
|||
///
|
||||
/// # Example
|
||||
/// - `Hash, Debug(custom_debug), MyTrait`
|
||||
pub fn parse_terminated(input: ParseStream, trait_: ReflectTraitToImpl) -> syn::Result<Self> {
|
||||
let mut this = Self::default();
|
||||
|
||||
pub fn parse_terminated(
|
||||
&mut self,
|
||||
input: ParseStream,
|
||||
trait_: ReflectTraitToImpl,
|
||||
) -> syn::Result<()> {
|
||||
terminated_parser(Token![,], |stream| {
|
||||
this.parse_container_attribute(stream, trait_)
|
||||
self.parse_container_attribute(stream, trait_)
|
||||
})(input)?;
|
||||
|
||||
Ok(this)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parse the contents of a `#[reflect(...)]` attribute into a [`ContainerAttributes`] instance.
|
||||
|
@ -246,8 +212,12 @@ impl ContainerAttributes {
|
|||
/// # Example
|
||||
/// - `#[reflect(Hash, Debug(custom_debug), MyTrait)]`
|
||||
/// - `#[reflect(no_field_bounds)]`
|
||||
pub fn parse_meta_list(meta: &MetaList, trait_: ReflectTraitToImpl) -> syn::Result<Self> {
|
||||
meta.parse_args_with(|stream: ParseStream| Self::parse_terminated(stream, trait_))
|
||||
pub fn parse_meta_list(
|
||||
&mut self,
|
||||
meta: &MetaList,
|
||||
trait_: ReflectTraitToImpl,
|
||||
) -> syn::Result<()> {
|
||||
meta.parse_args_with(|stream: ParseStream| self.parse_terminated(stream, trait_))
|
||||
}
|
||||
|
||||
/// Parse a single container attribute.
|
||||
|
@ -392,7 +362,7 @@ impl ContainerAttributes {
|
|||
trait_: ReflectTraitToImpl,
|
||||
) -> syn::Result<()> {
|
||||
let pair = input.parse::<MetaNameValue>()?;
|
||||
let value = extract_bool(&pair.value, |lit| {
|
||||
let extracted_bool = extract_bool(&pair.value, |lit| {
|
||||
// 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.
|
||||
|
@ -401,7 +371,16 @@ impl ContainerAttributes {
|
|||
.unwrap_or_else(|| lit.clone())
|
||||
})?;
|
||||
|
||||
self.from_reflect_attrs.auto_derive = Some(value);
|
||||
if let Some(existing) = &self.from_reflect_attrs.auto_derive {
|
||||
if existing.value() != extracted_bool.value() {
|
||||
return Err(syn::Error::new(
|
||||
extracted_bool.span(),
|
||||
format!("`{FROM_REFLECT_ATTR}` already set to {}", existing.value()),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
self.from_reflect_attrs.auto_derive = Some(extracted_bool);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -416,7 +395,7 @@ impl ContainerAttributes {
|
|||
trait_: ReflectTraitToImpl,
|
||||
) -> syn::Result<()> {
|
||||
let pair = input.parse::<MetaNameValue>()?;
|
||||
let value = extract_bool(&pair.value, |lit| {
|
||||
let extracted_bool = extract_bool(&pair.value, |lit| {
|
||||
// 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.
|
||||
|
@ -425,7 +404,16 @@ impl ContainerAttributes {
|
|||
.unwrap_or_else(|| lit.clone())
|
||||
})?;
|
||||
|
||||
self.type_path_attrs.auto_derive = Some(value);
|
||||
if let Some(existing) = &self.type_path_attrs.auto_derive {
|
||||
if existing.value() != extracted_bool.value() {
|
||||
return Err(syn::Error::new(
|
||||
extracted_bool.span(),
|
||||
format!("`{TYPE_PATH_ATTR}` already set to {}", existing.value()),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
self.type_path_attrs.auto_derive = Some(extracted_bool);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -530,50 +518,6 @@ impl ContainerAttributes {
|
|||
pub fn no_field_bounds(&self) -> bool {
|
||||
self.no_field_bounds
|
||||
}
|
||||
|
||||
/// Merges the trait implementations of this [`ContainerAttributes`] with another one.
|
||||
///
|
||||
/// An error is returned if the two [`ContainerAttributes`] have conflicting implementations.
|
||||
pub fn merge(&mut self, other: ContainerAttributes) -> Result<(), syn::Error> {
|
||||
// Destructuring is used to help ensure that all fields are merged
|
||||
let Self {
|
||||
debug,
|
||||
hash,
|
||||
partial_eq,
|
||||
from_reflect_attrs,
|
||||
type_path_attrs,
|
||||
custom_where,
|
||||
no_field_bounds,
|
||||
idents,
|
||||
} = self;
|
||||
|
||||
debug.merge(other.debug)?;
|
||||
hash.merge(other.hash)?;
|
||||
partial_eq.merge(other.partial_eq)?;
|
||||
from_reflect_attrs.merge(other.from_reflect_attrs)?;
|
||||
type_path_attrs.merge(other.type_path_attrs)?;
|
||||
|
||||
Self::merge_custom_where(custom_where, other.custom_where);
|
||||
|
||||
*no_field_bounds |= other.no_field_bounds;
|
||||
|
||||
for ident in other.idents {
|
||||
add_unique_ident(idents, ident)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn merge_custom_where(this: &mut Option<WhereClause>, other: Option<WhereClause>) {
|
||||
match (this, other) {
|
||||
(Some(this), Some(other)) => {
|
||||
this.predicates.extend(other.predicates);
|
||||
}
|
||||
(this @ None, Some(other)) => {
|
||||
*this = Some(other);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an identifier to a vector of identifiers if it is not already present.
|
||||
|
|
|
@ -183,7 +183,7 @@ impl<'a> ReflectDerive<'a> {
|
|||
input: &'a DeriveInput,
|
||||
provenance: ReflectProvenance,
|
||||
) -> Result<Self, syn::Error> {
|
||||
let mut traits = ContainerAttributes::default();
|
||||
let mut container_attributes = ContainerAttributes::default();
|
||||
// Should indicate whether `#[reflect_value]` was used.
|
||||
let mut reflect_mode = None;
|
||||
// Should indicate whether `#[type_path = "..."]` was used.
|
||||
|
@ -205,9 +205,7 @@ impl<'a> ReflectDerive<'a> {
|
|||
}
|
||||
|
||||
reflect_mode = Some(ReflectMode::Normal);
|
||||
let new_traits =
|
||||
ContainerAttributes::parse_meta_list(meta_list, provenance.trait_)?;
|
||||
traits.merge(new_traits)?;
|
||||
container_attributes.parse_meta_list(meta_list, provenance.trait_)?;
|
||||
}
|
||||
Meta::List(meta_list) if meta_list.path.is_ident(REFLECT_VALUE_ATTRIBUTE_NAME) => {
|
||||
if !matches!(reflect_mode, None | Some(ReflectMode::Value)) {
|
||||
|
@ -218,9 +216,7 @@ impl<'a> ReflectDerive<'a> {
|
|||
}
|
||||
|
||||
reflect_mode = Some(ReflectMode::Value);
|
||||
let new_traits =
|
||||
ContainerAttributes::parse_meta_list(meta_list, provenance.trait_)?;
|
||||
traits.merge(new_traits)?;
|
||||
container_attributes.parse_meta_list(meta_list, provenance.trait_)?;
|
||||
}
|
||||
Meta::Path(path) if path.is_ident(REFLECT_VALUE_ATTRIBUTE_NAME) => {
|
||||
if !matches!(reflect_mode, None | Some(ReflectMode::Value)) {
|
||||
|
@ -296,7 +292,7 @@ impl<'a> ReflectDerive<'a> {
|
|||
generics: &input.generics,
|
||||
};
|
||||
|
||||
let meta = ReflectMeta::new(type_path, traits);
|
||||
let meta = ReflectMeta::new(type_path, container_attributes);
|
||||
|
||||
if provenance.source == ReflectImplSource::ImplRemoteType
|
||||
&& meta.type_path_attrs().should_auto_derive()
|
||||
|
@ -439,7 +435,7 @@ impl<'a> ReflectMeta<'a> {
|
|||
Self { docs, ..self }
|
||||
}
|
||||
|
||||
/// The registered reflect traits on this struct.
|
||||
/// The registered reflect attributes on this struct.
|
||||
pub fn attrs(&self) -> &ContainerAttributes {
|
||||
&self.attrs
|
||||
}
|
||||
|
|
|
@ -55,7 +55,11 @@ impl ReflectValueDef {
|
|||
if input.peek(Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
traits = Some(ContainerAttributes::parse_terminated(&content, trait_)?);
|
||||
traits = Some({
|
||||
let mut attrs = ContainerAttributes::default();
|
||||
attrs.parse_terminated(&content, trait_)?;
|
||||
attrs
|
||||
});
|
||||
}
|
||||
Ok(ReflectValueDef {
|
||||
attrs,
|
||||
|
|
Loading…
Reference in a new issue