Skip to content

Commit

Permalink
Added Enum::variant_index
Browse files Browse the repository at this point in the history
  • Loading branch information
MrGVSV committed Sep 19, 2022
1 parent 3579313 commit ed0e660
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 18 deletions.
24 changes: 20 additions & 4 deletions crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
enum_name_at,
enum_field_len,
enum_variant_name,
enum_variant_index,
enum_variant_type,
} = generate_impls(reflect_enum, &ref_index, &ref_name);

Expand Down Expand Up @@ -137,6 +138,14 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
}
}

#[inline]
fn variant_index(&self) -> usize {
match self {
#(#enum_variant_index,)*
_ => unreachable!(),
}
}

#[inline]
fn variant_type(&self) -> #bevy_reflect_path::VariantType {
match self {
Expand Down Expand Up @@ -255,6 +264,7 @@ struct EnumImpls {
enum_name_at: Vec<proc_macro2::TokenStream>,
enum_field_len: Vec<proc_macro2::TokenStream>,
enum_variant_name: Vec<proc_macro2::TokenStream>,
enum_variant_index: Vec<proc_macro2::TokenStream>,
enum_variant_type: Vec<proc_macro2::TokenStream>,
}

Expand All @@ -268,13 +278,21 @@ fn generate_impls(reflect_enum: &ReflectEnum, ref_index: &Ident, ref_name: &Iden
let mut enum_name_at = Vec::new();
let mut enum_field_len = Vec::new();
let mut enum_variant_name = Vec::new();
let mut enum_variant_index = Vec::new();
let mut enum_variant_type = Vec::new();

for variant in reflect_enum.variants() {
for (variant_index, variant) in reflect_enum.variants().iter().enumerate() {
let ident = &variant.data.ident;
let name = ident.to_string();
let unit = reflect_enum.get_unit(ident);

enum_variant_name.push(quote! {
#unit{..} => #name
});
enum_variant_index.push(quote! {
#unit{..} => #variant_index
});

fn for_fields(
fields: &[StructField],
mut generate_for_field: impl FnMut(usize, usize, &StructField) -> proc_macro2::TokenStream,
Expand Down Expand Up @@ -302,9 +320,6 @@ fn generate_impls(reflect_enum: &ReflectEnum, ref_index: &Ident, ref_name: &Iden
enum_field_len.push(quote! {
#unit{..} => #field_len
});
enum_variant_name.push(quote! {
#unit{..} => #name
});
enum_variant_type.push(quote! {
#unit{..} => #bevy_reflect_path::VariantType::#variant
});
Expand Down Expand Up @@ -359,6 +374,7 @@ fn generate_impls(reflect_enum: &ReflectEnum, ref_index: &Ident, ref_name: &Iden
enum_name_at,
enum_field_len,
enum_variant_name,
enum_variant_index,
enum_variant_type,
}
}
51 changes: 48 additions & 3 deletions crates/bevy_reflect/src/enums/dynamic_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl From<()> for DynamicVariant {
pub struct DynamicEnum {
name: String,
variant_name: String,
variant_index: usize,
variant: DynamicVariant,
}

Expand All @@ -96,6 +97,30 @@ impl DynamicEnum {
) -> Self {
Self {
name: name.into(),
variant_index: 0,
variant_name: variant_name.into(),
variant: variant.into(),
}
}

/// Create a new [`DynamicEnum`] with a variant index to represent an enum at runtime.
///
/// # Arguments
///
/// * `name`: The type name of the enum
/// * `variant_index`: The index of the variant to set
/// * `variant_name`: The name of the variant to set
/// * `variant`: The variant data
///
pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
name: I,
variant_index: usize,
variant_name: I,
variant: V,
) -> Self {
Self {
name: name.into(),
variant_index,
variant_name: variant_name.into(),
variant: variant.into(),
}
Expand All @@ -117,6 +142,18 @@ impl DynamicEnum {
self.variant = variant.into();
}

/// Set the current enum variant represented by this struct along with its variant index.
pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
&mut self,
variant_index: usize,
name: I,
variant: V,
) {
self.variant_index = variant_index;
self.variant_name = name.into();
self.variant = variant.into();
}

/// Create a [`DynamicEnum`] from an existing one.
///
/// This is functionally the same as [`DynamicEnum::from_ref`] except it takes an owned value.
Expand All @@ -129,8 +166,9 @@ impl DynamicEnum {
/// This is functionally the same as [`DynamicEnum::from`] except it takes a reference.
pub fn from_ref<TEnum: Enum>(value: &TEnum) -> Self {
match value.variant_type() {
VariantType::Unit => DynamicEnum::new(
VariantType::Unit => DynamicEnum::new_with_index(
value.type_name(),
value.variant_index(),
value.variant_name(),
DynamicVariant::Unit,
),
Expand All @@ -139,8 +177,9 @@ impl DynamicEnum {
for field in value.iter_fields() {
data.insert_boxed(field.value().clone_value());
}
DynamicEnum::new(
DynamicEnum::new_with_index(
value.type_name(),
value.variant_index(),
value.variant_name(),
DynamicVariant::Tuple(data),
)
Expand All @@ -151,8 +190,9 @@ impl DynamicEnum {
let name = field.name().unwrap();
data.insert_boxed(name, field.value().clone_value());
}
DynamicEnum::new(
DynamicEnum::new_with_index(
value.type_name(),
value.variant_index(),
value.variant_name(),
DynamicVariant::Struct(data),
)
Expand Down Expand Up @@ -226,6 +266,10 @@ impl Enum for DynamicEnum {
&self.variant_name
}

fn variant_index(&self) -> usize {
self.variant_index
}

fn variant_type(&self) -> VariantType {
match &self.variant {
DynamicVariant::Unit => VariantType::Unit,
Expand All @@ -237,6 +281,7 @@ impl Enum for DynamicEnum {
fn clone_dynamic(&self) -> DynamicEnum {
Self {
name: self.name.clone(),
variant_index: self.variant_index,
variant_name: self.variant_name.clone(),
variant: self.variant.clone(),
}
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_reflect/src/enums/enum_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ pub trait Enum: Reflect {
fn field_len(&self) -> usize;
/// The name of the current variant.
fn variant_name(&self) -> &str;
/// The index of the current variant.
fn variant_index(&self) -> usize;
/// The type of the current variant.
fn variant_type(&self) -> VariantType;
// Clones the enum into a [`DynamicEnum`].
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_reflect/src/impls/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,13 @@ impl<T: FromReflect> Enum for Option<T> {
}
}

fn variant_index(&self) -> usize {
match self {
None => 0,
Some(..) => 1,
}
}

#[inline]
fn variant_type(&self) -> VariantType {
match self {
Expand Down
15 changes: 4 additions & 11 deletions crates/bevy_reflect/src/serde/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,22 +303,15 @@ impl<'a> Serialize for EnumSerializer<'a> {
};

let enum_name = enum_info.name();
let variant_index = self.enum_value.variant_index() as u32;
let variant_info = enum_info
.variant(self.enum_value.variant_name())
.variant_at(variant_index as usize)
.ok_or_else(|| {
Error::custom(format_args!(
"variant `{}` does not exist",
self.enum_value.variant_name()
"variant at index `{}` does not exist",
variant_index
))
})?;
let variant_index = enum_info
.index_of(self.enum_value.variant_name())
.ok_or_else(|| {
Error::custom(format_args!(
"variant `{}` does not exist",
self.enum_value.variant_name()
))
})? as u32;
let variant_name = variant_info.name();
let variant_type = self.enum_value.variant_type();
let field_len = self.enum_value.field_len();
Expand Down

0 comments on commit ed0e660

Please sign in to comment.