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