lava 0.4.9

Rust wrapper to manipulate Vulkan more conveniently than with bindings.
Documentation
const {
    getFieldsInformation
} = require('./utils');

const { EXTENSIONS } = require('./data');

function generateFunctionTableDefinition(functions) {
    for (let func of functions) {
        if (!func.argsInfo) {
            func.argsInfo = getFieldsInformation(func.args);
        }
    }

    return [
        `#![allow(non_snake_case)]`,
        genUses(functions),
        genDefinition(functions),
        genFromMethods(functions),
        genNullFunctions(functions),
        genExterns(functions)
    ];
}

const FUNCTION_TABLE_NAME = 'VkFunctionTable';

function genUses() {
    return [
        `std::os::raw::c_char`,
        `std::mem`,
        `utils::c_bindings::*`,
        `utils::vk_convert::{get_vk_instance_function_pointer, get_vk_device_function_pointer}`,
        'vulkan::vk::*',
        `vulkan::{${EXTENSIONS.map(str => str.toLowerCase()).join(',')}}`
    ].map(x => `use ${x};`);
}

function genDefinition(functions) {
    return [
        `#[doc(hidden)]`,
        `pub struct ${FUNCTION_TABLE_NAME}`, [
            `pub instance: RawVkInstance,`,
            `pub device: RawVkDevice,`,
            ...functions.map(func => `pub ${func.name}: ${functionToDeclaration(func)},`)
        ]
    ];
}

function getArgType(arg) {
    let type = arg.rawType;

    if (arg.extension) {
        type = type.replace(arg.rawTypeName, `${arg.extension}::${arg.rawTypeName}`)
    }

    return type;
}

function functionToDeclaration(func) {
    const args = func.argsInfo.map(getArgType);
    const returnType = func.type === 'VkResult' ? ' -> RawVkResult' : '';

    return `unsafe extern fn(${args.join(', ')})${returnType}`;
}

function getVkFunctionPrototype(func) {
    const args = func.argsInfo.map(arg => `${arg.varName}: ${getArgType(arg)}`);
    const returnType = func.type === 'VkResult' ? ' -> RawVkResult' : '';

    return `(${args.join(', ')})${returnType}`;
}

function genNullFunctions(functions) {
    return genNullFunctionsForParent(functions, 'instance').concat(genNullFunctionsForParent(functions, 'device'));
}

function genNullFunctionsForParent(functions, parent) {
    return functions.filter(func => func.name.startsWith('vk')).map(func => {
        const funcName = `null_${parent}_${func.name}`;

        return [
            `unsafe extern fn ${funcName}${getVkFunctionPrototype(func)}`, [
                `panic!("\\"vkGet${parent.capitalize()}ProcAddr\\" returned NULL for \\"${func.name}\\"");`
            ]
        ];
    }).reduce((acc, value) => acc.concat(value), []);
}

function getFunctionPointer(func, parent) {
    if (func.name.startsWith('vk')) {
        return `{ let fn_ptr = get_vk_${parent}_function_pointer(${parent}, "${func.name}"); if fn_ptr.is_null() { null_${parent}_${func.name} } else { mem::transmute(fn_ptr) } }`;
    } else {
        return func.name;
    }
}

function genFromMethods(functions) {
    return [
        `impl ${FUNCTION_TABLE_NAME}`, [
            `pub fn from_instance(instance: RawVkInstance) -> Self`, [
                `unsafe`, [
                    `Self`, [
                        `instance: instance,`,
                        `device: 0,`,
                        ...functions.map(func => `${func.name}: ${getFunctionPointer(func, 'instance')},`)
                    ]
                ]
            ],
            `pub fn from_device(device: RawVkDevice) -> Self`, [
                `unsafe`, [
                    `Self`, [
                        `instance: 0,`,
                        `device: device,`,
                        ...functions.map(func => `${func.name}: ${getFunctionPointer(func, 'device')},`)
                    ]
                ]
            ]
        ]
    ]
}

function genExterns(functions) {
    const externs = functions.filter(func => !func.name.startsWith('vk'));

    if (externs.length) {
        return [
            `extern`,
            externs.map(func => `fn ${func.name}${getVkFunctionPrototype(func)};`)
        ]
    }
}

module.exports = {
    generateFunctionTableDefinition,
    getVkFunctionPrototype
};