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

[Merged by Bors] - Add macro to implement reflect for struct types and migrate glam types #4540

Closed
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
71a770f
Implemented impl_reflect_struct
PROMETHIA-27 Apr 19, 2022
5860496
Testing impl_reflect_struct
PROMETHIA-27 Apr 19, 2022
478d9ce
Rephrased impl_struct for from_reflect
PROMETHIA-27 Apr 19, 2022
650e7a7
Added from_reflect to impl_reflect_struct
PROMETHIA-27 Apr 19, 2022
fd4f58d
Altered impl_struct to accept a custom constructor
PROMETHIA-27 Apr 19, 2022
9a9aaf6
Verified trait reflection
PROMETHIA-27 Apr 19, 2022
401fe37
Switched all (less quats) impls to structs
PROMETHIA-27 Apr 19, 2022
6592abe
Removed messy temp test
PROMETHIA-27 Apr 19, 2022
ac61dd2
Ran cargo fmt
PROMETHIA-27 Apr 19, 2022
44b06ba
Added bevy_reflect path override
PROMETHIA-27 Apr 20, 2022
b584f14
Restored `impl_from_reflect_value` for Quat/DQuat
PROMETHIA-27 Apr 21, 2022
fb4c12e
Added use for impl_from_reflect_value
PROMETHIA-27 Apr 21, 2022
1bdefbf
Ran cargo fmt again
PROMETHIA-27 Apr 21, 2022
c5d8ce1
Added tests for Vec3 serialization behavior
PROMETHIA-27 Apr 23, 2022
ed5372f
Ran cargo fmt --all
PROMETHIA-27 Apr 23, 2022
44f66c9
Split parsing into a separate Parse struct
PROMETHIA-27 Apr 25, 2022
b6c196e
Added tests for Vec3 reflection behavior
PROMETHIA-27 Apr 25, 2022
cbbae2b
Merge branch 'main' into glam-vec_struct_reflect_type
PROMETHIA-27 Apr 25, 2022
1e7cd55
Added docstrings
PROMETHIA-27 Apr 26, 2022
080971d
Fixed parsing issue
PROMETHIA-27 Apr 26, 2022
db1cd60
Updated parsing to use custom_keyword!()
PROMETHIA-27 Apr 26, 2022
b83578a
Ran cargo fmt --all
PROMETHIA-27 Apr 26, 2022
7f46274
Added panics for enum and union cases
PROMETHIA-27 Apr 26, 2022
a42f5f0
Switched to attribute-based overrides
PROMETHIA-27 Apr 26, 2022
3ef21d9
Ran cargo fmt --all
PROMETHIA-27 Apr 26, 2022
b2ae524
Added doc comment link backticks
PROMETHIA-27 Apr 26, 2022
91e8255
Fixed doc links, ignored doc comment examples
PROMETHIA-27 Apr 27, 2022
1f90de7
Changed to syn::Error instead of panics
PROMETHIA-27 Apr 27, 2022
21cc040
Switched from syn::Error::new to new_spanned
PROMETHIA-27 Apr 27, 2022
133d2be
Renamed to impl_reflect_struct
PROMETHIA-27 Apr 28, 2022
abf7ed2
Fix use statement
PROMETHIA-27 Apr 28, 2022
f4c3478
Cargo fmt --all
PROMETHIA-27 Apr 28, 2022
8ef79e1
Add reflect(Default) to glam types
PROMETHIA-27 May 5, 2022
259ca60
Merge branch 'bevyengine:main' into glam-vec_struct_reflect_type
PROMETHIA-27 May 5, 2022
7bbff47
Add `use create::prelude::ReflectDefault`
PROMETHIA-27 May 5, 2022
cdae659
Removed explicit ctor attribute
PROMETHIA-27 May 5, 2022
d6232eb
Fixed clippy warning
PROMETHIA-27 May 5, 2022
1864fb3
Removed instances of `use bevy_reflect::Struct`
PROMETHIA-27 May 5, 2022
35bde41
Removed uses of path special attribute
PROMETHIA-27 May 5, 2022
ca0c3a5
cargo fmt --all
PROMETHIA-27 May 5, 2022
dd4c158
Updated doc comments
PROMETHIA-27 May 6, 2022
ad8637f
Fix doc space
PROMETHIA-27 May 8, 2022
907ea55
Split comment into quick and extended summaries
PROMETHIA-27 May 8, 2022
ae91dc6
Merge branch 'bevyengine:main' into glam-vec_struct_reflect_type
PROMETHIA-27 May 8, 2022
27755a3
Replace outdated explanations of special attrs
PROMETHIA-27 May 8, 2022
8b0a422
Merge branch 'glam-vec_struct_reflect_type' of https://github.com/PRO…
PROMETHIA-27 May 8, 2022
9a73dfe
Explain type must be in scope
PROMETHIA-27 May 8, 2022
68fef52
Explain example
PROMETHIA-27 May 8, 2022
467a39a
Show Vec3 in scope
PROMETHIA-27 May 8, 2022
2f63312
.into -> TokenStream::from
PROMETHIA-27 May 8, 2022
c262d94
Merge branch 'glam-vec_struct_reflect_type' of https://github.com/PRO…
PROMETHIA-27 May 8, 2022
7aa58db
Cargo fmt --all
PROMETHIA-27 May 8, 2022
05f4f0b
ctor -> constructor
PROMETHIA-27 May 9, 2022
7683aa9
ctor -> constructor
PROMETHIA-27 May 9, 2022
58e127c
ctor -> constructor
PROMETHIA-27 May 9, 2022
ca936c8
ctor -> constructor
PROMETHIA-27 May 9, 2022
b7d76fb
last ctor -> constructor batch
PROMETHIA-27 May 9, 2022
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
33 changes: 25 additions & 8 deletions crates/bevy_reflect/bevy_reflect_derive/src/from_reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn impl_struct(
bevy_reflect_path: &Path,
active_fields: &[(&Field, usize)],
ignored_fields: &[(&Field, usize)],
custom_ctor: Option<proc_macro2::TokenStream>,
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
) -> TokenStream {
let field_names = active_fields
.iter()
Expand Down Expand Up @@ -60,20 +61,36 @@ pub fn impl_struct(
#(#field_types: #bevy_reflect_path::FromReflect,)*
});

