Path: blob/main/crates/bevy_reflect/derive/src/impls/enums.rs
9418 views
use crate::{1derive_data::{EnumVariantFields, ReflectEnum, StructField},2enum_utility::{EnumVariantOutputData, TryApplyVariantBuilder, VariantBuilder},3impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed},4};5use bevy_macro_utils::fq_std::{FQOption, FQResult};6use proc_macro2::{Ident, Span};7use quote::quote;8use syn::{Fields, Path};910pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream {11let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path();12let enum_path = reflect_enum.meta().type_path();13let is_remote = reflect_enum.meta().is_remote_wrapper();1415// For `match self` expressions where self is a reference16let match_this = if is_remote {17quote!(&self.0)18} else {19quote!(self)20};21// For `match self` expressions where self is a mutable reference22let match_this_mut = if is_remote {23quote!(&mut self.0)24} else {25quote!(self)26};27// For `*self` assignments28let deref_this = if is_remote {29quote!(self.0)30} else {31quote!(*self)32};3334let ref_name = Ident::new("__name_param", Span::call_site());35let ref_index = Ident::new("__index_param", Span::call_site());36let ref_value = Ident::new("__value_param", Span::call_site());3738let EnumImpls {39enum_field,40enum_field_mut,41enum_field_at,42enum_field_at_mut,43enum_index_of,44enum_name_at,45enum_field_len,46enum_variant_name,47enum_variant_index,48enum_variant_type,49} = generate_impls(reflect_enum, &ref_index, &ref_name);5051let EnumVariantOutputData {52variant_names,53variant_constructors,54..55} = TryApplyVariantBuilder::new(reflect_enum).build(&ref_value);5657let where_clause_options = reflect_enum.where_clause_options();58let typed_impl = impl_typed(&where_clause_options, reflect_enum.to_info_tokens());5960let type_path_impl = impl_type_path(reflect_enum.meta());61let full_reflect_impl = impl_full_reflect(&where_clause_options);62let common_methods = common_partial_reflect_methods(63reflect_enum.meta(),64|| Some(quote!(#bevy_reflect_path::enums::enum_partial_eq)),65|| Some(quote!(#bevy_reflect_path::enums::enum_hash)),66|| Some(quote!(#bevy_reflect_path::enums::enum_partial_cmp)),67);68let clone_fn = reflect_enum.get_clone_impl();6970#[cfg(not(feature = "functions"))]71let function_impls = None::<proc_macro2::TokenStream>;72#[cfg(feature = "functions")]73let function_impls = crate::impls::impl_function_traits(&where_clause_options);7475let get_type_registration_impl = reflect_enum.get_type_registration(&where_clause_options);7677let (impl_generics, ty_generics, where_clause) =78reflect_enum.meta().type_path().generics().split_for_impl();7980#[cfg(not(feature = "auto_register"))]81let auto_register = None::<proc_macro2::TokenStream>;82#[cfg(feature = "auto_register")]83let auto_register = crate::impls::reflect_auto_registration(reflect_enum.meta());8485let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);8687quote! {88#get_type_registration_impl8990#typed_impl9192#type_path_impl9394#full_reflect_impl9596#function_impls9798#auto_register99100impl #impl_generics #bevy_reflect_path::enums::Enum for #enum_path #ty_generics #where_reflect_clause {101fn field(&self, #ref_name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {102match #match_this {103#(#enum_field,)*104_ => #FQOption::None,105}106}107108fn field_at(&self, #ref_index: usize) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {109match #match_this {110#(#enum_field_at,)*111_ => #FQOption::None,112}113}114115fn field_mut(&mut self, #ref_name: &str) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {116match #match_this_mut {117#(#enum_field_mut,)*118_ => #FQOption::None,119}120}121122fn field_at_mut(&mut self, #ref_index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {123match #match_this_mut {124#(#enum_field_at_mut,)*125_ => #FQOption::None,126}127}128129fn index_of(&self, #ref_name: &str) -> #FQOption<usize> {130match #match_this {131#(#enum_index_of,)*132_ => #FQOption::None,133}134}135136fn name_at(&self, #ref_index: usize) -> #FQOption<&str> {137match #match_this {138#(#enum_name_at,)*139_ => #FQOption::None,140}141}142143fn iter_fields(&self) -> #bevy_reflect_path::enums::VariantFieldIter {144#bevy_reflect_path::enums::VariantFieldIter::new(self)145}146147#[inline]148fn field_len(&self) -> usize {149match #match_this {150#(#enum_field_len,)*151_ => 0,152}153}154155#[inline]156fn variant_name(&self) -> &str {157match #match_this {158#(#enum_variant_name,)*159_ => unreachable!(),160}161}162163#[inline]164fn variant_index(&self) -> usize {165match #match_this {166#(#enum_variant_index,)*167_ => unreachable!(),168}169}170171#[inline]172fn variant_type(&self) -> #bevy_reflect_path::enums::VariantType {173match #match_this {174#(#enum_variant_type,)*175_ => unreachable!(),176}177}178179fn to_dynamic_enum(&self) -> #bevy_reflect_path::enums::DynamicEnum {180#bevy_reflect_path::enums::DynamicEnum::from_ref::<Self>(self)181}182}183184impl #impl_generics #bevy_reflect_path::PartialReflect for #enum_path #ty_generics #where_reflect_clause {185#[inline]186fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {187#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())188}189190#[inline]191fn try_apply(192&mut self,193#ref_value: &dyn #bevy_reflect_path::PartialReflect194) -> #FQResult<(), #bevy_reflect_path::ApplyError> {195if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) =196#bevy_reflect_path::PartialReflect::reflect_ref(#ref_value) {197if #bevy_reflect_path::enums::Enum::variant_name(self) == #bevy_reflect_path::enums::Enum::variant_name(#ref_value) {198// Same variant -> just update fields199match #bevy_reflect_path::enums::Enum::variant_type(#ref_value) {200#bevy_reflect_path::enums::VariantType::Struct => {201for field in #bevy_reflect_path::enums::Enum::iter_fields(#ref_value) {202let name = field.name().unwrap();203if let #FQOption::Some(v) = #bevy_reflect_path::enums::Enum::field_mut(self, name) {204#bevy_reflect_path::PartialReflect::try_apply(v, field.value())?;205}206}207}208#bevy_reflect_path::enums::VariantType::Tuple => {209for (index, field) in ::core::iter::Iterator::enumerate(#bevy_reflect_path::enums::Enum::iter_fields(#ref_value)) {210if let #FQOption::Some(v) = #bevy_reflect_path::enums::Enum::field_at_mut(self, index) {211#bevy_reflect_path::PartialReflect::try_apply(v, field.value())?;212}213}214}215_ => {}216}217} else {218// New variant -> perform a switch219match #bevy_reflect_path::enums::Enum::variant_name(#ref_value) {220#(#variant_names => {221#deref_this = #variant_constructors222})*223name => {224return #FQResult::Err(225#bevy_reflect_path::ApplyError::UnknownVariant {226enum_name: ::core::convert::Into::into(#bevy_reflect_path::DynamicTypePath::reflect_type_path(self)),227variant_name: ::core::convert::Into::into(name),228}229);230}231}232}233} else {234return #FQResult::Err(235#bevy_reflect_path::ApplyError::MismatchedKinds {236from_kind: #bevy_reflect_path::PartialReflect::reflect_kind(#ref_value),237to_kind: #bevy_reflect_path::ReflectKind::Enum,238}239);240}241#FQResult::Ok(())242}243244fn reflect_kind(&self) -> #bevy_reflect_path::ReflectKind {245#bevy_reflect_path::ReflectKind::Enum246}247248fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef {249#bevy_reflect_path::ReflectRef::Enum(self)250}251252fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut {253#bevy_reflect_path::ReflectMut::Enum(self)254}255256fn reflect_owned(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::ReflectOwned {257#bevy_reflect_path::ReflectOwned::Enum(self)258}259260#common_methods261262#clone_fn263}264}265}266267struct EnumImpls {268enum_field: Vec<proc_macro2::TokenStream>,269enum_field_mut: Vec<proc_macro2::TokenStream>,270enum_field_at: Vec<proc_macro2::TokenStream>,271enum_field_at_mut: Vec<proc_macro2::TokenStream>,272enum_index_of: Vec<proc_macro2::TokenStream>,273enum_name_at: Vec<proc_macro2::TokenStream>,274enum_field_len: Vec<proc_macro2::TokenStream>,275enum_variant_name: Vec<proc_macro2::TokenStream>,276enum_variant_index: Vec<proc_macro2::TokenStream>,277enum_variant_type: Vec<proc_macro2::TokenStream>,278}279280fn generate_impls(reflect_enum: &ReflectEnum, ref_index: &Ident, ref_name: &Ident) -> EnumImpls {281let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path();282283let mut enum_field = Vec::new();284let mut enum_field_mut = Vec::new();285let mut enum_field_at = Vec::new();286let mut enum_field_at_mut = Vec::new();287let mut enum_index_of = Vec::new();288let mut enum_name_at = Vec::new();289let mut enum_field_len = Vec::new();290let mut enum_variant_name = Vec::new();291let mut enum_variant_index = Vec::new();292let mut enum_variant_type = Vec::new();293294for (variant_index, variant) in reflect_enum.variants().iter().enumerate() {295let ident = &variant.data.ident;296let name = ident.to_string();297let unit = reflect_enum.get_unit(ident);298299let variant_type_ident = match variant.data.fields {300Fields::Unit => Ident::new("Unit", Span::call_site()),301Fields::Unnamed(..) => Ident::new("Tuple", Span::call_site()),302Fields::Named(..) => Ident::new("Struct", Span::call_site()),303};304305enum_variant_name.push(quote! {306#unit{..} => #name307});308enum_variant_index.push(quote! {309#unit{..} => #variant_index310});311enum_variant_type.push(quote! {312#unit{..} => #bevy_reflect_path::enums::VariantType::#variant_type_ident313});314315fn process_fields(316fields: &[StructField],317mut f: impl FnMut(&StructField) + Sized,318) -> usize {319let mut field_len = 0;320for field in fields.iter() {321if field.attrs.ignore.is_ignored() {322// Ignored field323continue;324};325326f(field);327328field_len += 1;329}330331field_len332}333334/// Process the field value to account for remote types.335///336/// If the field is a remote type, then the value will be transmuted accordingly.337fn process_field_value(338ident: &Ident,339field: &StructField,340is_mutable: bool,341bevy_reflect_path: &Path,342) -> proc_macro2::TokenStream {343let method = if is_mutable {344quote!(as_wrapper_mut)345} else {346quote!(as_wrapper)347};348349field350.attrs351.remote352.as_ref()353.map(|ty| quote!(<#ty as #bevy_reflect_path::ReflectRemote>::#method(#ident)))354.unwrap_or_else(|| quote!(#ident))355}356357match &variant.fields {358EnumVariantFields::Unit => {359let field_len = process_fields(&[], |_| {});360361enum_field_len.push(quote! {362#unit{..} => #field_len363});364}365EnumVariantFields::Unnamed(fields) => {366let field_len = process_fields(fields, |field: &StructField| {367let reflection_index = field368.reflection_index369.expect("reflection index should exist for active field");370371let declare_field = syn::Index::from(field.declaration_index);372373let __value = Ident::new("__value", Span::call_site());374let value_ref = process_field_value(&__value, field, false, bevy_reflect_path);375let value_mut = process_field_value(&__value, field, true, bevy_reflect_path);376377enum_field_at.push(quote! {378#unit { #declare_field : #__value, .. } if #ref_index == #reflection_index => #FQOption::Some(#value_ref)379});380enum_field_at_mut.push(quote! {381#unit { #declare_field : #__value, .. } if #ref_index == #reflection_index => #FQOption::Some(#value_mut)382});383});384385enum_field_len.push(quote! {386#unit{..} => #field_len387});388}389EnumVariantFields::Named(fields) => {390let field_len = process_fields(fields, |field: &StructField| {391let field_ident = field.data.ident.as_ref().unwrap();392let field_name = field_ident.to_string();393let reflection_index = field394.reflection_index395.expect("reflection index should exist for active field");396397let __value = Ident::new("__value", Span::call_site());398let value_ref = process_field_value(&__value, field, false, bevy_reflect_path);399let value_mut = process_field_value(&__value, field, true, bevy_reflect_path);400401enum_field.push(quote! {402#unit{ #field_ident: #__value, .. } if #ref_name == #field_name => #FQOption::Some(#value_ref)403});404enum_field_mut.push(quote! {405#unit{ #field_ident: #__value, .. } if #ref_name == #field_name => #FQOption::Some(#value_mut)406});407enum_field_at.push(quote! {408#unit{ #field_ident: #__value, .. } if #ref_index == #reflection_index => #FQOption::Some(#value_ref)409});410enum_field_at_mut.push(quote! {411#unit{ #field_ident: #__value, .. } if #ref_index == #reflection_index => #FQOption::Some(#value_mut)412});413enum_index_of.push(quote! {414#unit{ .. } if #ref_name == #field_name => #FQOption::Some(#reflection_index)415});416enum_name_at.push(quote! {417#unit{ .. } if #ref_index == #reflection_index => #FQOption::Some(#field_name)418});419});420421enum_field_len.push(quote! {422#unit{..} => #field_len423});424}425};426}427428EnumImpls {429enum_field,430enum_field_mut,431enum_field_at,432enum_field_at_mut,433enum_index_of,434enum_name_at,435enum_field_len,436enum_variant_name,437enum_variant_index,438enum_variant_type,439}440}441442443