Fix incorrect generation of commands with aliases (#279)

* Fix incorrect generation of commands with aliases

* Use alias name instead of the actual cmd name
This commit is contained in:
Maik Klein 2020-03-22 13:56:01 +01:00 committed by GitHub
parent c32f0dd739
commit af6acb93e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 2203 additions and 304 deletions

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@ vkxml = "0.3"
nom = "4.0"
heck = "0.3"
proc-macro2 = "0.2"
itertools = "0.7"
itertools = "0.9"
[dependencies.quote]
version = "0.4.2"

View file

@ -723,10 +723,26 @@ pub type CommandMap<'a> = HashMap<vkxml::Identifier, &'a vkxml::Command>;
fn generate_function_pointers<'a>(
ident: Ident,
commands: &[&'a vkxml::Command],
aliases: &HashMap<String, String, impl BuildHasher>,
fn_cache: &mut HashSet<&'a str, impl BuildHasher>,
) -> quote::Tokens {
// We filter commands so that we don't have duplicates
let commands: Vec<_> = commands
// Commands can have duplicates inside them because they are declared per features. But we only
// really want to generate one function pointer.
let commands = {
let mut cache = HashSet::new();
let mut cmd_vec: Vec<&vkxml::Command> = Vec::new();
for cmd in commands {
let name = cmd.name.as_str();
if !cache.contains(name) {
cmd_vec.push(cmd);
cache.insert(name);
}
}
cmd_vec
};
// PFN function pointers are global and can not have duplicates. This can happen because there
// are aliases to commands
let commands_pfn: Vec<_> = commands
.iter()
.filter(|cmd| {
let ident = cmd.name.as_str();
@ -738,14 +754,29 @@ fn generate_function_pointers<'a>(
}
})
.collect();
let names: Vec<_> = commands.iter().map(|cmd| cmd.command_ident()).collect();
let function_name_raw = |name: &str| -> String {
if let Some(alias_name) = aliases.get(name) {
alias_name.to_string()
} else {
name.to_string()
}
};
let function_name = |name: &str| -> Ident {
let fn_name = function_name_raw(&name);
Ident::from(fn_name[2..].to_snake_case().as_str())
};
let names: Vec<_> = commands
.iter()
.map(|cmd| function_name(&cmd.name))
.collect();
let names_ref = &names;
let names_ref1 = &names;
let names_ref2 = &names;
let names_ref3 = &names;
let raw_names: Vec<_> = commands
.iter()
.map(|cmd| Ident::from(cmd.name.as_str()))
.map(|cmd| Ident::from(function_name_raw(cmd.name.as_str()).as_str()))
.collect();
let raw_names_ref = &raw_names;
let names_left = &names;
@ -809,7 +840,7 @@ fn generate_function_pointers<'a>(
.collect();
let return_types_ref = &return_types;
let pfn_names: Vec<_> = commands
let pfn_names: Vec<_> = commands_pfn
.iter()
.map(|cmd| Ident::from(format!("PFN_{}", cmd.name.as_str())))
.collect();
@ -985,24 +1016,38 @@ pub fn generate_extension_commands<'a>(
extension_name: &str,
items: &[vk_parse::ExtensionChild],
cmd_map: &CommandMap<'a>,
cmd_aliases: &HashMap<String, String, impl BuildHasher>,
fn_cache: &mut HashSet<&'a str, impl BuildHasher>,
) -> Tokens {
let commands = items
let mut commands = Vec::new();
let mut aliases = HashMap::new();
items
.iter()
.filter_map(|ext_item| match ext_item {
vk_parse::ExtensionChild::Require { items, .. } => {
Some(items.iter().filter_map(|item| match item {
vk_parse::InterfaceItem::Command { ref name, .. } => cmd_map.get(name).copied(),
vk_parse::InterfaceItem::Command { ref name, .. } => Some(name),
_ => None,
}))
}
_ => None,
})
.flat_map(|iter| iter)
.collect_vec();
.flatten()
.for_each(|name| {
if let Some(cmd) = cmd_map.get(name).copied() {
commands.push(cmd);
} else if let Some(cmd) = cmd_aliases
.get(name)
.and_then(|alias_name| cmd_map.get(alias_name).copied())
{
aliases.insert(cmd.name.clone(), name.to_string());
commands.push(cmd);
}
});
let name = format!("{}Fn", extension_name.to_camel_case());
let ident = Ident::from(&name[2..]);
let fp = generate_function_pointers(ident, &commands, fn_cache);
let fp = generate_function_pointers(ident, &commands, &aliases, fn_cache);
let byte_name = format!("{}\0", extension_name);
let byte_name_ident =
@ -1024,6 +1069,7 @@ pub fn generate_extension<'a>(
cmd_map: &CommandMap<'a>,
const_cache: &mut HashSet<&'a str, impl BuildHasher>,
const_values: &mut BTreeMap<Ident, Vec<Ident>>,
cmd_aliases: &HashMap<String, String, impl BuildHasher>,
fn_cache: &mut HashSet<&'a str, impl BuildHasher>,
) -> Option<quote::Tokens> {
// Okay this is a little bit odd. We need to generate all extensions, even disabled ones,
@ -1039,7 +1085,13 @@ pub fn generate_extension<'a>(
const_cache,
const_values,
);
let fp = generate_extension_commands(&extension.name, &extension.children, cmd_map, fn_cache);
let fp = generate_extension_commands(
&extension.name,
&extension.children,
cmd_map,
cmd_aliases,
fn_cache,
);
let q = quote! {
#fp
#extension_tokens
@ -1972,23 +2024,31 @@ pub fn generate_feature<'a>(
);
let version = feature.version_string();
let static_fn = if feature.is_version(1, 0) {
generate_function_pointers(Ident::from("StaticFn"), &static_commands, fn_cache)
generate_function_pointers(
Ident::from("StaticFn"),
&static_commands,
&HashMap::new(),
fn_cache,
)
} else {
quote! {}
};
let entry = generate_function_pointers(
Ident::from(format!("EntryFnV{}", version).as_str()),
&entry_commands,
&HashMap::new(),
fn_cache,
);
let instance = generate_function_pointers(
Ident::from(format!("InstanceFnV{}", version).as_str()),
&instance_commands,
&HashMap::new(),
fn_cache,
);
let device = generate_function_pointers(
Ident::from(format!("DeviceFnV{}", version).as_str()),
&device_commands,
&HashMap::new(),
fn_cache,
);
quote! {
@ -2154,6 +2214,24 @@ pub fn write_source_code(path: &Path) {
.collect();
let spec = vk_parse::parse_file_as_vkxml(path);
let cmd_aliases: HashMap<String, String> = spec2
.0
.iter()
.filter_map(|item| match item {
vk_parse::RegistryChild::Commands(cmds) => {
let cmd_tuple_iter = cmds.children.iter().filter_map(|cmd| match cmd {
vk_parse::Command::Alias { name, alias } => {
Some((name.to_string(), alias.to_string()))
}
_ => None,
});
Some(cmd_tuple_iter)
}
_ => None,
})
.flatten()
.collect();
let commands: HashMap<vkxml::Identifier, &vkxml::Command> = spec
.elements
.iter()
@ -2238,6 +2316,7 @@ pub fn write_source_code(path: &Path) {
&commands,
&mut const_cache,
&mut const_values,
&cmd_aliases,
&mut fn_cache,
)
})