generator: Borrow all command names and disentangle "aliases" (#733)

Turns out we were doing the wrong thing for the right reason: the
`aliases` here aren't `vk.xml` aliases: they are renames.  When
generating function pointers for extensions, a list of command
_definitions_ is collected, which can only ever be "root" `command`s.
Extensions typically reference stabilized `command`s under an alias with
the vendor tag suffixed, which the `Fn` struct field name is renamed to
using this `aliases` - now replaced with `rename_commands` - list, while
generating the rest of the "function pointer" command bits using the
"root" `command` (as this mostly pertains the parameters and return
type).  With that explanation it becomes clear why
`generate_extension_commands()` was creating an "alias" mapping from
stabilized name to vendor-suffixed extension name, and calls
`generate_function_pointers()` with that mapping - and a list of
stabilized/root `command`s - rather than passing `cmd_aliases` directly.
(This `cmd_aliases` list exists because the rename always happens in the
root `<commands>` element: extensions then `<require>` the aliased
rather than the stabilized name, so the base for this alias is found
first to look up the base command, and then stored in `rename_commands`
to rename it back to the aliased name).

With improved clarity we can now also borrow the name strings rather
than cloning them in many places.
This commit is contained in:
Marijn Suijten 2023-04-05 23:42:21 +02:00 committed by GitHub
parent 77e614d776
commit 5732d977cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -893,7 +893,7 @@ pub type CommandMap<'a> = HashMap<vkxml::Identifier, &'a vk_parse::CommandDefini
fn generate_function_pointers<'a>(
ident: Ident,
commands: &[&'a vk_parse::CommandDefinition],
aliases: &HashMap<String, String>,
rename_commands: &HashMap<&'a str, &'a str>,
fn_cache: &mut HashSet<&'a str>,
) -> TokenStream {
// Commands can have duplicates inside them because they are declared per features. But we only
@ -903,10 +903,10 @@ fn generate_function_pointers<'a>(
.unique_by(|cmd| cmd.proto.name.as_str())
.collect::<Vec<_>>();
struct Command {
struct Command<'a> {
type_needs_defining: bool,
type_name: Ident,
function_name_c: String,
function_name_c: &'a str,
function_name_rust: Ident,
parameters: TokenStream,
parameters_unused: TokenStream,
@ -919,11 +919,10 @@ fn generate_function_pointers<'a>(
let name = &cmd.proto.name;
let type_name = format_ident!("PFN_{}", name);
let function_name_c = if let Some(alias_name) = aliases.get(name) {
alias_name.to_string()
} else {
name.to_string()
};
// We might need to generate a function pointer for an extension, where we are given the original
// `cmd` and a rename back to the extension alias (typically with vendor suffix) in `rename_commands`:
let function_name_c = rename_commands.get(name.as_str()).cloned().unwrap_or(name);
let function_name_rust = format_ident!(
"{}",
function_name_c.strip_prefix("vk").unwrap().to_snake_case()
@ -976,7 +975,7 @@ fn generate_function_pointers<'a>(
})
.collect::<Vec<_>>();
struct CommandToType<'a>(&'a Command);
struct CommandToType<'a>(&'a Command<'a>);
impl<'a> quote::ToTokens for CommandToType<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let type_name = &self.0.type_name;
@ -990,7 +989,7 @@ fn generate_function_pointers<'a>(
}
}
struct CommandToMember<'a>(&'a Command);
struct CommandToMember<'a>(&'a Command<'a>);
impl<'a> quote::ToTokens for CommandToMember<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let type_name = &self.0.type_name;
@ -1006,7 +1005,7 @@ fn generate_function_pointers<'a>(
}
}
struct CommandToLoader<'a>(&'a Command);
struct CommandToLoader<'a>(&'a Command<'a>);
impl<'a> quote::ToTokens for CommandToLoader<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let function_name_rust = &self.0.function_name_rust;
@ -1163,13 +1162,13 @@ pub fn generate_extension_constants<'a>(
}
pub fn generate_extension_commands<'a>(
extension_name: &str,
items: &[vk_parse::ExtensionChild],
items: &'a [vk_parse::ExtensionChild],
cmd_map: &CommandMap<'a>,
cmd_aliases: &HashMap<String, String>,
cmd_aliases: &HashMap<&'a str, &'a str>,
fn_cache: &mut HashSet<&'a str>,
) -> TokenStream {
let mut commands = Vec::new();
let mut aliases = HashMap::new();
let mut rename_commands = HashMap::new();
let names = items
.iter()
.filter_map(get_variant!(vk_parse::ExtensionChild::Require {
@ -1179,14 +1178,18 @@ pub fn generate_extension_commands<'a>(
.filter(|(api, _items)| matches!(api.as_deref(), None | Some(DESIRED_API)))
.flat_map(|(_api, items)| items)
.filter_map(get_variant!(vk_parse::InterfaceItem::Command { name }));
// Collect a subset of `CommandDefinition`s to generate
for name in names {
if let Some(cmd) = cmd_map.get(name).copied() {
commands.push(cmd);
} else if let Some(cmd) = cmd_aliases.get(name) {
aliases.insert(cmd.clone(), name.to_string());
let cmd = cmd_map.get(cmd).copied().unwrap();
commands.push(cmd);
let mut name = name.as_str();
if let Some(&cmd) = cmd_aliases.get(name) {
// This extension is referencing the base command under a different name,
// make sure it is generated with a rename to it.
rename_commands.insert(cmd, name);
name = cmd;
}
commands.push(cmd_map[name]);
}
let ident = format_ident!(
@ -1196,7 +1199,7 @@ pub fn generate_extension_commands<'a>(
.strip_prefix("Vk")
.unwrap()
);
let fp = generate_function_pointers(ident.clone(), &commands, &aliases, fn_cache);
let fp = generate_function_pointers(ident.clone(), &commands, &rename_commands, fn_cache);
let spec_version = items
.iter()
@ -1232,7 +1235,7 @@ pub fn generate_extension<'a>(
cmd_map: &CommandMap<'a>,
const_cache: &mut HashSet<&'a str>,
const_values: &mut BTreeMap<Ident, ConstantTypeInfo>,
cmd_aliases: &HashMap<String, String>,
cmd_aliases: &HashMap<&'a str, &'a str>,
fn_cache: &mut HashSet<&'a str>,
) -> Option<TokenStream> {
let extension_tokens = generate_extension_constants(
@ -2776,14 +2779,14 @@ pub fn write_source_code<P: AsRef<Path>>(vk_headers_dir: &Path, src_dir: P) {
.map(|cmd| (cmd.proto.name.clone(), cmd))
.collect();
let cmd_aliases: HashMap<String, String> = spec2
let cmd_aliases: HashMap<_, _> = spec2
.0
.iter()
.filter_map(get_variant!(vk_parse::RegistryChild::Commands))
.flat_map(|cmds| &cmds.children)
.filter_map(get_variant!(vk_parse::Command::Alias { name, alias }))
.filter(|(name, _alias)| required_commands.contains(name.as_str()))
.map(|(name, alias)| (name.to_string(), alias.to_string()))
.map(|(name, alias)| (name.as_str(), alias.as_str()))
.collect();
let mut fn_cache = HashSet::new();