Theme

alex/volcanic

Automated vulkan bindings

BRANCH main
main
SNAPSHOT Improved loading api and made ready for publish
DOWNLOAD
Download file

root / codegen / src / emit / enums.rs

use super::*;

pub(super) fn rust_enum_infos(
    vk: &Registry,
    video: &Registry,
    modules: &[EmitModule],
    enum_widths: &IndexMap<String, &'static str>,
    bit_enums_to_flags: &IndexMap<String, String>,
) -> IndexMap<String, RustEnumInfo> {
    let groups: IndexSet<_> = video
        .enum_groups
        .iter()
        .chain(&vk.enum_groups)
        .filter(|group| group.kind == "enum")
        .filter_map(|group| group.name.as_deref())
        .filter(|name| !bit_enums_to_flags.contains_key(*name))
        .collect();
    let entries: IndexMap<_, _> = modules
        .iter()
        .flat_map(|module| module.enums.values())
        .map(|resolved| (resolved.entry.name.as_str(), resolved))
        .collect();
    let mut infos = IndexMap::new();

    for module in modules {
        for resolved in module.enums.values() {
            let Some(group) = resolved
                .group_name
                .as_deref()
                .filter(|name| groups.contains(name))
            else {
                continue;
            };
            if !select::api_matches(resolved.entry.api.as_deref()) {
                continue;
            }
            let value = enum_value(resolved, &entries, enum_widths);
            insert_enum_constant(
                &mut infos,
                group,
                &enum_variant_name(group, &resolved.entry.name),
                value,
                &resolved.condition,
            );
        }
    }
    infos
}

pub(super) fn enum_value<'a>(
    mut resolved: &'a ResolvedEnum,
    entries: &IndexMap<&str, &'a ResolvedEnum>,
    widths: &IndexMap<String, &'static str>,
) -> String {
    for _ in 0..=entries.len() {
        let Some(alias) = &resolved.entry.alias else {
            return const_value_from_widths(
                widths,
                &resolved.entry,
                resolved.group_name.as_deref(),
                resolved.extension_number,
            );
        };
        resolved = entries
            .get(alias.as_str())
            .unwrap_or_else(|| panic!("unknown enum alias target {alias}"));
    }
    panic!("cyclic enum alias involving {}", resolved.entry.name);
}

pub(super) fn insert_enum_constant(
    infos: &mut IndexMap<String, RustEnumInfo>,
    group: &str,
    name: &str,
    value: String,
    condition: &select::FeatureExpr,
) {
    let info = infos
        .entry(group.to_string())
        .or_insert_with(|| RustEnumInfo {
            constants: IndexMap::new(),
        });
    if let Some(existing) = info.constants.get_mut(name) {
        assert_eq!(
            existing.value, value,
            "conflicting values for {group}::{name}"
        );
        existing.condition =
            select::FeatureExpr::any([existing.condition.clone(), condition.clone()]);
    } else {
        info.constants.insert(
            name.to_string(),
            EnumConstant {
                value,
                condition: condition.clone(),
            },
        );
    }
}