vulkan_gen 0.1.0

Vulkan XML specification parser and Rust binding generator. Used internally by the vulkane crate, but reusable as a standalone code generator.
Documentation
//! Extensions generator module
//!
//! Generates Rust extension handling code from extensions.json intermediate file

use crate::parser::vk_types::ExtensionDefinition;
use std::fs;
use std::path::Path;

use super::{GeneratorError, GeneratorMetadata, GeneratorModule, GeneratorResult};

/// Generator module for Vulkan extensions
pub struct ExtensionGenerator;

impl Default for ExtensionGenerator {
    fn default() -> Self {
        Self::new()
    }
}

impl ExtensionGenerator {
    pub fn new() -> Self {
        Self
    }

    /// Generate Rust code for a single extension
    fn generate_extension(&self, ext: &ExtensionDefinition) -> String {
        let mut code = String::new();

        // Documentation comment with metadata
        if let Some(line) = ext.source_line {
            code.push_str(&format!(
                "/// Vulkan extension: {} (from line {})\n",
                ext.name, line
            ));
        } else {
            code.push_str(&format!("/// Vulkan extension: {}\n", ext.name));
        }

        if let Some(platform) = &ext.platform {
            code.push_str(&format!("/// Platform: {}\n", platform));
        }

        if let Some(author) = &ext.author {
            code.push_str(&format!("/// Author: {}\n", author));
        }

        if ext.provisional.is_some() {
            code.push_str("/// Status: Provisional\n");
        }

        if let Some(deprecated) = &ext.deprecated {
            code.push_str(&format!("/// Deprecated: {}\n", deprecated));
        }

        if let Some(promoted_to) = &ext.promotedto {
            code.push_str(&format!("/// Promoted to: {}\n", promoted_to));
        }

        // Extension name constant
        let const_name = format!(
            "{}_EXTENSION_NAME",
            ext.name.to_uppercase().replace("VK_", "")
        );
        code.push_str(&format!(
            "pub const {}: &str = \"{}\";\n",
            const_name, ext.name
        ));

        // Extension number if available
        if let Some(number) = &ext.number {
            let number_const = format!(
                "{}_SPEC_VERSION",
                ext.name.to_uppercase().replace("VK_", "")
            );
            code.push_str(&format!("pub const {}: u32 = {};\n", number_const, number));
        }

        // Extension features structures are generated by the structs generator
        // Skip generating stub structures here to avoid conflicts

        code.push('\n');
        code
    }

    /// Extension function pointer types and utilities are generated from vk.xml
    /// by the FunctionGenerator — no hardcoded types needed here.
    fn generate_extension_function_types(&self, _extensions: &[ExtensionDefinition]) -> String {
        String::new()
    }

    fn generate_extension_utilities(&self) -> String {
        String::new()
    }
}

impl GeneratorModule for ExtensionGenerator {
    fn name(&self) -> &str {
        "ExtensionGenerator"
    }

    fn input_files(&self) -> Vec<String> {
        vec!["extensions.json".to_string()]
    }

    fn output_file(&self) -> String {
        "extensions.rs".to_string()
    }

    fn dependencies(&self) -> Vec<String> {
        vec![
            "TypeGenerator".to_string(),
            "ConstantGenerator".to_string(),
            "StructGenerator".to_string(),
            "FunctionGenerator".to_string(),
        ]
    }

    fn generate(&self, input_dir: &Path, output_dir: &Path) -> GeneratorResult<()> {
        // Read input file
        let input_path = input_dir.join("extensions.json");
        let content =
            fs::read_to_string(&input_path).map_err(|_| GeneratorError::MissingInput {
                path: input_path.display().to_string(),
            })?;

        let extensions: Vec<ExtensionDefinition> = serde_json::from_str(&content)?;

        // Generate code
        let mut code = String::new();

        // File header
        code.push_str(
            "// Generated Vulkan extension definitions\n\
            //\n\
            // This file contains extension constants, feature structures,\n\
            // and utility functions for Vulkan extensions.\n\
            // Do not edit this file directly.\n\n",
        );

        // Generate individual extensions
        code.push_str("// === EXTENSION DEFINITIONS ===\n\n");
        for extension in &extensions {
            code.push_str(&self.generate_extension(extension));
        }

        // Generate function pointer types
        code.push_str(&self.generate_extension_function_types(&extensions));

        // Generate utilities
        code.push_str(&self.generate_extension_utilities());

        // Write output file
        let output_path = output_dir.join(self.output_file());
        fs::write(output_path, code)?;

        Ok(())
    }

    fn metadata(&self) -> GeneratorMetadata {
        GeneratorMetadata {
            defined_types: vec![
                "VkExtensionProperties".to_string(),
                "PFN_vkGetInstanceProcAddr".to_string(),
                "PFN_vkGetDeviceProcAddr".to_string(),
            ],
            used_types: vec![
                "VkStructureType".to_string(),
                "VkInstance".to_string(),
                "VkDevice".to_string(),
                "c_char".to_string(),
                "c_void".to_string(),
            ],
            has_forward_declarations: false,
            priority: 20, // After types and constants, before functions
        }
    }
}