Skip to content

Commit dc139ea

Browse files
committed
Add #[reflect(ignore)] for generic params
1 parent 9478432 commit dc139ea

File tree

10 files changed

+317
-200
lines changed

10 files changed

+317
-200
lines changed

crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ use bit_set::BitSet;
66
use quote::{quote, ToTokens};
77
use syn::token::Comma;
88

9+
use crate::generics::ReflectGenerics;
910
use crate::{
1011
utility, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME,
1112
TYPE_PATH_ATTRIBUTE_NAME,
1213
};
1314
use syn::punctuated::Punctuated;
1415
use syn::spanned::Spanned;
1516
use syn::{
16-
parse_str, Data, DeriveInput, Field, Fields, GenericParam, Generics, Ident, LitStr, Meta, Path,
17+
parse_str, Data, DeriveInput, Field, Fields, GenericParam, Ident, LitStr, Meta, Path,
1718
PathSegment, Type, TypeParam, Variant,
1819
};
1920

@@ -250,7 +251,7 @@ impl<'a> ReflectDerive<'a> {
250251
let type_path = ReflectTypePath::Internal {
251252
ident: &input.ident,
252253
custom_path,
253-
generics: &input.generics,
254+
generics: ReflectGenerics::new(&input.generics)?,
254255
};
255256

256257
let meta = ReflectMeta::new(type_path, traits);
@@ -467,8 +468,8 @@ impl<'a> ReflectStruct<'a> {
467468
&self.fields
468469
}
469470

470-
pub fn where_clause_options(&self) -> WhereClauseOptions {
471-
WhereClauseOptions::new(self.meta(), self.active_fields(), self.ignored_fields())
471+
pub fn where_clause_options(&self) -> Result<WhereClauseOptions, syn::Error> {
472+
WhereClauseOptions::new(self.meta())
472473
}
473474
}
474475

@@ -491,22 +492,8 @@ impl<'a> ReflectEnum<'a> {
491492
&self.variants
492493
}
493494

494-
/// Get an iterator of fields which are exposed to the reflection API
495-
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
496-
self.variants()
497-
.iter()
498-
.flat_map(|variant| variant.active_fields())
499-
}
500-
501-
/// Get an iterator of fields which are ignored by the reflection API
502-
pub fn ignored_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
503-
self.variants()
504-
.iter()
505-
.flat_map(|variant| variant.ignored_fields())
506-
}
507-
508-
pub fn where_clause_options(&self) -> WhereClauseOptions {
509-
WhereClauseOptions::new(self.meta(), self.active_fields(), self.ignored_fields())
495+
pub fn where_clause_options(&self) -> Result<WhereClauseOptions, syn::Error> {
496+
WhereClauseOptions::new(self.meta())
510497
}
511498
}
512499

