use {
    crate::{
        graphics::vulkan::{raii, VulkanContext},
        trace,
    },
    anyhow::{bail, Context, Result},
    ash::vk,
    std::path::Path,
};
pub fn spirv_module(
    ctx: &VulkanContext,
    shader_bytes: &[u8],
) -> Result<raii::ShaderModule> {
    let words = spirv_words(shader_bytes)?;
    raii::ShaderModule::new(
        ctx.device.clone(),
        &vk::ShaderModuleCreateInfo {
            code_size: words.len() * 4,
            p_code: words.as_ptr(),
            ..Default::default()
        },
    )
}
pub fn spirv_words(shader_bytes: &[u8]) -> Result<Vec<u32>> {
    if shader_bytes.len() % 4 != 0 {
        bail!(trace!(
            "Invalid length for compiled SPIRV bytes! {}",
            shader_bytes.len()
        )());
    }
    let shader_words: Vec<u32> = shader_bytes
        .chunks(4)
        .map(|w| u32::from_le_bytes([w[0], w[1], w[2], w[3]]))
        .collect();
    Ok(shader_words)
}
pub fn compile_slang(
    ctx: &VulkanContext,
    shader: impl AsRef<Path>,
) -> Result<raii::ShaderModule> {
    let shader = shader.as_ref();
    let shader_path_str = shader
        .to_str()
        .with_context(trace!("Unable to decode {:?} as unicode!", shader))?;
    let output = std::process::Command::new("slangc")
        .args([
            "-matrix-layout-column-major", "-target",
            "spirv",
            "--",
            shader_path_str,
        ])
        .output()
        .with_context(trace!("Error executing slangc!"))?;
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        bail!(trace!("Error when compiling shader!\n\n{}", stderr)());
    }
    spirv_module(ctx, &output.stdout).with_context(trace!(
        "Error creating shader module for {:?}",
        shader_path_str
    ))
}