let ctor = if let Some(ctor) = custom_ctor {
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
quote!(
let mut value: Self = #ctor;
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
#(
value.#field_idents = {
<#field_types as #bevy_reflect_path::FromReflect>::from_reflect(ref_struct.field(#field_names)?)?
};
)*
Some(value)
)
} else {
quote!(
Some(
Self {
#(#field_idents: {
<#field_types as #bevy_reflect_path::FromReflect>::from_reflect(ref_struct.field(#field_names)?)?
},)*
#(#ignored_field_idents: Default::default(),)*
}
)
)
};

TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #struct_name #ty_generics #where_from_reflect_clause
{
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> Option<Self> {
use #bevy_reflect_path::Struct;
if let #bevy_reflect_path::ReflectRef::Struct(ref_struct) = reflect.reflect_ref() {
Some(
Self{
#(#field_idents: {
<#field_types as #bevy_reflect_path::FromReflect>::from_reflect(ref_struct.field(#field_names)?)?
},)*
#(#ignored_field_idents: Default::default(),)*
}
)
#ctor
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
} else {
None
}
Expand Down
150 changes: 150 additions & 0 deletions crates/bevy_reflect/bevy_reflect_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,155 @@ pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
)
}

#[proc_macro]
pub fn impl_reflect_struct_and_from_reflect_struct(input: TokenStream) -> TokenStream {
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
let mut iter = input.into_iter().peekable();
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
let (r#constructor, ctor) = (iter.next().unwrap(), iter.next().unwrap());
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
match r#constructor {
proc_macro::TokenTree::Ident(i) => {
if i.to_string() != "Constructor" {
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
panic!("Invalid constructor syntax")
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
}
}
_ => panic!("Invalid constructor syntax"),
};
let ctor: proc_macro2::TokenStream = match ctor {
proc_macro::TokenTree::Group(g) => g.stream(),
_ => panic!("Invalid constructor syntax"),
}
.into();

let path_override = if let Some(next) = iter.peek() {
if match next {
proc_macro::TokenTree::Ident(i) => i.to_string() == "BevyReflectPath",
_ => false,
} {
_ = iter.next(); // Discard BevyReflectPath
Some(match iter.next() {
Some(proc_macro::TokenTree::Group(g)) => g.stream(),
_ => panic!("Invalid BevyReflectPath override!"),
})
} else {
None
}
} else {
None
};

let input = iter.collect();

let ast = parse_macro_input!(input as DeriveInput);

let bevy_reflect_path = if let Some(r#override) = path_override {
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
syn::parse(r#override).expect("Invalid BevyReflectPath override!")
} else {
BevyManifest::default().get_path("bevy_reflect")
};
let ident = &ast.ident;
let generics = &ast.generics;
let data = match &ast.data {
Data::Struct(r#struct) => r#struct,
// I don't believe enum reflection is implemented right now,
// and unions are likely not going to be reflected.
_ => unimplemented!(),
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
};
let fields = &data.fields;
let fields_and_args = fields
.iter()
.enumerate()
.map(|(i, f)| {
(
f,
f.attrs
.iter()
.find(|a| *a.path.get_ident().as_ref().unwrap() == REFLECT_ATTRIBUTE_NAME)
.map(|a| {
syn::custom_keyword!(ignore);
let mut attribute_args = PropAttributeArgs { ignore: None };
a.parse_args_with(|input: ParseStream| {
if input.parse::<Option<ignore>>()?.is_some() {
attribute_args.ignore = Some(true);
return Ok(());
}
Ok(())
})
.expect("Invalid 'property' attribute format.");

attribute_args
}),
i,
)
})
.collect::<Vec<(&Field, Option<PropAttributeArgs>, usize)>>();
let active_fields = fields_and_args
.iter()
.filter(|(_field, attrs, _i)| {
attrs.is_none()
|| match attrs.as_ref().unwrap().ignore {
Some(ignore) => !ignore,
None => true,
}
})
.map(|(f, _attr, i)| (*f, *i))
.collect::<Vec<(&Field, usize)>>();
let ignored_fields = fields_and_args
.iter()
.filter(|(_field, attrs, _i)| {
attrs
.as_ref()
.map(|attrs| attrs.ignore.unwrap_or(false))
.unwrap_or(false)
})
.map(|(f, _attr, i)| (*f, *i))
.collect::<Vec<(&Field, usize)>>();

let mut reflect_attrs = ReflectAttrs::default();
for attribute in ast.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
let meta_list = if let Meta::List(meta_list) = attribute {
meta_list
} else {
continue;
};

if let Some(ident) = meta_list.path.get_ident() {
if ident == REFLECT_ATTRIBUTE_NAME || ident == REFLECT_VALUE_ATTRIBUTE_NAME {
reflect_attrs = ReflectAttrs::from_nested_metas(&meta_list.nested);
}
}
}

let registration_data = &reflect_attrs.data;
let get_type_registration_impl =
impl_get_type_registration(ident, &bevy_reflect_path, registration_data, generics);

let impl_struct: proc_macro2::TokenStream = impl_struct(
ident,
generics,
&get_type_registration_impl,
&bevy_reflect_path,
&reflect_attrs,
&active_fields,
)
.into();

let impl_from_struct: proc_macro2::TokenStream = from_reflect::impl_struct(
ident,
generics,
&bevy_reflect_path,
&active_fields,
&ignored_fields,
Some(ctor),
)
.into();

quote!(
#impl_struct

#impl_from_struct
)
.into()
PROMETHIA-27 marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Default)]
struct ReflectAttrs {
reflect_hash: TraitImpl,
Expand Down Expand Up @@ -830,6 +979,7 @@ pub fn derive_from_reflect(input: TokenStream) -> TokenStream {
&bevy_reflect_path,
&active_fields,
&ignored_fields,
None,
),
DeriveType::TupleStruct => from_reflect::impl_tuple_struct(
type_name,
Expand Down
Loading