@@ -581,7 +568,7 @@ pub(crate) enum ReflectTypePath<'a> {
581568
External {
582569
path: &'a Path,
583570
custom_path: Option<Path>,
584-
generics: &'a Generics,
571+
generics: ReflectGenerics,
585572
},
586573
/// The name of a type relative to its scope.
587574
///
@@ -594,7 +581,7 @@ pub(crate) enum ReflectTypePath<'a> {
594581
Internal {
595582
ident: &'a Ident,
596583
custom_path: Option<Path>,
597-
generics: &'a Generics,
584+
generics: ReflectGenerics,
598585
},
599586
/// Any [`syn::Type`] with only a defined `type_path` and `short_type_path`.
600587
#[allow(dead_code)]
@@ -644,17 +631,10 @@ impl<'a> ReflectTypePath<'a> {
644631
///
645632
/// [primitive]: ReflectTypePath::Primitive
646633
/// [anonymous]: ReflectTypePath::Anonymous
647-
pub fn generics(&self) -> &'a Generics {
648-
// Use a constant because we need to return a reference of at least 'a.
649-
const EMPTY_GENERICS: &Generics = &Generics {
650-
gt_token: None,
651-
lt_token: None,
652-
where_clause: None,
653-
params: Punctuated::new(),
654-
};
634+
pub fn generics(&self) -> &ReflectGenerics {
655635
match self {
656636
Self::Internal { generics, .. } | Self::External { generics, .. } => generics,
657-
_ => EMPTY_GENERICS,
637+
_ => ReflectGenerics::EMPTY,
658638
}
659639
}
660640

@@ -666,9 +646,8 @@ impl<'a> ReflectTypePath<'a> {
666646
// (which all have to be 'static anyway).
667647
!self
668648
.generics()
669-
.params
670-
.iter()
671-
.all(|param| matches!(param, GenericParam::Lifetime(_)))
649+
.params()
650+
.all(|(param, _)| matches!(param, GenericParam::Lifetime(_)))
672651
}
673652

674653
/// Returns the path interpreted as a [`Path`].
@@ -736,10 +715,10 @@ impl<'a> ReflectTypePath<'a> {
736715
///
737716
/// The `ty_generic_fn` param maps [`TypeParam`]s to [`StringExpr`]s.
738717
fn reduce_generics(
739-
generics: &Generics,
718+
generics: &ReflectGenerics,
740719
mut ty_generic_fn: impl FnMut(&TypeParam) -> StringExpr,
741720
) -> StringExpr {
742-
let mut params = generics.params.iter().filter_map(|param| match param {
721+
let mut params = generics.params().filter_map(|(param, _)| match param {
743722
GenericParam::Type(type_param) => Some(ty_generic_fn(type_param)),
744723
GenericParam::Const(const_param) => {
745724
let ident = &const_param.ident;

crates/bevy_reflect/bevy_reflect_derive/src/from_reflect.rs

Lines changed: 21 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,38 @@ use quote::{quote, ToTokens};
1010
use syn::{Field, Ident, Lit, LitInt, LitStr, Member};
1111

1212
/// Implements `FromReflect` for the given struct
13-
pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenStream {
13+
pub(crate) fn impl_struct(
14+
reflect_struct: &ReflectStruct,
15+
) -> Result<proc_macro2::TokenStream, syn::Error> {
1416
impl_struct_internal(reflect_struct, false)
1517
}
1618

1719
/// Implements `FromReflect` for the given tuple struct
18-
pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenStream {
20+
pub(crate) fn impl_tuple_struct(
21+
reflect_struct: &ReflectStruct,
22+
) -> Result<proc_macro2::TokenStream, syn::Error> {
1923
impl_struct_internal(reflect_struct, true)
2024
}
2125

22-
pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
26+
pub(crate) fn impl_value(meta: &ReflectMeta) -> Result<proc_macro2::TokenStream, syn::Error> {
2327
let type_path = meta.type_path();
2428
let bevy_reflect_path = meta.bevy_reflect_path();
2529
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
2630
let where_from_reflect_clause =
27-
extend_where_clause(where_clause, &WhereClauseOptions::new_value(meta));
28-
quote! {
31+
extend_where_clause(where_clause, &WhereClauseOptions::new(meta)?);
32+
Ok(quote! {
2933
impl #impl_generics #bevy_reflect_path::FromReflect for #type_path #ty_generics #where_from_reflect_clause {
3034
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
3135
#FQOption::Some(#FQClone::clone(<dyn #FQAny>::downcast_ref::<#type_path #ty_generics>(<dyn #bevy_reflect_path::Reflect>::as_any(reflect))?))
3236
}
3337
}
34-
}
38+
})
3539
}
3640

3741
/// Implements `FromReflect` for the given enum type
38-
pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream {
42+
pub(crate) fn impl_enum(
43+
reflect_enum: &ReflectEnum,
44+
) -> Result<proc_macro2::TokenStream, syn::Error> {
3945
let fqoption = FQOption.into_token_stream();
4046

4147
let enum_path = reflect_enum.meta().type_path();
@@ -50,24 +56,10 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
5056
let (impl_generics, ty_generics, where_clause) = enum_path.generics().split_for_impl();
5157

5258
// Add FromReflect bound for each active field
53-
let where_from_reflect_clause = extend_where_clause(
54-
where_clause,
55-
&WhereClauseOptions::new_with_bounds(
56-
reflect_enum.meta(),
57-
reflect_enum.active_fields(),
58-
reflect_enum.ignored_fields(),
59-
|field| match &field.attrs.default {
60-
DefaultBehavior::Default => Some(quote!(#FQDefault)),
61-
_ => None,
62-
},
63-
|field| match &field.attrs.default {
64-
DefaultBehavior::Func(_) => None,
65-
_ => Some(quote!(#FQDefault)),
66-
},
67-
),
68-
);
59+
let where_from_reflect_clause =
60+
extend_where_clause(where_clause, &WhereClauseOptions::new(reflect_enum.meta())?);
6961

70-
quote! {
62+
Ok(quote! {
7163
impl #impl_generics #bevy_reflect_path::FromReflect for #enum_path #ty_generics #where_from_reflect_clause {
7264
fn from_reflect(#ref_value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
7365
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) {
@@ -80,7 +72,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
8072
}
8173
}
8274
}
83-
}
75+
})
8476
}
8577

8678
/// Container for a struct's members (field name or index) and their
@@ -96,7 +88,7 @@ impl MemberValuePair {
9688
fn impl_struct_internal(
9789
reflect_struct: &ReflectStruct,
9890
is_tuple: bool,
99-
) -> proc_macro2::TokenStream {
91+
) -> Result<proc_macro2::TokenStream, syn::Error> {
10092
let fqoption = FQOption.into_token_stream();
10193

10294
let struct_path = reflect_struct.meta().type_path();
@@ -146,28 +138,10 @@ fn impl_struct_internal(
146138
// Add FromReflect bound for each active field
147139
let where_from_reflect_clause = extend_where_clause(
148140
where_clause,
149-
&WhereClauseOptions::new_with_bounds(
150-
reflect_struct.meta(),
151-
reflect_struct.active_fields(),
152-
reflect_struct.ignored_fields(),
153-
|field| match &field.attrs.default {
154-
DefaultBehavior::Default => Some(quote!(#FQDefault)),
155-
_ => None,
156-
},
157-
|field| {
158-
if is_defaultable {
159-
None
160-
} else {
161-
match &field.attrs.default {
162-
DefaultBehavior::Func(_) => None,
163-
_ => Some(quote!(#FQDefault)),
164-
}
165-
}
166-
},
167-
),
141+
&WhereClauseOptions::new(reflect_struct.meta())?,
168142
);
169143

170-
quote! {
144+
Ok(quote! {
171145
impl #impl_generics #bevy_reflect_path::FromReflect for #struct_path #ty_generics #where_from_reflect_clause {
172146
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
173147
if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct) = #bevy_reflect_path::Reflect::reflect_ref(reflect) {
@@ -177,7 +151,7 @@ fn impl_struct_internal(
177151
}
178152
}
179153
}
180-
}
154+
})
181155
}
182156

183157
/// Get the collection of ignored field definitions
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use crate::field_attributes::IGNORE_ALL_ATTR;
2+
use crate::REFLECT_ATTRIBUTE_NAME;
3+
use quote::ToTokens;
4+
use syn::punctuated::Punctuated;
5+
use syn::{
6+
Attribute, GenericParam, Generics, ImplGenerics, Meta, TypeGenerics, TypeParam, WhereClause,
7+
};
8+
9+
pub(crate) struct ReflectGenerics {
10+
generics: Generics,
11+
attrs: Vec<GenericParamAttr>,
12+
}
13+
14+
impl ReflectGenerics {
15+
pub const EMPTY: &ReflectGenerics = &ReflectGenerics {
16+
generics: Generics {
17+
gt_token: None,
18+
lt_token: None,
19+
where_clause: None,
20+
params: Punctuated::new(),
21+
},
22+
attrs: Vec::new(),
23+
};
24+
25+
pub fn new(generics: &Generics) -> Result<Self, syn::Error> {
26+
let mut generics = generics.clone();
27+
28+
let attrs = generics
29+
.params
30+
.iter_mut()
31+
.map(GenericParamAttr::from_param)
32+
.collect::<Result<Vec<_>, syn::Error>>()?;
33+
34+
Ok(Self { generics, attrs })
35+
}
36+
37+
pub fn params(&self) -> impl Iterator<Item = (&GenericParam, &GenericParamAttr)> {
38+
self.generics.params.iter().zip(self.attrs.iter())
39+
}
40+
41+
pub fn type_params(&self) -> impl Iterator<Item = (&TypeParam, &GenericParamAttr)> {
42+
self.params().filter_map(|(param, attr)| match param {
43+
GenericParam::Type(param) => Some((param, attr)),
44+
_ => None,
45+
})
46+
}
47+
48+
pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
49+
self.generics.split_for_impl()
50+
}
51+
}
52+
53+
#[derive(Default, Clone)]
54+
pub(crate) struct GenericParamAttr {
55+
pub ignore: bool,
56+
}
57+
58+
impl GenericParamAttr {
59+
fn from_param(param: &mut GenericParam) -> Result<Self, syn::Error> {
60+
match param {
61+
GenericParam::Type(param) => Self::from_type_attrs(&mut param.attrs),
62+
GenericParam::Lifetime(param) => Self::from_lifetime_attrs(&mut param.attrs),
63+
GenericParam::Const(param) => Self::from_const_attrs(&mut param.attrs),
64+
}
65+
}
66+
67+
fn from_type_attrs(attrs: &mut Vec<Attribute>) -> Result<Self, syn::Error> {
68+
let mut args = Self::default();
69+
let mut errors: Option<syn::Error> = None;
70+
71+
attrs.retain(|attr| {
72+
if attr.path().is_ident(REFLECT_ATTRIBUTE_NAME) {
73+
if let Err(err) = parse_meta(&mut args, &attr.meta) {
74+
if let Some(ref mut error) = errors {
75+
error.combine(err);
76+
} else {
77+
errors = Some(err);
78+
}
79+
}
80+
81+
false
82+
} else {
83+
true
84+
}
85+
});
86+
87+
if let Some(error) = errors {
88+
Err(error)
89+
} else {
90+
Ok(args)
91+
}
92+
}
93+
94+
fn from_lifetime_attrs(attrs: &mut [Attribute]) -> Result<Self, syn::Error> {
95+
match attrs
96+
.iter()
97+
.find(|attr| attr.path().is_ident(REFLECT_ATTRIBUTE_NAME))
98+
{
99+
Some(attr) => Err(syn::Error::new_spanned(
100+
attr,
101+
format!(
102+
"{REFLECT_ATTRIBUTE_NAME} attributes cannot be used on lifetime parameters"
103+
),
104+
)),
105+
None => Ok(Self::default()),
106+
}
107+
}
108+
109+
fn from_const_attrs(attrs: &mut [Attribute]) -> Result<Self, syn::Error> {
110+
match attrs
111+
.iter()
112+
.find(|attr| attr.path().is_ident(REFLECT_ATTRIBUTE_NAME))
113+
{
114+
Some(attr) => Err(syn::Error::new_spanned(
115+
attr,
116+
format!("{REFLECT_ATTRIBUTE_NAME} attributes cannot be used on const parameters"),
117+
)),
118+
None => Ok(Self::default()),
119+
}
120+
}
121+
}
122+
123+
fn parse_meta(args: &mut GenericParamAttr, meta: &Meta) -> Result<(), syn::Error> {
124+
let meta = meta.require_list()?;
125+
meta.parse_nested_meta(|meta| {
126+
if meta.path.is_ident(IGNORE_ALL_ATTR) {
127+
args.ignore = true;
128+
Ok(())
129+
} else {
130+
Err(syn::Error::new_spanned(
131+
&meta.path,
132+
format!("unknown attribute '{}'", meta.path.to_token_stream()),
133+
))
134+
}
135+
})
136+
}

0 commit comments

Comments
 (0)