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 / declarations.rs

use super::*;

pub(super) fn params(decls: &[Decl]) -> String {
    decls
        .iter()
        .filter(|decl| select::api_matches(decl.api.as_deref()))
        .map(|decl| format!("{}: {}", rust_ident(&decl.name), rust_param_type(decl)))
        .collect::<Vec<_>>()
        .join(", ")
}

pub(super) fn rust_param_type(decl: &Decl) -> String {
    if decl.arrays.is_empty() {
        return rust_decl_type(decl, false);
    }
    // C array parameters decay to a pointer to the first element
    let mut element = decl.clone();
    element.arrays.remove(0);
    let pointee_const = decl.pointer_const.is_empty() && decl.base_const;
    format!(
        "*{} {}",
        if pointee_const { "const" } else { "mut" },
        rust_decl_type(&element, false)
    )
}

pub(super) fn call_args(decls: &[Decl]) -> String {
    decls
        .iter()
        .filter(|decl| select::api_matches(decl.api.as_deref()))
        .map(|decl| rust_ident(&decl.name))
        .collect::<Vec<_>>()
        .join(", ")
}

pub(super) fn rust_decl_type(decl: &Decl, is_return: bool) -> String {
    let mut ty = if is_return && decl.base == "void" && decl.pointer_const.is_empty() {
        "()".to_string()
    } else {
        rust_base(&decl.base)
    };

    for pointee_const in &decl.pointer_const {
        ty = format!("*{} {ty}", if *pointee_const { "const" } else { "mut" });
    }

    for dim in decl.arrays.iter().rev() {
        ty = format!("[{ty}; {}]", array_dim(dim));
    }

    ty
}

pub(super) fn rust_base(base: &str) -> String {
    match base {
        "void" => "c_void".to_string(),
        "char" => "c_char".to_string(),
        "float" => "f32".to_string(),
        "double" => "f64".to_string(),
        "int" => "c_int".to_string(),
        "int8_t" => "i8".to_string(),
        "uint8_t" => "u8".to_string(),
        "int16_t" => "i16".to_string(),
        "uint16_t" => "u16".to_string(),
        "int32_t" => "i32".to_string(),
        "uint32_t" => "u32".to_string(),
        "int64_t" => "i64".to_string(),
        "uint64_t" => "u64".to_string(),
        "size_t" => "usize".to_string(),
        other => other.to_string(),
    }
}

pub(super) fn array_dim(dim: &str) -> String {
    if dim.bytes().all(|b| b.is_ascii_digit()) {
        dim.to_string()
    } else {
        format!("{dim} as usize")
    }
}