Init generator
This commit is contained in:
parent
700f4430be
commit
be08103d1d
6 changed files with 8633 additions and 0 deletions
10
generator/Cargo.toml
Normal file
10
generator/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Maik Klein <maikklein@googlemail.com>"]
|
||||
|
||||
[dependencies]
|
||||
vkxml = {git = "https://github.com/maikklein/vkxml"}
|
||||
quote = "0.4.2"
|
||||
syn = "0.12.14"
|
||||
heck = "0.3.0"
|
1
generator/New-Vulkan-XML-Format
Submodule
1
generator/New-Vulkan-XML-Format
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 460746da3c2dfd1d247b12a619f47f2078a4374b
|
1
generator/Vulkan-Docs
Submodule
1
generator/Vulkan-Docs
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit ce60b9c88745ecded74296dfbe69dae7c1fb2e62
|
36
generator/src/bin/generator.rs
Normal file
36
generator/src/bin/generator.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
extern crate generator;
|
||||
use std::fs::File;
|
||||
use generator::*;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let file = File::open("vk_new.xml").expect("vk");
|
||||
let spec = vkxml::Registry::from_file(file).expect("");
|
||||
|
||||
let commands: HashMap<vkxml::Identifier, &vkxml::Command> = spec.elements
|
||||
.iter()
|
||||
.filter_map(|elem| match elem {
|
||||
&vkxml::RegistryElement::Commands(ref cmds) => Some(cmds),
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|cmds| cmds.elements.iter().map(|cmd| (cmd.name.clone(), cmd)))
|
||||
.collect();
|
||||
|
||||
let features: Vec<&vkxml::Feature> = spec.elements
|
||||
.iter()
|
||||
.filter_map(|elem| match elem {
|
||||
&vkxml::RegistryElement::Features(ref features) => Some(features),
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|features| features.elements.iter().map(|feature| feature))
|
||||
.collect();
|
||||
|
||||
let source_code: Vec<_> = features.iter().map(|feature| gen_load(feature, &commands)).collect();
|
||||
let mut file = File::create("vk_test.rs").expect("vk");
|
||||
for source_code in &source_code {
|
||||
write!(&mut file, "{}", source_code);
|
||||
}
|
||||
|
||||
|
||||
}
|
126
generator/src/lib.rs
Normal file
126
generator/src/lib.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
// extern crate serde;
|
||||
// #[macro_use]
|
||||
// extern crate serde_derive;
|
||||
extern crate heck;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
extern crate syn;
|
||||
pub extern crate vkxml;
|
||||
|
||||
use heck::SnakeCase;
|
||||
|
||||
use syn::Ident;
|
||||
|
||||
pub trait CommandExt {
|
||||
/// Returns the ident in snake_case and without the 'vk' prefix.
|
||||
fn is_device_command(&self) -> bool;
|
||||
///
|
||||
/// Returns true if the command is a device level command. This is indicated by
|
||||
/// the type of the first parameter.
|
||||
fn command_ident(&self) -> Ident;
|
||||
}
|
||||
|
||||
impl CommandExt for vkxml::Command {
|
||||
fn command_ident(&self) -> Ident {
|
||||
Ident::from(self.name[2..].to_snake_case().as_str())
|
||||
}
|
||||
|
||||
fn is_device_command(&self) -> bool {
|
||||
self.param
|
||||
.iter()
|
||||
.nth(0)
|
||||
.map(|field| match field.basetype.as_str() {
|
||||
"VkDevice" | "VkCommandBuffer" | "VkQueue" => true,
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FieldExt {
|
||||
/// Returns the name of the paramter that doesn't clash with Rusts resevered
|
||||
/// keywords
|
||||
fn param_ident(&self) -> Ident;
|
||||
|
||||
/// Returns the basetype ident and removes the 'Vk' prefix
|
||||
fn type_ident(&self) -> Ident;
|
||||
}
|
||||
|
||||
impl FieldExt for vkxml::Field {
|
||||
fn param_ident(&self) -> Ident {
|
||||
let name = self.name.as_ref().map(|s| s.as_str()).unwrap_or("field");
|
||||
let name_corrected = match name {
|
||||
"type" => "ty",
|
||||
_ => name,
|
||||
};
|
||||
Ident::from(name_corrected.to_snake_case().as_str())
|
||||
}
|
||||
|
||||
fn type_ident(&self) -> Ident {
|
||||
let prefix = &self.basetype[0..2];
|
||||
if prefix == "Vk" {
|
||||
Ident::from(&self.basetype[2..])
|
||||
} else {
|
||||
Ident::from(&self.basetype[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
use std::collections::HashMap;
|
||||
pub type CommandMap<'a> = HashMap<vkxml::Identifier, &'a vkxml::Command>;
|
||||
pub fn gen_load(feature: &vkxml::Feature, commands: &CommandMap) -> quote::Tokens {
|
||||
let (device_commands, instance_commands) = feature
|
||||
.elements
|
||||
.iter()
|
||||
.flat_map(|feature| {
|
||||
if let &vkxml::FeatureElement::Require(ref spec) = feature {
|
||||
spec.elements
|
||||
.iter()
|
||||
.filter_map(|feature_spec| {
|
||||
if let &vkxml::FeatureReference::CommandReference(ref cmd_ref) =
|
||||
feature_spec
|
||||
{
|
||||
Some(cmd_ref)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
})
|
||||
.filter_map(|cmd_ref| commands.get(&cmd_ref.name))
|
||||
.fold((Vec::new(), Vec::new()), |mut acc, &cmd_ref| {
|
||||
let basetype = cmd_ref.param[0].basetype.as_str();
|
||||
match basetype {
|
||||
"VkDevice" | "VkCommandBuffer" | "VkQueue" => acc.0.push(cmd_ref),
|
||||
_ => acc.1.push(cmd_ref),
|
||||
};
|
||||
acc
|
||||
});
|
||||
let name = Ident::from("Test");
|
||||
let function_pointers: Vec<_> = instance_commands
|
||||
.iter()
|
||||
.map(|cmd| {
|
||||
let fn_name_raw = cmd.name.as_str();
|
||||
let fn_name_snake = cmd.command_ident();
|
||||
let params: Vec<_> = cmd.param
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let name = field.param_ident();
|
||||
let ty = field.type_ident();
|
||||
quote!{#name: vk::#ty}
|
||||
})
|
||||
.collect();
|
||||
let return_ty = cmd.return_type.type_ident();
|
||||
quote!{
|
||||
#fn_name_snake: extern "system" fn(#(#params,)*) -> vk::#return_ty
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
quote!{
|
||||
pub struct #name {
|
||||
#(#function_pointers,)*
|
||||
}
|
||||
}
|
||||
}
|
8459
generator/vk.xml
Normal file
8459
generator/vk.xml
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue