From a294f246535df777ad87e45dd78180c03d3c8311 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Fri, 29 Jan 2021 23:34:29 +0900 Subject: [PATCH 01/12] Add the Enum trait to reflect enum types --- crates/bevy_reflect/src/enum_trait.rs | 53 +++++++++++++++++++++++++ crates/bevy_reflect/src/lib.rs | 2 + crates/bevy_reflect/src/reflect.rs | 4 +- crates/bevy_reflect/src/serde/ser.rs | 3 ++ examples/reflection/reflection_types.rs | 3 ++ 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_reflect/src/enum_trait.rs diff --git a/crates/bevy_reflect/src/enum_trait.rs b/crates/bevy_reflect/src/enum_trait.rs new file mode 100644 index 0000000000000..8dadd82dd0f05 --- /dev/null +++ b/crates/bevy_reflect/src/enum_trait.rs @@ -0,0 +1,53 @@ +use crate::{Reflect, Struct, Tuple}; + +pub trait Enum: Reflect { + fn variant(&self) -> EnumVariant<'_>; + fn variant_mut(&mut self) -> EnumVariantMut<'_>; + fn variant_info(&self) -> VariantInfo<'_>; + fn iter_variants_info(&self) -> VariantInfoIter<'_>; + fn get_index_name(&self, index: usize) -> Option<&str>; + fn get_index_from_name(&self, name: &str) -> Option; +} +pub struct VariantInfo<'a> { + pub index: usize, + pub name: &'a str, +} +pub struct VariantInfoIter<'a> { + pub(crate) value: &'a dyn Enum, + pub(crate) index: usize, + pub(crate) len: usize, +} +impl<'a> Iterator for VariantInfoIter<'a> { + type Item = VariantInfo<'a>; + + fn next(&mut self) -> Option { + if self.index == self.len { + return None; + } + let item = VariantInfo { + index: self.index, + name: self.value.get_index_name(self.index).unwrap(), + }; + self.index += 1; + Some(item) + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.len - self.index; + (size, Some(size)) + } +} +impl<'a> ExactSizeIterator for VariantInfoIter<'a> {} + +pub enum EnumVariant<'a> { + Unit, + NewType(&'a dyn Reflect), + Tuple(&'a dyn Tuple), + Struct(&'a dyn Struct), +} +pub enum EnumVariantMut<'a> { + Unit, + NewType(&'a mut dyn Reflect), + Tuple(&'a mut dyn Tuple), + Struct(&'a mut dyn Struct), +} diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index cdfbf0a19bd8f..4dde6801fe676 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1,3 +1,4 @@ +mod enum_trait; mod list; mod map; mod path; @@ -41,6 +42,7 @@ pub mod prelude { }; } +pub use enum_trait::*; pub use impls::*; pub use list::*; pub use map::*; diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 28ccf3e428d74..0966e96ac30b9 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,4 +1,4 @@ -use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct}; +use crate::{serde::Serializable, Enum, List, Map, Struct, Tuple, TupleStruct}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; @@ -9,6 +9,7 @@ pub enum ReflectRef<'a> { Tuple(&'a dyn Tuple), List(&'a dyn List), Map(&'a dyn Map), + Enum(&'a dyn Enum), Value(&'a dyn Reflect), } @@ -18,6 +19,7 @@ pub enum ReflectMut<'a> { Tuple(&'a mut dyn Tuple), List(&'a mut dyn List), Map(&'a mut dyn Map), + Enum(&'a mut dyn Enum), Value(&'a mut dyn Reflect), } diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index a865bd13b438b..db5341546e5f6 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -77,6 +77,9 @@ impl<'a> Serialize for ReflectSerializer<'a> { value, } .serialize(serializer), + ReflectRef::Enum(_value) => { + todo!() + } } } } diff --git a/examples/reflection/reflection_types.rs b/examples/reflection/reflection_types.rs index 25de5fbb90048..611d82d4874ac 100644 --- a/examples/reflection/reflection_types.rs +++ b/examples/reflection/reflection_types.rs @@ -75,6 +75,9 @@ fn setup() { // operations on your type, allowing you to interact with fields via their indices. Tuple is automatically // implemented for tuples of arity 12 or less. ReflectRef::Tuple(_) => {} + // `Enum` is a trait automatically implemented for enums that derive Reflect. This trait allows you + // to interact list possible variants and interact with the currently active one + ReflectRef::Enum(_) => {} // `List` is a special trait that can be manually implemented (instead of deriving Reflect). This exposes "list" // operations on your type, such as indexing and insertion. List is automatically implemented for relevant core // types like Vec From fac285e68c298d772ff6eaa6da0d1d6ebd182490 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Fri, 29 Jan 2021 23:37:25 +0900 Subject: [PATCH 02/12] Add upcasting to the Reflect trait --- .../bevy_reflect_derive/src/lib.rs | 24 +++++++++++++++++++ crates/bevy_reflect/src/impls/smallvec.rs | 8 +++++++ crates/bevy_reflect/src/impls/std.rs | 16 +++++++++++++ crates/bevy_reflect/src/list.rs | 8 +++++++ crates/bevy_reflect/src/map.rs | 8 +++++++ crates/bevy_reflect/src/reflect.rs | 2 ++ crates/bevy_reflect/src/struct_trait.rs | 8 +++++++ crates/bevy_reflect/src/tuple.rs | 16 +++++++++++++ crates/bevy_reflect/src/tuple_struct.rs | 8 +++++++ 9 files changed, 98 insertions(+) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 73371602f1b6a..6640496fc2cbd 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -318,6 +318,14 @@ fn impl_struct( fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { #partial_eq_fn } + + fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect { + self + } } }) } @@ -437,6 +445,14 @@ fn impl_tuple_struct( fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { #partial_eq_fn } + + fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect { + self + } } }) } @@ -512,6 +528,14 @@ fn impl_value( fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> { #serialize_fn } + + fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect { + self + } } }) } diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 589bd4c0b1327..f883bf0a8e1b0 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -93,4 +93,12 @@ where fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index feae40b69a3fd..454f64c5dc718 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -109,6 +109,14 @@ impl Reflect for Vec { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } impl Map for HashMap { @@ -203,6 +211,14 @@ impl Reflect for HashMap Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } impl Reflect for Cow<'static, str> { diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 4506bb3ba0be8..5fa66700fd5ce 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -122,6 +122,14 @@ impl Reflect for DynamicList { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } pub struct ListIter<'a> { diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index eb5a89467f299..03d3f5ec44c7e 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -141,6 +141,14 @@ impl Reflect for DynamicMap { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } pub struct MapIter<'a> { diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 0966e96ac30b9..c2461b9eb277f 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -39,6 +39,8 @@ pub trait Reflect: Any + Send + Sync { fn reflect_partial_eq(&self, _value: &dyn Reflect) -> Option; /// Returns a serializable value, if serialization is supported. Otherwise `None` will be returned. fn serializable(&self) -> Option; + fn as_reflect(&self) -> &dyn Reflect; + fn as_reflect_mut(&mut self) -> &mut dyn Reflect; } impl Debug for dyn Reflect { diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 764d36a336cb8..7cbf040de308d 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -227,6 +227,14 @@ impl Reflect for DynamicStruct { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } #[inline] diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 901a8610e5e11..a8a0120cf89ca 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -165,6 +165,14 @@ impl Reflect for DynamicTuple { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } #[inline] @@ -291,6 +299,14 @@ macro_rules! impl_reflect_tuple { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 502d836f1c4e8..66f7d4553fd50 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -182,6 +182,14 @@ impl Reflect for DynamicTupleStruct { fn serializable(&self) -> Option { None } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } #[inline] From dabdd3976ae02ec83362314c798c42ce2f968556 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Sat, 30 Jan 2021 10:04:52 +0900 Subject: [PATCH 03/12] Derive Reflect on enums --- .../bevy_reflect_derive/src/lib.rs | 688 +++++++++++++++++- crates/bevy_reflect/src/enum_trait.rs | 82 ++- 2 files changed, 719 insertions(+), 51 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 6640496fc2cbd..e34a1f84e91f4 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -15,8 +15,8 @@ use syn::{ parse_macro_input, punctuated::Punctuated, token::{Comma, Paren, Where}, - Data, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, Member, Meta, NestedMeta, - Path, + Attribute, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, + Member, Meta, NestedMeta, Path, Token, Variant, }; #[derive(Default)] @@ -41,9 +41,15 @@ enum DeriveType { Struct, TupleStruct, UnitStruct, + Enum, Value, } +enum Items<'a> { + Fields(&'a Punctuated), + Variants(&'a Punctuated), +} + static REFLECT_ATTRIBUTE_NAME: &str = "reflect"; static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value"; @@ -51,29 +57,35 @@ static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value"; pub fn derive_reflect(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let unit_struct_punctuated = Punctuated::new(); - let (fields, mut derive_type) = match &ast.data { + let (items, mut derive_type) = match &ast.data { Data::Struct(DataStruct { fields: Fields::Named(fields), .. - }) => (&fields.named, DeriveType::Struct), + }) => (Items::Fields(&fields.named), DeriveType::Struct), Data::Struct(DataStruct { fields: Fields::Unnamed(fields), .. - }) => (&fields.unnamed, DeriveType::TupleStruct), + }) => (Items::Fields(&fields.unnamed), DeriveType::TupleStruct), Data::Struct(DataStruct { fields: Fields::Unit, .. - }) => (&unit_struct_punctuated, DeriveType::UnitStruct), - _ => (&unit_struct_punctuated, DeriveType::Value), + }) => ( + Items::Fields(&unit_struct_punctuated), + DeriveType::UnitStruct, + ), + Data::Enum(DataEnum { variants, .. }) => (Items::Variants(variants), DeriveType::Enum), + _ => (Items::Fields(&unit_struct_punctuated), DeriveType::Value), }; - - let fields_and_args = fields + let attrs: Vec<&Vec> = match items { + Items::Fields(fields) => fields.iter().map(|field| &field.attrs).collect(), + Items::Variants(variants) => variants.iter().map(|variant| &variant.attrs).collect(), + }; + let args = attrs .iter() .enumerate() - .map(|(i, f)| { + .map(|(i, attrs)| { ( - f, - f.attrs + attrs .iter() .find(|a| *a.path.get_ident().as_ref().unwrap() == REFLECT_ATTRIBUTE_NAME) .map(|a| { @@ -93,18 +105,18 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { i, ) }) - .collect::, usize)>>(); - let active_fields = fields_and_args + .collect::, usize)>>(); + let active_items = args .iter() - .filter(|(_field, attrs, _i)| { + .filter(|(attrs, _i)| { attrs.is_none() || match attrs.as_ref().unwrap().ignore { Some(ignore) => !ignore, None => true, } }) - .map(|(f, _attr, i)| (*f, *i)) - .collect::>(); + .map(|(_attr, i)| *i) + .collect::>(); let modules = get_modules(); let bevy_reflect_path = get_path(&modules.bevy_reflect); @@ -137,22 +149,46 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { ); match derive_type { - DeriveType::Struct | DeriveType::UnitStruct => impl_struct( - type_name, - &ast.generics, - get_type_registration_impl, - &bevy_reflect_path, - &reflect_attrs, - &active_fields, - ), - DeriveType::TupleStruct => impl_tuple_struct( - type_name, - &ast.generics, - get_type_registration_impl, - &bevy_reflect_path, - &reflect_attrs, - &active_fields, - ), + DeriveType::Struct | DeriveType::UnitStruct => { + let active_fields = match items { + Items::Fields(fields) => fields, + Items::Variants(_) => { + unreachable!() + } + } + .iter() + .zip(active_items.iter()) + .map(|(field, i)| (field, *i)) + .collect::>(); + impl_struct( + type_name, + &ast.generics, + get_type_registration_impl, + &bevy_reflect_path, + &reflect_attrs, + &active_fields, + ) + } + DeriveType::TupleStruct => { + let active_fields = match items { + Items::Fields(fields) => fields, + Items::Variants(_) => { + unreachable!() + } + } + .iter() + .zip(active_items.iter()) + .map(|(field, i)| (field, *i)) + .collect::>(); + impl_tuple_struct( + type_name, + &ast.generics, + get_type_registration_impl, + &bevy_reflect_path, + &reflect_attrs, + &active_fields, + ) + } DeriveType::Value => impl_value( type_name, &ast.generics, @@ -160,6 +196,24 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { &bevy_reflect_path, &reflect_attrs, ), + DeriveType::Enum => { + let active_variants = match items { + Items::Fields(_) => unreachable!(), + Items::Variants(variants) => variants, + } + .iter() + .zip(active_items.iter()) + .map(|(variant, i)| (variant, *i)) + .collect::>(); + impl_enum( + type_name, + &ast.generics, + get_type_registration_impl, + &bevy_reflect_path, + &reflect_attrs, + &active_variants, + ) + } } } @@ -494,12 +548,12 @@ fn impl_value( } #[inline] - fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { + fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { // FIXME let value = value.any(); if let Some(value) = value.downcast_ref::() { *self = value.clone(); } else { - panic!("Value is not {}.", std::any::type_name::()); + panic!("Attempted to apply non-enum type to enum type."); } } @@ -539,6 +593,570 @@ fn impl_value( } }) } + +fn impl_enum( + enum_name: &Ident, + generics: &Generics, + get_type_registration_impl: proc_macro2::TokenStream, + bevy_reflect_path: &Path, + reflect_attrs: &ReflectAttrs, + active_variants: &[(&Variant, usize)], +) -> TokenStream { + let mut variant_indices = Vec::new(); + let mut struct_wrappers = Vec::new(); + let mut tuple_wrappers = Vec::new(); + let mut variant_names = Vec::new(); + let mut variant_idents = Vec::new(); + let mut variant_and_fields_idents = Vec::new(); + let mut reflect_variants = Vec::new(); + let mut reflect_variants_mut = Vec::new(); + for (variant, variant_index) in active_variants.iter() { + let ident = &variant.ident; + let variant_name = format!("{}::{}", enum_name, variant.ident); + let variant_ident = { + match &variant.fields { + Fields::Named(_struct_fields) => { + quote!(#enum_name::#ident {..}) + } + Fields::Unnamed(tuple) => { + let tuple_fields = &tuple.unnamed; + if tuple_fields.len() == 1 { + quote!(#enum_name::#ident (_)) + } else { + quote!(#enum_name::#ident (..)) + } + } + Fields::Unit => { + quote!(#enum_name::#ident) + } + } + }; + let variant_and_fields_ident = { + match &variant.fields { + Fields::Named(struct_fields) => { + let field_names = struct_fields + .named + .iter() + .map(|field| field.ident.as_ref().unwrap()) + .collect::>(); + quote!(#enum_name::#ident {#(#field_names,)*}) + } + Fields::Unnamed(tuple_fields) => { + let field_names = (0..tuple_fields.unnamed.len()) + .map(|i| Ident::new(format!("t{}", i).as_str(), Span::call_site())) + .collect::>(); + if tuple_fields.unnamed.len() == 1 { + quote!(#enum_name::#ident (new_type)) + } else { + quote!(#enum_name::#ident (#(#field_names,)*)) + } + } + Fields::Unit => { + quote!(#enum_name::#ident) + } + } + }; + let wrapper_ident = if let Fields::Named(_) | Fields::Unnamed(_) = &variant.fields { + Ident::new( + format!("{}{}Wrapper", enum_name, variant.ident).as_str(), + Span::call_site(), + ) + } else { + Ident::new("unused", Span::call_site()) + }; + let wrapper_name = match &variant.fields { + Fields::Named(struct_fields) => { + quote!(#struct_fields).to_string() + } + Fields::Unnamed(tuple_fields) => { + quote!(#tuple_fields).to_string() + } + Fields::Unit => "unused".to_string(), + }; + let reflect_variant = { + match &variant.fields { + Fields::Named(_struct_fields) => { + quote!({ + let wrapper_ref = unsafe { std::mem::transmute::< &Self, &#wrapper_ident >(self) }; + #bevy_reflect_path::EnumVariant::Struct(wrapper_ref as &dyn Struct) + }) + } + Fields::Unnamed(tuple_fields) => { + if tuple_fields.unnamed.len() == 1 { + quote!(#bevy_reflect_path::EnumVariant::NewType(new_type as &dyn #bevy_reflect_path::Reflect)) + } else { + quote!({ + let wrapper_ref = unsafe { std::mem::transmute::< &Self, &#wrapper_ident >(self) }; + #bevy_reflect_path::EnumVariant::Tuple(wrapper_ref as &dyn Tuple) + }) + } + } + Fields::Unit => { + quote!(#bevy_reflect_path::EnumVariant::Unit) + } + } + }; + let reflect_variant_mut = { + match &variant.fields { + Fields::Named(_struct_fields) => { + quote!({ + let wrapper_ref = unsafe { std::mem::transmute::< &mut Self, &mut #wrapper_ident >(self) }; + #bevy_reflect_path::EnumVariantMut::Struct(wrapper_ref as &mut dyn Struct) + }) + } + Fields::Unnamed(tuple) => { + let tuple_fields = &tuple.unnamed; + if tuple_fields.len() == 1 { + quote!(#bevy_reflect_path::EnumVariantMut::NewType(new_type as &mut dyn #bevy_reflect_path::Reflect)) + } else { + quote!({ + let wrapper_ref = unsafe { std::mem::transmute::< &mut Self, &mut #wrapper_ident >(self) }; + #bevy_reflect_path::EnumVariantMut::Tuple(wrapper_ref as &mut dyn Tuple) + }) + } + } + Fields::Unit => { + quote!(#bevy_reflect_path::EnumVariantMut::Unit) + } + } + }; + match &variant.fields { + Fields::Named(struct_fields) => { + struct_wrappers.push(( + wrapper_ident, + wrapper_name, + variant_index, + variant_name.clone(), + variant_ident.clone(), + variant_and_fields_ident.clone(), + struct_fields.clone(), + )); + } + Fields::Unnamed(tuple_fields) => { + if tuple_fields.unnamed.len() > 1 { + tuple_wrappers.push(( + wrapper_ident, + wrapper_name, + variant_index, + variant_name.clone(), + variant_ident.clone(), + variant_and_fields_ident.clone(), + tuple_fields.clone(), + )); + } + } + Fields::Unit => {} + } + variant_indices.push(variant_index); + variant_names.push(variant_name); + variant_idents.push(variant_ident); + variant_and_fields_idents.push(variant_and_fields_ident); + reflect_variants.push(reflect_variant); + reflect_variants_mut.push(reflect_variant_mut); + } + let hash_fn = reflect_attrs.get_hash_impl(&bevy_reflect_path); + let serialize_fn = reflect_attrs.get_serialize_impl(&bevy_reflect_path); + let partial_eq_fn = match reflect_attrs.reflect_partial_eq { + TraitImpl::NotImplemented => quote! { + use #bevy_reflect_path::Enum; + #bevy_reflect_path::enum_partial_eq(self, value) + }, + TraitImpl::Implemented | TraitImpl::Custom(_) => reflect_attrs.get_partial_eq_impl(), + }; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let mut token_stream = TokenStream::from(quote! { + #get_type_registration_impl + + impl #impl_generics #bevy_reflect_path::Enum for #enum_name#ty_generics #where_clause { + fn variant(&self) -> #bevy_reflect_path::EnumVariant<'_> { + match self { + #(#variant_and_fields_idents => #reflect_variants,)* + } + } + + fn variant_mut(&mut self) -> #bevy_reflect_path::EnumVariantMut<'_> { + match self { + #(#variant_and_fields_idents => #reflect_variants_mut,)* + } + } + + fn variant_info(&self) -> #bevy_reflect_path::VariantInfo<'_> { + let index = match self { + #(#variant_idents => #variant_indices,)* + }; + #bevy_reflect_path::VariantInfo { + index, + name: self.get_index_name(index).unwrap(), + } + } + + fn get_index_name(&self, index: usize) -> Option<&'_ str> { + match index { + #(#variant_indices => Some(#variant_names),)* + _ => None, + } + } + + fn get_index_from_name(&self, name: &str) -> Option { + match name { + #(#variant_names => Some(#variant_indices),)* + _ => None, + } + } + + fn iter_variants_info(&self) -> #bevy_reflect_path::VariantInfoIter<'_> { + #bevy_reflect_path::VariantInfoIter::new(self) + } + } + + impl #impl_generics #bevy_reflect_path::Reflect for #enum_name#ty_generics #where_clause { + #[inline] + fn type_name(&self) -> &str { + std::any::type_name::() + } + + #[inline] + fn any(&self) -> &dyn std::any::Any { + self + } + #[inline] + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + #[inline] + fn clone_value(&self) -> Box { + use #bevy_reflect_path::Enum; + Box::new(self.clone()) // FIXME: should it be clone_dynamic? + } + #[inline] + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + #[inline] + fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { // FIXME + use #bevy_reflect_path::Enum; + let value = value.any(); + if let Some(value) = value.downcast_ref::() { + *self = value.clone(); + } else { + panic!("Attempted to apply non-enum type to enum type."); + } + } + + fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef { + #bevy_reflect_path::ReflectRef::Enum(self) + } + + fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut { + #bevy_reflect_path::ReflectMut::Enum(self) + } + + fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> { + #serialize_fn + } + + fn reflect_hash(&self) -> Option { + #hash_fn + } + + fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { + #partial_eq_fn + } + + fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect { + self + } + } + }); + for ( + wrapper_ident, + wrapper_name, + variant_index, + variant_name, + _variant_ident, + variant_and_fields_ident, + fields, + ) in struct_wrappers + { + let mut field_names = Vec::new(); + let mut field_idents = Vec::new(); + let mut field_indices = Vec::new(); + for (i, field) in fields.named.iter().enumerate() { + field_names.push(field.ident.as_ref().unwrap().to_string()); + field_idents.push(field.ident.clone()); + field_indices.push(i); + } + let fields_len = field_indices.len(); + let mut match_fields = quote!(); + for (i, variant_ident) in variant_idents.iter().enumerate() { + if i == *variant_index { + match_fields.extend(quote!( + #variant_and_fields_ident => (#(#field_idents,)*), + )); + } else { + match_fields.extend(quote!( + #variant_ident => unreachable!(), + )); + } + } + let match_fields_mut = quote!(let (#(#field_idents,)*) = match &mut self.0 { + #match_fields + };); + let match_fields = quote!(let (#(#field_idents,)*) = match &self.0 { + #match_fields + };); + token_stream.extend(TokenStream::from(quote! { + #[repr(transparent)] + pub struct #wrapper_ident(TestEnum); + impl #bevy_reflect_path::Reflect for #wrapper_ident { + fn type_name(&self) -> &str { + #wrapper_name + } + + fn any(&self) -> &dyn std::any::Any { + self.0.any() + } + + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self.0.any_mut() + } + + fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { + self.0.apply(value); + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + self.0.set(value) + } + + fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef { + #bevy_reflect_path::ReflectRef::Struct(self) + } + + fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut { + #bevy_reflect_path::ReflectMut::Struct(self) + } + + fn clone_value(&self) -> Box { + self.0.clone_value() + } + + fn reflect_hash(&self) -> Option { + self.0.reflect_hash() + } + + fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { + self.0.reflect_partial_eq(value) + } + + fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> { + self.0.serializable() + } + + fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect { + self + } + } + impl #bevy_reflect_path::Struct for #wrapper_ident { + fn field(&self, name: &str) -> Option<&dyn #bevy_reflect_path::Reflect> { + #match_fields + match name { + #(#field_names => Some(#field_idents),)* + _ => None, + } + } + + fn field_mut(&mut self, name: &str) -> Option<&mut dyn #bevy_reflect_path::Reflect> { + #match_fields_mut + match name { + #(#field_names => Some(#field_idents),)* + _ => None, + } + } + + fn field_at(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { + #match_fields + match index { + #(#field_indices => Some(#field_idents),)* + _ => None, + } + } + + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> { + #match_fields_mut + match index { + #(#field_indices => Some(#field_idents),)* + _ => None, + } + } + fn name_at(&self, index: usize) -> Option<&str> { + match index { + #(#field_indices => Some(#field_names),)* + _ => None, + } + } + + fn field_len(&self) -> usize { + #fields_len + } + + fn iter_fields(&self) -> bevy::reflect::FieldIter { + FieldIter::new(self) + } + + fn clone_dynamic(&self) -> bevy::reflect::DynamicStruct { + #match_fields + let mut dynamic = #bevy_reflect_path::DynamicStruct::default(); + dynamic.set_name(self.type_name().to_string()); + #(dynamic.insert_boxed(#field_names, #field_idents.clone_value());)* + dynamic + } + } + })); + } + for ( + wrapper_ident, + wrapper_name, + variant_index, + variant_name, + _variant_ident, + variant_and_fields_ident, + fields, + ) in tuple_wrappers + { + let mut field_names = Vec::new(); + let mut field_idents = Vec::new(); + let mut field_indices = Vec::new(); + for (index, _field) in fields.unnamed.iter().enumerate() { + let field_name = format!("t{}", index); // FIXME: done in 2 places + let field_ident = Ident::new(field_name.as_str(), Span::call_site()); + field_names.push(field_name); + field_idents.push(field_ident); + field_indices.push(index); + } + let fields_len = field_indices.len(); + let mut match_fields = quote!(); + for (i, variant_ident) in variant_idents.iter().enumerate() { + if i == *variant_index { + match_fields.extend(quote!( + #variant_and_fields_ident => (#(#field_idents,)*), + )); + } else { + match_fields.extend(quote!( + #variant_ident => unreachable!(), + )); + } + } + let match_fields_mut = quote!(let (#(#field_idents,)*) = match &mut self.0 { + #match_fields + };); + let match_fields = quote!(let (#(#field_idents,)*) = match &self.0 { + #match_fields + };); + token_stream.extend(TokenStream::from(quote! { + #[repr(transparent)] + pub struct #wrapper_ident(TestEnum); + impl #bevy_reflect_path::Reflect for #wrapper_ident { + fn type_name(&self) -> &str { + #wrapper_name + } + + fn any(&self) -> &dyn std::any::Any { + self.0.any() + } + + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self.0.any_mut() + } + + fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { + self.0.apply(value); + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + self.0.set(value) + } + + fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef { + #bevy_reflect_path::ReflectRef::Tuple(self) + } + + fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut { + #bevy_reflect_path::ReflectMut::Tuple(self) + } + + fn clone_value(&self) -> Box { + self.0.clone_value() + } + + fn reflect_hash(&self) -> Option { + self.0.reflect_hash() + } + + fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { + self.0.reflect_partial_eq(value) + } + + fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> { + self.0.serializable() + } + + fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect { + self + } + } + impl #bevy_reflect_path::Tuple for #wrapper_ident { + fn field(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { + #match_fields + match index { + #(#field_indices => Some(#field_idents),)* + _ => None, + } + } + + fn field_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> { + #match_fields_mut + match index { + #(#field_indices => Some(#field_idents),)* + _ => None, + } + } + + fn field_len(&self) -> usize { + #fields_len + } + + fn iter_fields(&self) -> bevy::reflect::TupleFieldIter { + TupleFieldIter::new(self) + } + + fn clone_dynamic(&self) -> bevy::reflect::DynamicTuple { + #match_fields + let mut dynamic = #bevy_reflect_path::DynamicTuple::default(); + #(dynamic.insert_boxed(#field_idents.clone_value());)* + dynamic + } + } + })); + } + token_stream +} struct ReflectDef { type_name: Ident, generics: Generics, diff --git a/crates/bevy_reflect/src/enum_trait.rs b/crates/bevy_reflect/src/enum_trait.rs index 8dadd82dd0f05..16eb90c7f49fc 100644 --- a/crates/bevy_reflect/src/enum_trait.rs +++ b/crates/bevy_reflect/src/enum_trait.rs @@ -1,4 +1,4 @@ -use crate::{Reflect, Struct, Tuple}; +use crate::{Reflect, ReflectRef, Struct, Tuple}; pub trait Enum: Reflect { fn variant(&self) -> EnumVariant<'_>; @@ -8,6 +8,7 @@ pub trait Enum: Reflect { fn get_index_name(&self, index: usize) -> Option<&str>; fn get_index_from_name(&self, name: &str) -> Option; } +#[derive(PartialEq, Eq)] pub struct VariantInfo<'a> { pub index: usize, pub name: &'a str, @@ -15,29 +16,27 @@ pub struct VariantInfo<'a> { pub struct VariantInfoIter<'a> { pub(crate) value: &'a dyn Enum, pub(crate) index: usize, - pub(crate) len: usize, +} +impl<'a> VariantInfoIter<'a> { + pub fn new(value: &'a dyn Enum) -> Self { + Self { value, index: 0 } + } } impl<'a> Iterator for VariantInfoIter<'a> { type Item = VariantInfo<'a>; fn next(&mut self) -> Option { - if self.index == self.len { - return None; - } - let item = VariantInfo { - index: self.index, - name: self.value.get_index_name(self.index).unwrap(), - }; + let value = self + .value + .get_index_name(self.index) + .map(|name| VariantInfo { + index: self.index, + name, + }); self.index += 1; - Some(item) - } - - fn size_hint(&self) -> (usize, Option) { - let size = self.len - self.index; - (size, Some(size)) + value } } -impl<'a> ExactSizeIterator for VariantInfoIter<'a> {} pub enum EnumVariant<'a> { Unit, @@ -51,3 +50,54 @@ pub enum EnumVariantMut<'a> { Tuple(&'a mut dyn Tuple), Struct(&'a mut dyn Struct), } + +#[inline] +pub fn enum_partial_eq(enum_a: &E, reflect_b: &dyn Reflect) -> Option { + let enum_b = if let ReflectRef::Enum(e) = reflect_b.reflect_ref() { + e + } else { + return Some(false); + }; + + if enum_a.variant_info() != enum_b.variant_info() { + return Some(false); + } + + let variant_b = enum_b.variant(); + match enum_a.variant() { + EnumVariant::Unit => { + if let EnumVariant::Unit = variant_b { + } else { + return Some(false); + } + } + EnumVariant::NewType(t_a) => { + if let EnumVariant::NewType(t_b) = variant_b { + if let Some(false) | None = t_b.reflect_partial_eq(t_a) { + return Some(false); + } + } else { + return Some(false); + } + } + EnumVariant::Tuple(t_a) => { + if let EnumVariant::Tuple(t_b) = variant_b { + if let Some(false) | None = t_b.reflect_partial_eq(t_a.as_reflect()) { + return Some(false); + } + } else { + return Some(false); + } + } + EnumVariant::Struct(s_a) => { + if let EnumVariant::Struct(s_b) = variant_b { + if let Some(false) | None = s_b.reflect_partial_eq(s_a.as_reflect()) { + return Some(false); + } + } else { + return Some(false); + } + } + } + Some(true) +} From 9261317ea5eb1137e49624e2c45615e2af1eaa34 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Sat, 30 Jan 2021 10:06:55 +0900 Subject: [PATCH 04/12] Implement Reflect and Enum for Option --- .../bevy_reflect_derive/src/lib.rs | 12 +- crates/bevy_reflect/src/impls/std.rs | 133 +++++++++++++++++- 2 files changed, 134 insertions(+), 11 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index e34a1f84e91f4..ef23f22d499f5 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -665,12 +665,8 @@ fn impl_enum( Ident::new("unused", Span::call_site()) }; let wrapper_name = match &variant.fields { - Fields::Named(struct_fields) => { - quote!(#struct_fields).to_string() - } - Fields::Unnamed(tuple_fields) => { - quote!(#tuple_fields).to_string() - } + Fields::Named(struct_fields) => quote!(#struct_fields).to_string(), + Fields::Unnamed(tuple_fields) => quote!(#tuple_fields).to_string(), Fields::Unit => "unused".to_string(), }; let reflect_variant = { @@ -880,7 +876,7 @@ fn impl_enum( wrapper_ident, wrapper_name, variant_index, - variant_name, + _variant_name, _variant_ident, variant_and_fields_ident, fields, @@ -1030,7 +1026,7 @@ fn impl_enum( wrapper_ident, wrapper_name, variant_index, - variant_name, + _variant_name, _variant_ident, variant_and_fields_ident, fields, diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 454f64c5dc718..a97df087b8593 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,6 +1,7 @@ use crate::{ - map_partial_eq, serde::Serializable, DynamicMap, List, ListIter, Map, MapIter, Reflect, - ReflectDeserialize, ReflectMut, ReflectRef, + map_partial_eq, serde::Serializable, DynamicMap, Enum, EnumVariant, EnumVariantMut, + GetTypeRegistration, List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, + ReflectRef, TypeRegistration, VariantInfo, VariantInfoIter, }; use bevy_reflect_derive::impl_reflect_value; @@ -29,7 +30,6 @@ impl_reflect_value!(isize(Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(f32(Serialize, Deserialize)); impl_reflect_value!(f64(Serialize, Deserialize)); impl_reflect_value!(String(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Option Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize)); impl_reflect_value!(HashSet Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize)); impl_reflect_value!(Range Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize)); @@ -279,4 +279,131 @@ impl Reflect for Cow<'static, str> { fn serializable(&self) -> Option { Some(Serializable::Borrowed(self)) } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } +} + +impl GetTypeRegistration for Option { + fn get_type_registration() -> TypeRegistration { + TypeRegistration::of::>() + } +} +impl Enum for Option { + fn variant(&self) -> EnumVariant<'_> { + match self { + Option::Some(new_type) => EnumVariant::NewType(new_type as &dyn Reflect), + Option::None => EnumVariant::Unit, + } + } + + fn variant_mut(&mut self) -> EnumVariantMut<'_> { + match self { + Option::Some(new_type) => EnumVariantMut::NewType(new_type as &mut dyn Reflect), + Option::None => EnumVariantMut::Unit, + } + } + + fn variant_info(&self) -> VariantInfo<'_> { + let index = match self { + Option::Some(_) => 0usize, + Option::None => 1usize, + }; + VariantInfo { + index, + name: self.get_index_name(index).unwrap(), + } + } + + fn get_index_name(&self, index: usize) -> Option<&'_ str> { + match index { + 0usize => Some("Option::Some"), + 1usize => Some("Option::None"), + _ => None, + } + } + + fn get_index_from_name(&self, name: &str) -> Option { + match name { + "Option::Some" => Some(0usize), + "Option::None" => Some(1usize), + _ => None, + } + } + + fn iter_variants_info(&self) -> VariantInfoIter<'_> { + VariantInfoIter::new(self) + } +} +impl Reflect for Option { + #[inline] + fn type_name(&self) -> &str { + std::any::type_name::() + } + + #[inline] + fn any(&self) -> &dyn std::any::Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + + #[inline] + fn clone_value(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + #[inline] + fn apply(&mut self, value: &dyn Reflect) { + let value = value.any(); + if let Some(value) = value.downcast_ref::() { + *self = value.clone(); + } else { + { + panic!("Enum is not {}.", &std::any::type_name::()); + }; + } + } + + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Enum(self) + } + + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Enum(self) + } + + fn serializable(&self) -> Option { + None + } + + fn reflect_hash(&self) -> Option { + None + } + + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + crate::enum_partial_eq(self, value) + } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } } From 91fdac0662317504e94cf4cafb73b733b399b558 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Mon, 1 Feb 2021 13:28:40 +0900 Subject: [PATCH 05/12] Fix field indices --- .../bevy_reflect_derive/src/lib.rs | 175 +++++++++++------- 1 file changed, 108 insertions(+), 67 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index ef23f22d499f5..946c2d713e295 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -15,8 +15,8 @@ use syn::{ parse_macro_input, punctuated::Punctuated, token::{Comma, Paren, Where}, - Attribute, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, - Member, Meta, NestedMeta, Path, Token, Variant, + Data, DataEnum, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, Member, Meta, + NestedMeta, Path, Token, Variant, }; #[derive(Default)] @@ -45,9 +45,9 @@ enum DeriveType { Value, } -enum Items<'a> { - Fields(&'a Punctuated), - Variants(&'a Punctuated), +enum Item<'a> { + Field(&'a Field), + Variant(&'a Variant), } static REFLECT_ATTRIBUTE_NAME: &str = "reflect"; @@ -56,67 +56,96 @@ static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value"; #[proc_macro_derive(Reflect, attributes(reflect, reflect_value, module))] pub fn derive_reflect(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); - let unit_struct_punctuated = Punctuated::new(); - let (items, mut derive_type) = match &ast.data { + let unit_struct_punctuated = Punctuated::::new(); + let (items, mut derive_type): (Vec, DeriveType) = match &ast.data { Data::Struct(DataStruct { fields: Fields::Named(fields), .. - }) => (Items::Fields(&fields.named), DeriveType::Struct), + }) => ( + fields + .named + .iter() + .map(|field| Item::Field(field)) + .collect(), + DeriveType::Struct, + ), Data::Struct(DataStruct { fields: Fields::Unnamed(fields), .. - }) => (Items::Fields(&fields.unnamed), DeriveType::TupleStruct), + }) => ( + fields + .unnamed + .iter() + .map(|field| Item::Field(field)) + .collect(), + DeriveType::TupleStruct, + ), Data::Struct(DataStruct { fields: Fields::Unit, .. }) => ( - Items::Fields(&unit_struct_punctuated), + unit_struct_punctuated + .iter() + .map(|field| Item::Field(field)) + .collect(), DeriveType::UnitStruct, ), - Data::Enum(DataEnum { variants, .. }) => (Items::Variants(variants), DeriveType::Enum), - _ => (Items::Fields(&unit_struct_punctuated), DeriveType::Value), - }; - let attrs: Vec<&Vec> = match items { - Items::Fields(fields) => fields.iter().map(|field| &field.attrs).collect(), - Items::Variants(variants) => variants.iter().map(|variant| &variant.attrs).collect(), + Data::Enum(DataEnum { variants, .. }) => ( + variants + .iter() + .map(|variant| Item::Variant(variant)) + .collect(), + DeriveType::Enum, + ), + _ => ( + unit_struct_punctuated + .iter() + .map(|field| Item::Field(field)) + .collect(), + DeriveType::Value, + ), }; - let args = attrs + let items_and_args = items .iter() .enumerate() - .map(|(i, attrs)| { + .map(|(i, item)| { ( - 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::>()?.is_some() { - attribute_args.ignore = Some(true); - return Ok(()); - } - Ok(()) - }) - .expect("Invalid 'property' attribute format."); + item, + match *item { + Item::Field(field) => &field.attrs, + Item::Variant(variant) => &variant.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::>()?.is_some() { + attribute_args.ignore = Some(true); + return Ok(()); + } + Ok(()) + }) + .expect("Invalid 'property' attribute format."); - attribute_args - }), + attribute_args + }), i, ) }) - .collect::, usize)>>(); - let active_items = args + .collect::, usize)>>(); + let active_items = items_and_args .iter() - .filter(|(attrs, _i)| { + .filter(|(_item, attrs, _i)| { attrs.is_none() || match attrs.as_ref().unwrap().ignore { Some(ignore) => !ignore, None => true, } }) - .map(|(_attr, i)| *i) - .collect::>(); + .map(|(item, _attr, i)| (*item, *i)) + .collect::>(); let modules = get_modules(); let bevy_reflect_path = get_path(&modules.bevy_reflect); @@ -150,16 +179,20 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { match derive_type { DeriveType::Struct | DeriveType::UnitStruct => { - let active_fields = match items { - Items::Fields(fields) => fields, - Items::Variants(_) => { - unreachable!() - } - } - .iter() - .zip(active_items.iter()) - .map(|(field, i)| (field, *i)) - .collect::>(); + let active_fields = active_items + .iter() + .map(|(item, i)| { + ( + match *item { + Item::Field(field) => *field, + Item::Variant(_) => { + unreachable!() + } + }, + *i, + ) + }) + .collect::>(); impl_struct( type_name, &ast.generics, @@ -170,16 +203,20 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { ) } DeriveType::TupleStruct => { - let active_fields = match items { - Items::Fields(fields) => fields, - Items::Variants(_) => { - unreachable!() - } - } - .iter() - .zip(active_items.iter()) - .map(|(field, i)| (field, *i)) - .collect::>(); + let active_fields = active_items + .iter() + .map(|(item, i)| { + ( + match *item { + Item::Field(field) => *field, + Item::Variant(_) => { + unreachable!() + } + }, + *i, + ) + }) + .collect::>(); impl_tuple_struct( type_name, &ast.generics, @@ -197,14 +234,18 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { &reflect_attrs, ), DeriveType::Enum => { - let active_variants = match items { - Items::Fields(_) => unreachable!(), - Items::Variants(variants) => variants, - } - .iter() - .zip(active_items.iter()) - .map(|(variant, i)| (variant, *i)) - .collect::>(); + let active_variants = active_items + .iter() + .map(|(item, i)| { + ( + match *item { + Item::Field(_) => unreachable!(), + Item::Variant(variant) => *variant, + }, + *i, + ) + }) + .collect::>(); impl_enum( type_name, &ast.generics, From 3704e0e8e058f67adb42b0f5400e9fefac5f76af Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Mon, 1 Feb 2021 14:37:49 +0900 Subject: [PATCH 06/12] refactoring --- .../bevy_reflect_derive/src/lib.rs | 109 ++++++++---------- 1 file changed, 51 insertions(+), 58 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 946c2d713e295..a9f3dab37e7e9 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -425,6 +425,14 @@ fn impl_struct( }) } +fn tuple_field_name(i: usize) -> String { + format!("t{}", i) +} + +fn tuple_field_ident(i: usize) -> Ident { + Ident::new(tuple_field_name(i).as_str(), Span::call_site()) +} + fn impl_tuple_struct( struct_name: &Ident, generics: &Generics, @@ -589,12 +597,12 @@ fn impl_value( } #[inline] - fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { // FIXME + fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { let value = value.any(); if let Some(value) = value.downcast_ref::() { *self = value.clone(); } else { - panic!("Attempted to apply non-enum type to enum type."); + panic!("Value is not {}.", std::any::type_name::()); } } @@ -648,52 +656,56 @@ fn impl_enum( let mut tuple_wrappers = Vec::new(); let mut variant_names = Vec::new(); let mut variant_idents = Vec::new(); - let mut variant_and_fields_idents = Vec::new(); let mut reflect_variants = Vec::new(); let mut reflect_variants_mut = Vec::new(); + let mut variant_with_fields_idents = Vec::new(); + let mut variant_without_fields_idents = Vec::new(); for (variant, variant_index) in active_variants.iter() { - let ident = &variant.ident; - let variant_name = format!("{}::{}", enum_name, variant.ident); let variant_ident = { + let ident = &variant.ident; + quote!(#enum_name::#ident) + }; + let variant_name = variant_ident.to_string(); + let variant_without_fields_ident = { match &variant.fields { Fields::Named(_struct_fields) => { - quote!(#enum_name::#ident {..}) + quote!(#variant_ident {..}) } Fields::Unnamed(tuple) => { let tuple_fields = &tuple.unnamed; if tuple_fields.len() == 1 { - quote!(#enum_name::#ident (_)) + quote!(#variant_ident (_)) } else { - quote!(#enum_name::#ident (..)) + quote!(#variant_ident (..)) } } Fields::Unit => { - quote!(#enum_name::#ident) + quote!(#variant_ident) } } }; - let variant_and_fields_ident = { + let variant_with_fields_ident = { match &variant.fields { Fields::Named(struct_fields) => { - let field_names = struct_fields + let field_idents = struct_fields .named .iter() .map(|field| field.ident.as_ref().unwrap()) .collect::>(); - quote!(#enum_name::#ident {#(#field_names,)*}) + quote!(#variant_ident {#(#field_idents,)*}) } Fields::Unnamed(tuple_fields) => { - let field_names = (0..tuple_fields.unnamed.len()) - .map(|i| Ident::new(format!("t{}", i).as_str(), Span::call_site())) + let field_idents = (0..tuple_fields.unnamed.len()) + .map(|i| tuple_field_ident(i)) .collect::>(); if tuple_fields.unnamed.len() == 1 { - quote!(#enum_name::#ident (new_type)) + quote!(#variant_ident (new_type)) } else { - quote!(#enum_name::#ident (#(#field_names,)*)) + quote!(#variant_ident (#(#field_idents,)*)) } } Fields::Unit => { - quote!(#enum_name::#ident) + quote!(#variant_ident) } } }; @@ -763,9 +775,7 @@ fn impl_enum( wrapper_ident, wrapper_name, variant_index, - variant_name.clone(), - variant_ident.clone(), - variant_and_fields_ident.clone(), + variant_with_fields_ident.clone(), struct_fields.clone(), )); } @@ -775,9 +785,7 @@ fn impl_enum( wrapper_ident, wrapper_name, variant_index, - variant_name.clone(), - variant_ident.clone(), - variant_and_fields_ident.clone(), + variant_with_fields_ident.clone(), tuple_fields.clone(), )); } @@ -787,9 +795,10 @@ fn impl_enum( variant_indices.push(variant_index); variant_names.push(variant_name); variant_idents.push(variant_ident); - variant_and_fields_idents.push(variant_and_fields_ident); reflect_variants.push(reflect_variant); reflect_variants_mut.push(reflect_variant_mut); + variant_with_fields_idents.push(variant_with_fields_ident); + variant_without_fields_idents.push(variant_without_fields_ident); } let hash_fn = reflect_attrs.get_hash_impl(&bevy_reflect_path); let serialize_fn = reflect_attrs.get_serialize_impl(&bevy_reflect_path); @@ -809,19 +818,19 @@ fn impl_enum( impl #impl_generics #bevy_reflect_path::Enum for #enum_name#ty_generics #where_clause { fn variant(&self) -> #bevy_reflect_path::EnumVariant<'_> { match self { - #(#variant_and_fields_idents => #reflect_variants,)* + #(#variant_with_fields_idents => #reflect_variants,)* } } fn variant_mut(&mut self) -> #bevy_reflect_path::EnumVariantMut<'_> { match self { - #(#variant_and_fields_idents => #reflect_variants_mut,)* + #(#variant_with_fields_idents => #reflect_variants_mut,)* } } fn variant_info(&self) -> #bevy_reflect_path::VariantInfo<'_> { let index = match self { - #(#variant_idents => #variant_indices,)* + #(#variant_without_fields_idents => #variant_indices,)* }; #bevy_reflect_path::VariantInfo { index, @@ -865,7 +874,7 @@ fn impl_enum( #[inline] fn clone_value(&self) -> Box { use #bevy_reflect_path::Enum; - Box::new(self.clone()) // FIXME: should it be clone_dynamic? + Box::new(self.clone()) // FIXME: should be clone_dynamic, so that Clone is not a required bound } #[inline] fn set(&mut self, value: Box) -> Result<(), Box> { @@ -874,11 +883,11 @@ fn impl_enum( } #[inline] - fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { // FIXME + fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) { use #bevy_reflect_path::Enum; let value = value.any(); if let Some(value) = value.downcast_ref::() { - *self = value.clone(); + *self = value.clone_value(); } else { panic!("Attempted to apply non-enum type to enum type."); } @@ -913,15 +922,8 @@ fn impl_enum( } } }); - for ( - wrapper_ident, - wrapper_name, - variant_index, - _variant_name, - _variant_ident, - variant_and_fields_ident, - fields, - ) in struct_wrappers + for (wrapper_ident, wrapper_name, variant_index, variant_with_fields_ident, fields) in + struct_wrappers { let mut field_names = Vec::new(); let mut field_idents = Vec::new(); @@ -933,14 +935,14 @@ fn impl_enum( } let fields_len = field_indices.len(); let mut match_fields = quote!(); - for (i, variant_ident) in variant_idents.iter().enumerate() { + for (i, _variant_ident) in variant_idents.iter().enumerate() { if i == *variant_index { match_fields.extend(quote!( - #variant_and_fields_ident => (#(#field_idents,)*), + #variant_with_fields_ident => (#(#field_idents,)*), )); } else { match_fields.extend(quote!( - #variant_ident => unreachable!(), + #variant_with_fields_ident => unreachable!(), )); } } @@ -1063,36 +1065,27 @@ fn impl_enum( } })); } - for ( - wrapper_ident, - wrapper_name, - variant_index, - _variant_name, - _variant_ident, - variant_and_fields_ident, - fields, - ) in tuple_wrappers + for (wrapper_ident, wrapper_name, variant_index, variant_with_fields_ident, fields) in + tuple_wrappers { let mut field_names = Vec::new(); let mut field_idents = Vec::new(); let mut field_indices = Vec::new(); for (index, _field) in fields.unnamed.iter().enumerate() { - let field_name = format!("t{}", index); // FIXME: done in 2 places - let field_ident = Ident::new(field_name.as_str(), Span::call_site()); - field_names.push(field_name); - field_idents.push(field_ident); + field_names.push(tuple_field_name(index)); + field_idents.push(tuple_field_ident(index)); field_indices.push(index); } let fields_len = field_indices.len(); let mut match_fields = quote!(); - for (i, variant_ident) in variant_idents.iter().enumerate() { + for (i, _variant_ident) in variant_idents.iter().enumerate() { if i == *variant_index { match_fields.extend(quote!( - #variant_and_fields_ident => (#(#field_idents,)*), + #variant_with_fields_ident => (#(#field_idents,)*), )); } else { match_fields.extend(quote!( - #variant_ident => unreachable!(), + #variant_with_fields_ident => unreachable!(), )); } } From 4490387dc5feaae752e92636a535c5bdeb7e2333 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Tue, 23 Feb 2021 11:14:14 +0900 Subject: [PATCH 07/12] Fix wrappers using wrong ident --- crates/bevy_reflect/bevy_reflect_derive/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index a9f3dab37e7e9..1bde62e83447d 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -954,7 +954,7 @@ fn impl_enum( };); token_stream.extend(TokenStream::from(quote! { #[repr(transparent)] - pub struct #wrapper_ident(TestEnum); + pub struct #wrapper_ident(#enum_name); impl #bevy_reflect_path::Reflect for #wrapper_ident { fn type_name(&self) -> &str { #wrapper_name @@ -1097,7 +1097,7 @@ fn impl_enum( };); token_stream.extend(TokenStream::from(quote! { #[repr(transparent)] - pub struct #wrapper_ident(TestEnum); + pub struct #wrapper_ident(#enum_name); impl #bevy_reflect_path::Reflect for #wrapper_ident { fn type_name(&self) -> &str { #wrapper_name From 9357f2f56f96a054747df1167acd604a2de1d07e Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Tue, 23 Feb 2021 11:14:49 +0900 Subject: [PATCH 08/12] Fix bevy path --- .../bevy_reflect_derive/src/lib.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 1bde62e83447d..5ab42229025a2 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -727,7 +727,7 @@ fn impl_enum( Fields::Named(_struct_fields) => { quote!({ let wrapper_ref = unsafe { std::mem::transmute::< &Self, &#wrapper_ident >(self) }; - #bevy_reflect_path::EnumVariant::Struct(wrapper_ref as &dyn Struct) + #bevy_reflect_path::EnumVariant::Struct(wrapper_ref as &dyn #bevy_reflect_path::Struct) }) } Fields::Unnamed(tuple_fields) => { @@ -736,7 +736,7 @@ fn impl_enum( } else { quote!({ let wrapper_ref = unsafe { std::mem::transmute::< &Self, &#wrapper_ident >(self) }; - #bevy_reflect_path::EnumVariant::Tuple(wrapper_ref as &dyn Tuple) + #bevy_reflect_path::EnumVariant::Tuple(wrapper_ref as &dyn #bevy_reflect_path::Tuple) }) } } @@ -750,7 +750,7 @@ fn impl_enum( Fields::Named(_struct_fields) => { quote!({ let wrapper_ref = unsafe { std::mem::transmute::< &mut Self, &mut #wrapper_ident >(self) }; - #bevy_reflect_path::EnumVariantMut::Struct(wrapper_ref as &mut dyn Struct) + #bevy_reflect_path::EnumVariantMut::Struct(wrapper_ref as &mut dyn #bevy_reflect_path::Struct) }) } Fields::Unnamed(tuple) => { @@ -760,7 +760,7 @@ fn impl_enum( } else { quote!({ let wrapper_ref = unsafe { std::mem::transmute::< &mut Self, &mut #wrapper_ident >(self) }; - #bevy_reflect_path::EnumVariantMut::Tuple(wrapper_ref as &mut dyn Tuple) + #bevy_reflect_path::EnumVariantMut::Tuple(wrapper_ref as &mut dyn #bevy_reflect_path::Tuple) }) } } @@ -1051,11 +1051,11 @@ fn impl_enum( #fields_len } - fn iter_fields(&self) -> bevy::reflect::FieldIter { - FieldIter::new(self) + fn iter_fields(&self) -> #bevy_reflect_path::FieldIter { + #bevy_reflect_path::FieldIter::new(self) } - fn clone_dynamic(&self) -> bevy::reflect::DynamicStruct { + fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicStruct { #match_fields let mut dynamic = #bevy_reflect_path::DynamicStruct::default(); dynamic.set_name(self.type_name().to_string()); @@ -1172,11 +1172,11 @@ fn impl_enum( #fields_len } - fn iter_fields(&self) -> bevy::reflect::TupleFieldIter { - TupleFieldIter::new(self) + fn iter_fields(&self) -> #bevy_reflect_path::TupleFieldIter { + #bevy_reflect_path::TupleFieldIter::new(self) } - fn clone_dynamic(&self) -> bevy::reflect::DynamicTuple { + fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicTuple { #match_fields let mut dynamic = #bevy_reflect_path::DynamicTuple::default(); #(dynamic.insert_boxed(#field_idents.clone_value());)* From 82a17778fa3e07088bc42b3266d4797c3ec6f14e Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Tue, 23 Feb 2021 11:34:55 +0900 Subject: [PATCH 09/12] Use Clone in apply for now --- crates/bevy_reflect/bevy_reflect_derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 5ab42229025a2..f0aa8dbc34bf6 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -887,7 +887,7 @@ fn impl_enum( use #bevy_reflect_path::Enum; let value = value.any(); if let Some(value) = value.downcast_ref::() { - *self = value.clone_value(); + *self = value.clone(); //FIXME: should apply the variant instead } else { panic!("Attempted to apply non-enum type to enum type."); } From d9efc321ef76f515c5195ebaf3f4f9fe87539653 Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Tue, 23 Feb 2021 11:47:39 +0900 Subject: [PATCH 10/12] clippy --- crates/bevy_reflect/bevy_reflect_derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index f0aa8dbc34bf6..1b5e18924fc7c 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -696,7 +696,7 @@ fn impl_enum( } Fields::Unnamed(tuple_fields) => { let field_idents = (0..tuple_fields.unnamed.len()) - .map(|i| tuple_field_ident(i)) + .map(tuple_field_ident) .collect::>(); if tuple_fields.unnamed.len() == 1 { quote!(#variant_ident (new_type)) From 9f57610bf75fe352bd507abffefcbc966f31a03c Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Thu, 25 Feb 2021 12:46:52 +0900 Subject: [PATCH 11/12] Fix duplicated ident when using multiple struct or tuple variants --- .../bevy_reflect_derive/src/lib.rs | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 1b5e18924fc7c..b127652a23ac3 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -934,18 +934,10 @@ fn impl_enum( field_indices.push(i); } let fields_len = field_indices.len(); - let mut match_fields = quote!(); - for (i, _variant_ident) in variant_idents.iter().enumerate() { - if i == *variant_index { - match_fields.extend(quote!( - #variant_with_fields_ident => (#(#field_idents,)*), - )); - } else { - match_fields.extend(quote!( - #variant_with_fields_ident => unreachable!(), - )); - } - } + let match_fields = quote!( + #variant_with_fields_ident => (#(#field_idents,)*), + _ => unreachable!(), + ); let match_fields_mut = quote!(let (#(#field_idents,)*) = match &mut self.0 { #match_fields };); @@ -1077,18 +1069,10 @@ fn impl_enum( field_indices.push(index); } let fields_len = field_indices.len(); - let mut match_fields = quote!(); - for (i, _variant_ident) in variant_idents.iter().enumerate() { - if i == *variant_index { - match_fields.extend(quote!( - #variant_with_fields_ident => (#(#field_idents,)*), - )); - } else { - match_fields.extend(quote!( - #variant_with_fields_ident => unreachable!(), - )); - } - } + let match_fields = quote!( + #variant_with_fields_ident => (#(#field_idents,)*), + _ => unreachable!(), + ); let match_fields_mut = quote!(let (#(#field_idents,)*) = match &mut self.0 { #match_fields };); From 59c0b9773283168d978c1c4de305af36330e4cab Mon Sep 17 00:00:00 2001 From: Brice DAVIER Date: Thu, 25 Feb 2021 12:52:46 +0900 Subject: [PATCH 12/12] Remove whitespace from variant names --- crates/bevy_reflect/bevy_reflect_derive/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index b127652a23ac3..fbd0692f8b3c4 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -665,7 +665,11 @@ fn impl_enum( let ident = &variant.ident; quote!(#enum_name::#ident) }; - let variant_name = variant_ident.to_string(); + let variant_name = variant_ident + .to_string() + .chars() + .filter(|c| !c.is_whitespace()) + .collect::(); let variant_without_fields_ident = { match &variant.fields { Fields::Named(_struct_fields) => {