Documentation
fn print_type(ty: &dxcwr::Type, indent: usize) {
    match ty {
        dxcwr::Type::Struct(s) => {
            println!("{} {{", s.name);
            for member in s.members.iter() {
                print!("{:indent$}{}: ", "", member.name, indent = (indent + 1) * 4);
                print_type(&member.ty, indent + 1);
            }
            println!("{:indent$}}}", "", indent = indent * 4);
        }
        dxcwr::Type::Vector(v) => println!("{:?}", v),
        dxcwr::Type::Matrix(m) => println!("{:?}", m),
        _ => println!("{:?}", ty),
    }
}

fn print_reflection(reflection: &dxcwr::Reflection) -> anyhow::Result<()> {
    println!("[input parameters]");
    for input in reflection.input_parameters()? {
        println!("{{");
        println!("    semantic name: {}", input.semantic_name());
        println!("    semantic index: {}", input.semantic_index());
        println!("    system_value_type: {:?}", input.system_value_type());
        println!("    component_type: {:?}", input.component_type());
        println!("    mask: 0x{:x}", input.mask());
        println!("    read_write_mask: 0x{:x}", input.read_write_mask());
        println!("    stream: {}", input.stream());
        println!("    min_precision: {:?}", input.min_precision());
        println!("}}");
    }
    println!("\n[resource bind descs]");
    match reflection.resource_bind_descs() {
        Ok(descs) => {
            for desc in descs {
                println!("{{");
                println!("    input_type: {:?}", desc.input_type());
                println!("    bind_point: {}", desc.bind_point());
                println!("    bind_count: {}", desc.bind_count());
                println!("    flags: {:?}", desc.flags());
                println!("    return_type: {:?}", desc.return_type());
                println!("    srv_dimension: {:?}", desc.dimension());
                if desc.num_samples() == u32::MAX {
                    println!("    num_samples: not multisampled");
                } else {
                    println!("    num_samples: {}", desc.num_samples());
                }
                println!("    space: {}", desc.space());
                println!("    id: {}", desc.id());
                println!("}}");
            }
        }
        Err(e) => {
            println!("{e}");
        }
    }
    println!("\n[constant buffer descs]");
    match reflection.constant_buffer_descs() {
        Ok(descs) => {
            for desc in descs {
                println!("{{");
                print!("    {}: ", desc.name(),);
                for member in desc.members() {
                    print_type(member, 1);
                }
                println!("}}");
            }
        }
        Err(e) => {
            println!("{e}");
        }
    }
    Ok(())
}

fn main() -> anyhow::Result<()> {
    let dxc = dxcwr::Dxc::new()?;
    let vs = dxc.compile(
        include_str!("../assets/example2.hlsl"),
        dxcwr::Arguments::new()
            .source_name("example2.hlsl")
            .target("vs_6_0")
            .entry_point("vs_main"),
    )?;
    let ps = dxc.compile(
        include_str!("../assets/example2.hlsl"),
        dxcwr::Arguments::new()
            .source_name("example2.hlsl")
            .target("ps_6_0")
            .entry_point("ps_main"),
    )?;
    println!("--- vertex shader ---");
    print_reflection(&vs.reflection()?.unwrap())?;
    println!("\n--- pixel shader ---");
    print_reflection(&ps.reflection()?.unwrap())?;
    Ok(())
}