const {
toPascalCase,
getRawVkTypeName,
getWrappedVkTypeName,
getConstVkValueName,
findEnumPrefix,
toSnakeCase,
getFullWrappedType,
getFullRawType,
blockToString,
isCount,
areCountAndArray,
isPlural,
cToRustVarName,
argToString,
getFieldInformation,
documentType
} = require('./utils');
function generateVkBitFlagsDefinition(cDef) {
cDef.rawTypeName = getRawVkTypeName(cDef.name);
cDef.wrappedTypeName = getWrappedVkTypeName(cDef.name);
const prefix = findEnumPrefix(cDef.name.replace('Flags', ''));
const extSuffix = `_${cDef.extension.toUpperCase()}`;
for (let field of cDef.fields) {
const name = field.name.replace('_BIT', '');
const suffix = name.endsWith(extSuffix) ? extSuffix : '';
const strippedName = name.substring(prefix.length + 1, name.length - suffix.length);
field.varName = formatBitFlagsFieldName(strippedName);
}
return [
genUses(),
genWrappedType(cDef),
genRawType(cDef),
genImplVkWrappedType(cDef),
genImplVkRawType(cDef),
genImplDefault(cDef),
genImplFlags(cDef, 'u32')
];
}
function genUses() {
return [
`utils::vk_traits::*`
].map(str => `use ${str};`);
}
function genRawType(def) {
return [
`#[doc(hidden)]`,
`pub type ${def.rawTypeName} = u32;`
];
}
function genFlagBitsDoc(def) {
const fields = def.fields.slice(0, 2).map(f => f.varName);
return [
`Use the macro \`${def.wrappedTypeName}!\` as an alternative method to create a structure. For example, these two snippets return the same value:`,
'```',
`${def.wrappedTypeName}!(${fields.join(', ')})`,
'```',
'```',
`${def.wrappedTypeName} {`,
...fields.map(f => ` ${f}: true,`),
def.fields.length <= 2 ? '' : ` ..${def.wrappedTypeName}::none()`,
`}`,
'```'
].filter(x => x).map(x => `/// ${x}`).join('\n');
}
function genWrappedType(def) {
return [
documentType(def, genFlagBitsDoc(def)),
`#[derive(Debug, Clone)]`,
`pub struct ${def.wrappedTypeName}`,
def.fields.map(field => `pub ${field.varName}: bool,`)
];
}
function genImplVkRawType(def) {
return [
`impl VkRawType<${def.wrappedTypeName}> for ${def.rawTypeName}`, [
`fn vk_to_wrapped(src: &${def.rawTypeName}) -> ${def.wrappedTypeName}`, [
def.wrappedTypeName,
def.fields.map(field => `${field.varName}: (src & ${field.value}) != 0,`)
]
]
];
}
function genImplVkWrappedType(def) {
return [
`impl VkWrappedType<${def.rawTypeName}> for ${def.wrappedTypeName}`, [
`fn vk_to_raw(src: &${def.wrappedTypeName}, dst: &mut ${def.rawTypeName})`, [
`*dst = 0;`,
...def.fields.map(field => `if src.${field.varName} { *dst |= ${field.value}; }`),
]
]
];
}
function genImplDefault(def) {
return [
`impl Default for ${def.wrappedTypeName}`, [
`fn default() -> ${def.wrappedTypeName}`, [
def.wrappedTypeName,
def.fields.map(field => `${field.varName}: false,`)
]
]
];
}
function formatBitFlagsFieldName(name) {
return toSnakeCase(name)
.replace(/^(\d)/, '_$1');
}
const NONE_DOC = '/// Return a structure with all flags to `false`.\n'
const ALL_DOC = '/// Return a structure with all flags to `true`.\n'
const TO_U32_DOC = '/// Return the numerical bit flags corresponding to the structure (as described in the Vulkan specs).\n';
const FROM_U32_DOC = '/// Create a structure corresponding to the specified numerical bit flags.\n';
const MACRO_NAME_CONFLICTS = [
'VkExternalMemoryFeatureFlags',
'VkExternalMemoryHandleTypeFlags'
];
function genImplFlags(def, intType) {
let macroSuffix = '';
if (MACRO_NAME_CONFLICTS.includes(def.wrappedTypeName)) {
macroSuffix = def.extension.capitalize();
}
const toIntDoc = intType === 'u32' ? TO_U32_DOC : '';
const fromIntDoc = intType === 'u32' ? FROM_U32_DOC : '';
return [
`impl ${def.wrappedTypeName}`, [
`\n${NONE_DOC}pub fn none() -> Self`, [
def.wrappedTypeName,
def.fields.map(field => `${field.varName}: false,`)
],
`\n${ALL_DOC}pub fn all() -> Self`, [
def.wrappedTypeName,
def.fields.map(field => `${field.varName}: true,`)
],
`\n${toIntDoc}pub fn to_${intType}(&self) -> ${intType}`, [
`0${def.fields.map(field => `\n+ if self.${field.varName} { ${field.value} } else { 0 }`).join('')}`
],
`\n${fromIntDoc}pub fn from_${intType}(value: ${intType}) -> Self`, [
def.wrappedTypeName,
def.fields.map(field => `${field.varName}: value & ${field.value} > 0,`)
]
],
``,
`#[doc(hidden)]`,
`#[macro_export]`,
`macro_rules! ${def.wrappedTypeName}${macroSuffix}`, [
`( $( $x:ident ),* ) =>`, [
`${def.wrappedTypeName}`, [
`$($x: true,)*`,
`..${def.wrappedTypeName}::none()`
]
]
]
];
}
module.exports = {
generateVkBitFlagsDefinition,
genImplFlags,
genFlagBitsDoc
};