shdrlib 0.1.5

A three-tiered Vulkan shader compilation and rendering framework built in pure Rust
Documentation
//! EZ tier error types with user-friendly messages
//!
//! EZ tier provides the most beginner-friendly error messages with:
//! - Clear explanations in plain language
//! - Step-by-step recovery instructions
//! - Links to relevant documentation
//! - Common gotchas highlighted

use thiserror::Error;

/// EZ tier error with helpful recovery suggestions
#[derive(Debug, Error)]
pub enum EzError {
    /// RuntimeManager creation failed
    #[error("❌ Failed to initialize Vulkan renderer\n\n\
             What happened:\n\
             {details}\n\n\
             Common causes:\n\
             • Vulkan runtime not installed (install from https://vulkan.lunarg.com/)\n\
             • Outdated GPU drivers\n\
             • GPU doesn't support Vulkan 1.3\n\
             • Validation layers requested but not installed\n\n\
             Try these fixes:\n\
             1. Update your GPU drivers to the latest version\n\
             2. Download and install the Vulkan SDK\n\
             3. If using validation layers, install Vulkan SDK or disable them\n\
             4. Run 'vulkaninfo' to check if Vulkan is working\n\n\
             Need more help? Check: docs/getting-started/troubleshooting.md")]
    InitializationFailed { details: String },

    /// Shader compilation failed
    #[error("❌ Shader compilation failed\n\n\
             What happened:\n\
             Your GLSL shader code has errors and couldn't be compiled to SPIR-V.\n\n\
             Details:\n\
             {details}\n\n\
             Debugging tips:\n\
             • Check the error message above for line numbers\n\
             • Verify your shader version is #version 450 or higher\n\
             • Make sure all variables are declared\n\
             • Check for typos in GLSL keywords\n\
             • Ensure all functions return the correct type\n\n\
             Common GLSL mistakes:\n\
             • Missing semicolons\n\
             • Using = instead of == in comparisons\n\
             • Forgetting to declare uniform blocks\n\
             • Wrong vector component names (use .xyzw or .rgba, not both)\n\n\
             Resources:\n\
             • GLSL quick reference: https://www.khronos.org/files/opengl45-quick-reference-card.pdf\n\
             • Shader examples: demos/ex/README.md")]
    ShaderCompilationFailed { details: String },

    /// Pipeline creation failed
    #[error("❌ Pipeline creation failed\n\n\
             What happened:\n\
             The graphics or compute pipeline couldn't be created.\n\n\
             Details:\n\
             {details}\n\n\
             Common causes:\n\
             • Shaders are incompatible (vertex output doesn't match fragment input)\n\
             • Missing required shader stages\n\
             • Descriptor bindings don't match shader\n\
             • Render format mismatch\n\n\
             Quick fixes:\n\
             1. Ensure vertex shader outputs match fragment shader inputs\n\
             2. Check that both vertex and fragment shaders are provided\n\
             3. Verify color attachment formats are correct\n\
             4. Enable validation layers for detailed error messages\n\n\
             Validation layers:\n\
             Add this to your config: enable_validation: true\n\
             This will show exactly what's wrong!")]
    PipelineCreationFailed { details: String },

