#Derive Macro: Enum Variation order not consistent?

11 messages · Page 1 of 1 (latest)

verbal elbow
#

This isnt necessarily bevy related, but maybe someone could still help me?

I'm working on a derivable macro which loops through variants of an enum and then serializes them in a special format.
All this works, no issues.
But I noticed that the order of the variants doesnt seem to be the same every time?

So my code is like this.
I have this enum that derives QevyProperty:

#[derive(Reflect, Default, QevyProperty)]
#[reflect(QevyProperty, Default)]
#[qevy_property(property_type = "flags")]
enum EnumTestFlag {
    #[default]
    #[qevy_property(selected_by_default = true)]
    Test,
    EnumVariantTest,
}

the macro code itself is too long for this message, so i'll send it after

#

the releveant part (i think?) should be after //Extract field attributes

fn qevy_property_derive_macro2(
    item: proc_macro2::TokenStream,
) -> deluxe::Result<proc_macro2::TokenStream> {
    // Parse
    let mut ast: DeriveInput = syn::parse2(item)?;

    // Extract struct attributes
    let QevyPropertyStructAttributes { property_type } = deluxe::extract_attributes(&mut ast)?;
    let ident = &ast.ident;
    let ident_name = ident.to_string();

    // Extract field attributes
    // TODO: the order of the fields doesn't seem to be guaranteed...?
    let field_attrs = extract_qevy_property_field_attributes(&mut ast)?;
    let (field_names, field_attrs): (Vec<String>, Vec<QevyPropertyFieldAttributes>) = field_attrs
        .into_iter()
        .map(|(field, attrs)| (field, attrs))
        .unzip();

    let formatted_field_strings = match property_type.as_str() {
        "flags" => {
            let mut formatted_field_strings = String::new();
            formatted_field_strings.push_str(" =\n\t[\n");

            formatted_field_strings.push_str(
                field_names
                    .iter()
                    .enumerate()
                    .map(|(i, field)| {
                        let selected_by_default = if field_attrs[i].selected_by_default {
                            "1"
                        } else {
                            "0"
                        };
                        format!("\t\t{} : \"{}\" : {}\n", i + 1, field, selected_by_default)
                    })
                    .collect::<Vec<String>>()
                    .join("")
                    .as_str(),
            );

            formatted_field_strings
        }
    }

    /*
      A lot of unrelated things here.
    */

    // generate
    Ok(generated_code)
}
true kraken
#

Please post the extract fn too

#

When I did something similar to this, and ran into a similar issue as you, it was because I stored them in a HashMap which has effectively random ordering

verbal elbow
#

sorry for the late response, took a nap lol

#

ah i forgot to share the extract fn

#

one sec

#

and yeah now that you say it.... i also use a hashmap, didnt even think of that being the issue, but it makes sense.

fn extract_qevy_property_field_attributes(
    ast: &mut DeriveInput,
) -> deluxe::Result<HashMap<String, QevyPropertyFieldAttributes>> {
    let mut field_attrs = HashMap::new();

    if let syn::Data::Enum(e) = &mut ast.data {
        for variant in e.variants.iter_mut() {
            let variant_name = variant.ident.to_string();
            let attrs: QevyPropertyFieldAttributes = deluxe::extract_attributes(variant)?;
            field_attrs.insert(variant_name, attrs);
        }
    }

    Ok(field_attrs)
}
#

@true kraken how did you solve it in your case?

#

ah i guess i could just directly return a (Vec<String>, Vec<QevyPropertyFieldAttributes>), as i'm litteraly directly converting that into this after calling the function and am not even using the hashmap...

true kraken
#

Yeah I just switched to Vec