Skip to content

Commit f039478

Browse files
committed
[reflection] cleanup derive_reflect (#2377)
# Objective - The current `derive_reflect` implementation is a large function with difficult to follow code paths. - When determining the "active fields" (e.g. those that don't use `#[reflect(ignore)]`) the logic is unnecessarily complex. ## Solution - Refactor `derive_reflect` by breaking into into smaller functions, and simplifying the logic for obtaining the "active fields".
1 parent 00f8394 commit f039478

File tree

1 file changed

+42
-63
lines changed
  • crates/bevy_reflect/bevy_reflect_derive/src

1 file changed

+42
-63
lines changed

crates/bevy_reflect/bevy_reflect_derive/src/lib.rs

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,10 @@ use syn::{
1414
parse_macro_input,
1515
punctuated::Punctuated,
1616
token::{Comma, Paren, Where},
17-
Data, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, Member, Meta, NestedMeta,
18-
Path,
17+
Attribute, Data, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, Member, Meta,
18+
NestedMeta, Path,
1919
};
2020

21-
#[derive(Default)]
22-
struct PropAttributeArgs {
23-
pub ignore: Option<bool>,
24-
}
25-
2621
#[derive(Clone)]
2722
enum TraitImpl {
2823
NotImplemented,
@@ -46,11 +41,47 @@ enum DeriveType {
4641
static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
4742
static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
4843

44+
fn active_fields(punctuated: &Punctuated<Field, Comma>) -> impl Iterator<Item = (&Field, usize)> {
45+
punctuated.iter().enumerate().filter_map(|(idx, field)| {
46+
field
47+
.attrs
48+
.iter()
49+
.find(|attr| attr.path.get_ident().unwrap() == REFLECT_ATTRIBUTE_NAME)
50+
.map(|attr| {
51+
syn::custom_keyword!(ignore);
52+
attr.parse_args::<Option<ignore>>()
53+
.expect("Invalid 'property' attribute format.")
54+
.is_none()
55+
})
56+
.unwrap_or(true)
57+
.then(|| (field, idx))
58+
})
59+
}
60+
61+
fn reflect_attrs(attrs: &[Attribute]) -> (ReflectAttrs, Option<DeriveType>) {
62+
for attribute in attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
63+
if let Meta::List(meta_list) = attribute {
64+
if let Some(ident) = meta_list.path.get_ident() {
65+
if ident == REFLECT_ATTRIBUTE_NAME {
66+
return (ReflectAttrs::from_nested_metas(&meta_list.nested), None);
67+
} else if ident == REFLECT_VALUE_ATTRIBUTE_NAME {
68+
return (
69+
ReflectAttrs::from_nested_metas(&meta_list.nested),
70+
Some(DeriveType::Value),
71+
);
72+
}
73+
}
74+
}
75+
}
76+
77+
Default::default()
78+
}
79+
4980
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value, module))]
5081
pub fn derive_reflect(input: TokenStream) -> TokenStream {
5182
let ast = parse_macro_input!(input as DeriveInput);
5283
let unit_struct_punctuated = Punctuated::new();
53-
let (fields, mut derive_type) = match &ast.data {
84+
let (fields, derive_type) = match &ast.data {
5485
Data::Struct(DataStruct {
5586
fields: Fields::Named(fields),
5687
..
@@ -66,66 +97,14 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream {
6697
_ => (&unit_struct_punctuated, DeriveType::Value),
6798
};
6899

69-
let fields_and_args = fields
70-
.iter()
71-
.enumerate()
72-
.map(|(i, f)| {
73-
(
74-
f,
75-
f.attrs
76-
.iter()
77-
.find(|a| *a.path.get_ident().as_ref().unwrap() == REFLECT_ATTRIBUTE_NAME)
78-
.map(|a| {
79-
syn::custom_keyword!(ignore);
80-
let mut attribute_args = PropAttributeArgs { ignore: None };
81-
a.parse_args_with(|input: ParseStream| {
82-
if input.parse::<Option<ignore>>()?.is_some() {
83-
attribute_args.ignore = Some(true);
84-
return Ok(());
85-
}
86-
Ok(())
87-
})
88-
.expect("Invalid 'property' attribute format.");
100+
let active_fields = active_fields(&fields).collect::<Vec<_>>();
89101

90-
attribute_args
91-
}),
92-
i,
93-
)
94-
})
95-
.collect::<Vec<(&Field, Option<PropAttributeArgs>, usize)>>();
96-
let active_fields = fields_and_args
97-
.iter()
98-
.filter(|(_field, attrs, _i)| {
99-
attrs.is_none()
100-
|| match attrs.as_ref().unwrap().ignore {
101-
Some(ignore) => !ignore,
102-
None => true,
103-
}
104-
})
105-
.map(|(f, _attr, i)| (*f, *i))
106-
.collect::<Vec<(&Field, usize)>>();
102+
let (reflect_attrs, modified_derive_type) = reflect_attrs(&ast.attrs);
103+
let derive_type = modified_derive_type.unwrap_or(derive_type);
107104

108105
let bevy_reflect_path = BevyManifest::default().get_path("bevy_reflect");
109106
let type_name = &ast.ident;
110107

111-
let mut reflect_attrs = ReflectAttrs::default();
112-
for attribute in ast.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
113-
let meta_list = if let Meta::List(meta_list) = attribute {
114-
meta_list
115-
} else {
116-
continue;
117-
};
118-
119-
if let Some(ident) = meta_list.path.get_ident() {
120-
if ident == REFLECT_ATTRIBUTE_NAME {
121-
reflect_attrs = ReflectAttrs::from_nested_metas(&meta_list.nested);
122-
} else if ident == REFLECT_VALUE_ATTRIBUTE_NAME {
123-
derive_type = DeriveType::Value;
124-
reflect_attrs = ReflectAttrs::from_nested_metas(&meta_list.nested);
125-
}
126-
}
127-
}
128-
129108
let registration_data = &reflect_attrs.data;
130109
let get_type_registration_impl = impl_get_type_registration(
131110
type_name,

0 commit comments

Comments
 (0)