    /// Invalid shader stage combination
    #[error("❌ Invalid shader stages\n\n\
             What happened:\n\
             {details}\n\n\
             Quick guide:\n\
             • Graphics pipelines need: vertex shader (required) + fragment shader (optional but recommended)\n\
             • Compute pipelines need: compute shader only\n\n\
             Example:\n\
             For graphics:\n\
               let vert = ez.compile_shader(\"vertex.glsl\", ShaderStage::Vertex)?;\n\
               let frag = ez.compile_shader(\"fragment.glsl\", ShaderStage::Fragment)?;\n\n\
             For compute:\n\
               let comp = ez.compile_shader(\"compute.glsl\", ShaderStage::Compute)?;")]
    InvalidShaderStages { details: String },

    /// Frame operation failed
    #[error("❌ Frame rendering failed\n\n\
             What happened:\n\
             {details}\n\n\
             This could mean:\n\
             • Window was resized (this is normal, recreate swapchain)\n\
             • GPU device was lost (driver crash or timeout)\n\
             • Invalid rendering commands\n\n\
             Recovery steps:\n\
             1. If window resized: catch this error and recreate swapchain\n\
             2. If device lost: reinitialize everything (full restart)\n\
             3. Enable validation layers to see what command failed\n\n\
             Preventing device loss:\n\
             • Avoid infinite loops in shaders\n\
             • Check for validation errors early\n\
             • Don't exceed GPU timeouts (Windows: 2 seconds default)")]
    FrameFailed { details: String },

    /// Resource creation failed
    #[error("❌ Failed to create {resource_type}\n\n\
             What happened:\n\
             {details}\n\n\
             Common causes:\n\
             • Out of GPU memory (VRAM)\n\
             • Invalid parameters\n\
             • Resource too large\n\n\
             Tips:\n\
             • Check GPU has enough free VRAM\n\
             • Reduce texture sizes or buffer counts\n\
             • Free resources you're not using\n\
             • Monitor memory usage with GPU-Z or similar tools")]
    ResourceCreationFailed {
        resource_type: String,
        details: String,
    },

    /// Buffer operation failed
    #[error("❌ Buffer operation failed: {operation}\n\n\
             What happened:\n\
             {details}\n\n\
             Buffer operations that can fail:\n\
             • Creating buffer (out of memory)\n\
             • Mapping memory (wrong memory type)\n\
             • Uploading data (size mismatch)\n\
             • Binding buffer (wrong offset/range)\n\n\
             Double-check:\n\
             • Buffer size matches your data\n\
             • Memory type supports your usage\n\
             • Offsets are properly aligned\n\
             • Buffer isn't already mapped when mapping")]
    BufferOperationFailed { operation: String, details: String },

    /// Mesh operation failed
    #[error("❌ Mesh operation failed\n\n\
             What happened:\n\
             {details}\n\n\
             Common mesh issues:\n\
             • Vertex/index count mismatch\n\
             • Invalid vertex format\n\
             • Empty mesh data\n\
             • Indices out of bounds\n\n\
             Mesh checklist:\n\
             ✓ Vertices have correct format (position, texcoord, etc.)\n\
             ✓ Index count is multiple of 3 (for triangles)\n\
             ✓ All indices are less than vertex count\n\
             ✓ Data types match shader expectations")]
    MeshOperationFailed { details: String },

    /// Generic runtime error
    #[error("❌ Runtime error\n\n{0}\n\n\
             General troubleshooting:\n\
             1. Enable validation layers for detailed diagnostics\n\
             2. Check if GPU drivers are up to date\n\
             3. Review recent code changes\n\
             4. Look for validation warnings in console\n\n\
             Still stuck? Create an issue with:\n\
             • Your GPU model and driver version\n\
             • Full error message\n\
             • Minimal code to reproduce\n\
             → https://github.com/your-repo/issues")]
    RuntimeError(String),

    /// Validation error with detailed info
    #[error("❌ Vulkan Validation Error\n\n\
             Message ID: {message_id}\n\
             Severity: {severity}\n\n\
             {message}\n\n\
             What are validation errors?\n\
             Validation layers catch Vulkan API misuse before it crashes.\n\
             These errors are CRITICAL and must be fixed!\n\n\
             Location: {location}\n\n\
             Next steps:\n\
             1. Read the message carefully - it tells you exactly what's wrong\n\
             2. Fix the issue (don't just disable validation!)\n\
             3. Test again with validation enabled\n\n\
             Learn more: https://vulkan.lunarg.com/doc/view/latest/windows/validation_error_database.html")]
    ValidationError {
        message_id: String,
        severity: String,
        message: String,
        location: String,
    },
}

// Implement From conversions for lower tier errors
impl From<crate::ex::RuntimeError> for EzError {
    fn from(err: crate::ex::RuntimeError) -> Self {
        match err {
            crate::ex::RuntimeError::InstanceCreationFailed(e) => {
                EzError::InitializationFailed {
                    details: format!("Instance creation failed: {}", e),
                }
            }
            crate::ex::RuntimeError::DeviceCreationFailed(e) => {
                EzError::InitializationFailed {
                    details: format!("Device creation failed: {}", e),
                }
            }
            crate::ex::RuntimeError::NoGraphicsQueue => {
                EzError::InitializationFailed {
                    details: "Selected GPU doesn't have a graphics queue".to_string(),
                }
            }
            crate::ex::RuntimeError::NoSuitableDevice(count) => {
                EzError::InitializationFailed {
                    details: format!(
                        "Found {} GPU(s) but none support Vulkan 1.3 with required features",
                        count
                    ),
                }
            }
            _ => EzError::RuntimeError(err.to_string()),
        }
    }
}

impl From<crate::ex::ShaderManagerError> for EzError {
    fn from(err: crate::ex::ShaderManagerError) -> Self {
        match err {
            crate::ex::ShaderManagerError::ShaderCompilationFailed(e) => {
                EzError::ShaderCompilationFailed {
                    details: e.to_string(),
                }
            }
            crate::ex::ShaderManagerError::PipelineCreationFailed(e) => {
                EzError::PipelineCreationFailed {
                    details: e.to_string(),
                }
            }
            crate::ex::ShaderManagerError::PipelineBuilderError(e) => {
                EzError::PipelineCreationFailed {
                    details: e.to_string(),
                }
            }
            _ => EzError::RuntimeError(err.to_string()),
        }
    }
}

impl From<crate::core::ShaderError> for EzError {
    fn from(err: crate::core::ShaderError) -> Self {
        EzError::ShaderCompilationFailed {
            details: err.to_string(),
        }
    }
}

impl From<crate::core::PipelineError> for EzError {
    fn from(err: crate::core::PipelineError) -> Self {
        EzError::PipelineCreationFailed {
            details: err.to_string(),
        }
    }
}

/// Helper for displaying errors with nice formatting
pub trait EzErrorDisplay {
    fn display_friendly(&self) -> String;
}

impl EzErrorDisplay for EzError {
    fn display_friendly(&self) -> String {
        format!(
            "\n\
            ╔══════════════════════════════════════════════════════════════════╗\n\
            ║                         🚨 EZ TIER ERROR 🚨                       ║\n\
            ╠══════════════════════════════════════════════════════════════════╣\n\
            \n\
            {}\n\
            \n\
            ╚══════════════════════════════════════════════════════════════════╝\n",
            self
        )
    }
}