generator: Generate enums from vk_parse representation (#410)
* generator: Generate enums from vk_parse representation This change prepares for future additions in vk_parse fields ([1]) by converting over the enum generation path from vkxml. Most of the conversion is easy by repurposing the existing `EnumSpec` parsing logic from extension constants for all enumeration variants, with slight modifications to not bail when `extends` is not set which is specific to extension constants. As an (unintended) added bonus this unification of the `EnumSpec` codepath allows aliases (for backwards-compatible names) to be generated as discussed earlier in [2]. [1]: https://github.com/krolli/vk-parse/pull/17 [2]: https://github.com/MaikKlein/ash/pull/384#discussion_r588693967 * generator: Turn "backwards"-mentioning docs into deprecation notices All constant aliases for misspelled items (missing `_BIT` andsoforth) contain the text "backwards compatibility" or "Backwards-compatible alias". * generator: Drop aliases whose name becomes identical after de-mangling * generator: Remove aliases from const_debugs These already have a match against the name they're aliasing, and some of the aliases are "deprecated" (since they're just typo fixups for backwards compatibility).
This commit is contained in:
parent
90b0531474
commit
46ed5158ab
|
@ -496,6 +496,8 @@ impl StencilFaceFlags {
|
|||
pub const BACK: Self = Self(0b10);
|
||||
#[doc = "Front and back faces"]
|
||||
pub const FRONT_AND_BACK: Self = Self(0x0000_0003);
|
||||
#[deprecated = "Alias for backwards compatibility"]
|
||||
pub const STENCIL_FRONT_AND_BACK: Self = Self::FRONT_AND_BACK;
|
||||
}
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
@ -689,6 +691,7 @@ impl ExternalSemaphoreHandleTypeFlags {
|
|||
pub const OPAQUE_WIN32: Self = Self(0b10);
|
||||
pub const OPAQUE_WIN32_KMT: Self = Self(0b100);
|
||||
pub const D3D12_FENCE: Self = Self(0b1000);
|
||||
pub const D3D11_FENCE: Self = Self::D3D12_FENCE;
|
||||
pub const SYNC_FD: Self = Self(0b1_0000);
|
||||
}
|
||||
#[repr(transparent)]
|
||||
|
|
|
@ -1128,6 +1128,8 @@ impl ColorSpaceKHR {
|
|||
}
|
||||
impl ColorSpaceKHR {
|
||||
pub const SRGB_NONLINEAR: Self = Self(0);
|
||||
#[deprecated = "Backwards-compatible alias containing a typo"]
|
||||
pub const COLORSPACE_SRGB_NONLINEAR: Self = Self::SRGB_NONLINEAR;
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
|
@ -1189,9 +1191,13 @@ impl DebugReportObjectTypeEXT {
|
|||
pub const SURFACE_KHR: Self = Self(26);
|
||||
pub const SWAPCHAIN_KHR: Self = Self(27);
|
||||
pub const DEBUG_REPORT_CALLBACK_EXT: Self = Self(28);
|
||||
#[deprecated = "Backwards-compatible alias containing a typo"]
|
||||
pub const DEBUG_REPORT: Self = Self::DEBUG_REPORT_CALLBACK_EXT;
|
||||
pub const DISPLAY_KHR: Self = Self(29);
|
||||
pub const DISPLAY_MODE_KHR: Self = Self(30);
|
||||
pub const VALIDATION_CACHE_EXT: Self = Self(33);
|
||||
#[deprecated = "Backwards-compatible alias containing a typo"]
|
||||
pub const VALIDATION_CACHE: Self = Self::VALIDATION_CACHE_EXT;
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
|
@ -1974,6 +1980,9 @@ impl PerformanceCounterScopeKHR {
|
|||
pub const COMMAND_BUFFER: Self = Self(0);
|
||||
pub const RENDER_PASS: Self = Self(1);
|
||||
pub const COMMAND: Self = Self(2);
|
||||
pub const QUERY_SCOPE_COMMAND_BUFFER: Self = Self::COMMAND_BUFFER;
|
||||
pub const QUERY_SCOPE_RENDER_PASS: Self = Self::RENDER_PASS;
|
||||
pub const QUERY_SCOPE_COMMAND: Self = Self::COMMAND;
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
|
|
|
@ -401,13 +401,16 @@ impl ConstVal {
|
|||
}
|
||||
}
|
||||
pub trait ConstantExt {
|
||||
fn constant(&self) -> Constant;
|
||||
fn constant(&self, enum_name: &str) -> Constant;
|
||||
fn variant_ident(&self, enum_name: &str) -> Ident;
|
||||
fn notation(&self) -> Option<&str>;
|
||||
fn is_alias(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstantExt for vkxml::ExtensionEnum {
|
||||
fn constant(&self) -> Constant {
|
||||
fn constant(&self, _enum_name: &str) -> Constant {
|
||||
Constant::from_extension_enum(self).unwrap()
|
||||
}
|
||||
fn variant_ident(&self, enum_name: &str) -> Ident {
|
||||
|
@ -418,8 +421,25 @@ impl ConstantExt for vkxml::ExtensionEnum {
|
|||
}
|
||||
}
|
||||
|
||||
impl ConstantExt for vk_parse::Enum {
|
||||
fn constant(&self, enum_name: &str) -> Constant {
|
||||
Constant::from_vk_parse_enum_spec(&self.spec, Some(enum_name), None)
|
||||
.unwrap()
|
||||
.0
|
||||
}
|
||||
fn variant_ident(&self, enum_name: &str) -> Ident {
|
||||
variant_ident(enum_name, &self.name)
|
||||
}
|
||||
fn notation(&self) -> Option<&str> {
|
||||
self.comment.as_deref()
|
||||
}
|
||||
fn is_alias(&self) -> bool {
|
||||
matches!(self.spec, vk_parse::EnumSpec::Alias { .. })
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstantExt for vkxml::Constant {
|
||||
fn constant(&self) -> Constant {
|
||||
fn constant(&self, _enum_name: &str) -> Constant {
|
||||
Constant::from_constant(self)
|
||||
}
|
||||
fn variant_ident(&self, enum_name: &str) -> Ident {
|
||||
|
@ -534,6 +554,53 @@ impl Constant {
|
|||
.map(|e| Constant::CExpr(e.clone()));
|
||||
number.or(hex).or(bitpos).or(expr).expect("")
|
||||
}
|
||||
|
||||
/// Returns (Constant, optional base type, is_alias)
|
||||
pub fn from_vk_parse_enum_spec(
|
||||
spec: &vk_parse::EnumSpec,
|
||||
enum_name: Option<&str>,
|
||||
extension_number: Option<i64>,
|
||||
) -> Option<(Self, Option<String>, bool)> {
|
||||
use vk_parse::EnumSpec;
|
||||
|
||||
match spec {
|
||||
EnumSpec::Bitpos { bitpos, extends } => {
|
||||
Some((Self::BitPos(*bitpos as u32), extends.clone(), false))
|
||||
}
|
||||
EnumSpec::Offset {
|
||||
offset,
|
||||
extends,
|
||||
extnumber,
|
||||
dir: positive,
|
||||
} => {
|
||||
let ext_base = 1_000_000_000;
|
||||
let ext_block_size = 1000;
|
||||
let extnumber = extnumber
|
||||
.or(extension_number)
|
||||
.expect("Need an extension number");
|
||||
let value = ext_base + (extnumber - 1) * ext_block_size + offset;
|
||||
let value = if *positive { value } else { -value };
|
||||
Some((Self::Number(value as i32), Some(extends.clone()), false))
|
||||
}
|
||||
EnumSpec::Value { value, extends } => {
|
||||
let value = value
|
||||
.strip_prefix("0x")
|
||||
.map(|hex| Self::Hex(hex.to_owned()))
|
||||
.or_else(|| value.parse::<i32>().ok().map(Self::Number))?;
|
||||
Some((value, extends.clone(), false))
|
||||
}
|
||||
EnumSpec::Alias { alias, extends } => {
|
||||
let base_type = extends.as_deref().or(enum_name)?;
|
||||
let key = variant_ident(base_type, &alias);
|
||||
if key == "DISPATCH_BASE" {
|
||||
None
|
||||
} else {
|
||||
Some((Self::Alias(key), Some(base_type.to_owned()), true))
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FeatureExt {
|
||||
|
@ -1007,7 +1074,7 @@ pub struct ExtensionConstant<'a> {
|
|||
pub constant: Constant,
|
||||
}
|
||||
impl<'a> ConstantExt for ExtensionConstant<'a> {
|
||||
fn constant(&self) -> Constant {
|
||||
fn constant(&self, _enum_name: &str) -> Constant {
|
||||
self.constant.clone()
|
||||
}
|
||||
fn variant_ident(&self, enum_name: &str) -> Ident {
|
||||
|
@ -1025,7 +1092,6 @@ pub fn generate_extension_constants<'a>(
|
|||
const_cache: &mut HashSet<&'a str, impl BuildHasher>,
|
||||
const_values: &mut BTreeMap<Ident, Vec<ConstantMatchInfo>>,
|
||||
) -> TokenStream {
|
||||
use vk_parse::EnumSpec;
|
||||
let items = extension_items
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
|
@ -1034,52 +1100,16 @@ pub fn generate_extension_constants<'a>(
|
|||
})
|
||||
.flat_map(|iter| iter);
|
||||
let enum_tokens = items.filter_map(|item| match item {
|
||||
vk_parse::InterfaceItem::Enum(_enum) => {
|
||||
if const_cache.contains(_enum.name.as_str()) {
|
||||
vk_parse::InterfaceItem::Enum(enum_) => {
|
||||
if const_cache.contains(enum_.name.as_str()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (constant, extends, is_alias) = match &_enum.spec {
|
||||
EnumSpec::Bitpos { bitpos, extends } => {
|
||||
Some((Constant::BitPos(*bitpos as u32), extends.clone(), false))
|
||||
}
|
||||
EnumSpec::Offset {
|
||||
offset,
|
||||
extends,
|
||||
extnumber,
|
||||
dir: positive,
|
||||
} => {
|
||||
let ext_base = 1_000_000_000;
|
||||
let ext_block_size = 1000;
|
||||
let extnumber = extnumber.unwrap_or_else(|| extension_number);
|
||||
let value = ext_base + (extnumber - 1) * ext_block_size + offset;
|
||||
let value = if *positive { value } else { -value };
|
||||
Some((Constant::Number(value as i32), Some(extends.clone()), false))
|
||||
}
|
||||
EnumSpec::Value { value, extends } => {
|
||||
if let (Some(extends), Ok(value)) = (extends, value.parse::<i32>()) {
|
||||
Some((Constant::Number(value), Some(extends.clone()), false))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
EnumSpec::Alias { alias, extends } => {
|
||||
if let Some(extends) = extends {
|
||||
let key = variant_ident(&extends, &alias);
|
||||
if key == "DISPATCH_BASE" {
|
||||
None
|
||||
} else {
|
||||
Some((Constant::Alias(key), Some(extends.clone()), true))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}?;
|
||||
let (constant, extends, is_alias) =
|
||||
Constant::from_vk_parse_enum_spec(&enum_.spec, None, Some(extension_number))?;
|
||||
let extends = extends?;
|
||||
let ext_constant = ExtensionConstant {
|
||||
name: &_enum.name,
|
||||
name: &enum_.name,
|
||||
constant,
|
||||
};
|
||||
let ident = name_to_tokens(&extends);
|
||||
|
@ -1097,7 +1127,7 @@ pub fn generate_extension_constants<'a>(
|
|||
#impl_block
|
||||
};
|
||||
|
||||
const_cache.insert(_enum.name.as_str());
|
||||
const_cache.insert(enum_.name.as_str());
|
||||
Some(q)
|
||||
}
|
||||
_ => None,
|
||||
|
@ -1334,7 +1364,7 @@ pub fn bitflags_impl_block(
|
|||
.iter()
|
||||
.map(|constant| {
|
||||
let variant_ident = constant.variant_ident(enum_name);
|
||||
let constant = constant.constant();
|
||||
let constant = constant.constant(enum_name);
|
||||
let tokens = if let Constant::Alias(_) = &constant {
|
||||
quote!(#constant)
|
||||
} else {
|
||||
|
@ -1346,8 +1376,10 @@ pub fn bitflags_impl_block(
|
|||
|
||||
let notations = constants.iter().map(|constant| {
|
||||
constant.notation().map(|n| {
|
||||
quote! {
|
||||
#[doc = #n]
|
||||
if n.to_lowercase().contains("backwards") {
|
||||
quote!(#[deprecated = #n])
|
||||
} else {
|
||||
quote!(#[doc = #n])
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -1370,39 +1402,52 @@ pub fn bitflags_impl_block(
|
|||
}
|
||||
|
||||
pub fn generate_enum<'a>(
|
||||
_enum: &'a vkxml::Enumeration,
|
||||
enum_: &'a vk_parse::Enums,
|
||||
const_cache: &mut HashSet<&'a str, impl BuildHasher>,
|
||||
const_values: &mut BTreeMap<Ident, Vec<ConstantMatchInfo>>,
|
||||
bitflags_cache: &mut HashSet<Ident, impl BuildHasher>,
|
||||
) -> EnumType {
|
||||
let name = &_enum.name[2..];
|
||||
let _name = name.replace("FlagBits", "Flags");
|
||||
let name = enum_.name.as_ref().unwrap();
|
||||
let clean_name = name.strip_prefix("Vk").unwrap();
|
||||
let _name = clean_name.replace("FlagBits", "Flags");
|
||||
let ident = format_ident!("{}", _name.as_str());
|
||||
let constants: Vec<_> = _enum
|
||||
.elements
|
||||
let constants = enum_
|
||||
.children
|
||||
.iter()
|
||||
.filter_map(|elem| match *elem {
|
||||
vkxml::EnumerationElement::Enum(ref constant) => Some(constant),
|
||||
vk_parse::EnumsChild::Enum(ref constant) => Some(constant),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|constant| match &constant.spec {
|
||||
vk_parse::EnumSpec::Alias { alias, .. } => {
|
||||
// Remove any alias whose name is identical after name de-mangling. For example
|
||||
// the XML contains compatibility aliases for variants without _BIT postfix
|
||||
// which are removed by the generator anyway, after which they become identical.
|
||||
let alias_name = constant.variant_ident(name);
|
||||
let aliases_to = variant_ident(name, alias);
|
||||
alias_name != aliases_to
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let mut values = Vec::with_capacity(constants.len());
|
||||
for constant in &constants {
|
||||
const_cache.insert(constant.name.as_str());
|
||||
values.push(ConstantMatchInfo {
|
||||
ident: constant.variant_ident(&_enum.name),
|
||||
is_alias: false,
|
||||
ident: constant.variant_ident(name),
|
||||
is_alias: constant.is_alias(),
|
||||
});
|
||||
}
|
||||
const_values.insert(ident.clone(), values);
|
||||
|
||||
let khronos_link = khronos_link(&_enum.name);
|
||||
let khronos_link = khronos_link(name);
|
||||
|
||||
if name.contains("Bit") {
|
||||
if clean_name.contains("Bit") {
|
||||
let ident = format_ident!("{}", _name.as_str());
|
||||
let all_bits = constants
|
||||
.iter()
|
||||
.filter_map(|constant| Constant::from_constant(constant).value())
|
||||
.filter_map(|constant| constant.constant(name).value())
|
||||
.fold(0, |acc, next| acc | next.bits());
|
||||
let bit_string = format!("{:b}", all_bits);
|
||||
let bit_string = interleave_number('_', 4, &bit_string);
|
||||
|
@ -1411,7 +1456,7 @@ pub fn generate_enum<'a>(
|
|||
if bitflags_cache.contains(&ident) {
|
||||
EnumType::Bitflags(quote! {})
|
||||
} else {
|
||||
let impl_bitflags = bitflags_impl_block(ident.clone(), &_enum.name, &constants);
|
||||
let impl_bitflags = bitflags_impl_block(ident.clone(), name, &constants);
|
||||
bitflags_cache.insert(ident.clone());
|
||||
let q = quote! {
|
||||
#[repr(transparent)]
|
||||
|
@ -1426,11 +1471,11 @@ pub fn generate_enum<'a>(
|
|||
} else {
|
||||
let (struct_attribute, special_quote) = match _name.as_str() {
|
||||
//"StructureType" => generate_structure_type(&_name, _enum, create_info_constants),
|
||||
"Result" => (quote!(#[must_use]), generate_result(ident.clone(), _enum)),
|
||||
"Result" => (quote!(#[must_use]), generate_result(ident.clone(), enum_)),
|
||||
_ => (quote!(), quote!()),
|
||||
};
|
||||
|
||||
let impl_block = bitflags_impl_block(ident.clone(), &_enum.name, &constants);
|
||||
let impl_block = bitflags_impl_block(ident.clone(), name, &constants);
|
||||
let enum_quote = quote! {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
|
@ -1452,19 +1497,19 @@ pub fn generate_enum<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn generate_result(ident: Ident, _enum: &vkxml::Enumeration) -> TokenStream {
|
||||
let notation = _enum.elements.iter().filter_map(|elem| {
|
||||
pub fn generate_result(ident: Ident, enum_: &vk_parse::Enums) -> TokenStream {
|
||||
let notation = enum_.children.iter().filter_map(|elem| {
|
||||
let (variant_name, notation) = match *elem {
|
||||
vkxml::EnumerationElement::Enum(ref constant) => (
|
||||
vk_parse::EnumsChild::Enum(ref constant) => (
|
||||
constant.name.as_str(),
|
||||
constant.notation.as_deref().unwrap_or(""),
|
||||
constant.comment.as_deref().unwrap_or(""),
|
||||
),
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let variant_ident = variant_ident(&_enum.name, variant_name);
|
||||
let variant_ident = variant_ident(&enum_.name.as_ref().unwrap(), variant_name);
|
||||
Some(quote! {
|
||||
#ident::#variant_ident => Some(#notation)
|
||||
})
|
||||
|
@ -2461,21 +2506,6 @@ pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
|
|||
.flat_map(|definitions| definitions.elements.iter())
|
||||
.collect();
|
||||
|
||||
let enums: Vec<&vkxml::Enumeration> = spec
|
||||
.elements
|
||||
.iter()
|
||||
.filter_map(|elem| match elem {
|
||||
vkxml::RegistryElement::Enums(ref enums) => Some(enums),
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|enums| {
|
||||
enums.elements.iter().filter_map(|_enum| match *_enum {
|
||||
vkxml::EnumsElement::Enumeration(ref e) => Some(e),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let constants: Vec<&vkxml::Constant> = spec
|
||||
.elements
|
||||
.iter()
|
||||
|
@ -2492,8 +2522,13 @@ pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
|
|||
|
||||
let mut const_values: BTreeMap<Ident, Vec<ConstantMatchInfo>> = BTreeMap::new();
|
||||
|
||||
let (enum_code, bitflags_code) = enums
|
||||
.into_iter()
|
||||
let (enum_code, bitflags_code) = spec2
|
||||
.0
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
vk_parse::RegistryChild::Enums(ref enums) if enums.kind.is_some() => Some(enums),
|
||||
_ => None,
|
||||
})
|
||||
.map(|e| generate_enum(e, &mut const_cache, &mut const_values, &mut bitflags_cache))
|
||||
.fold((Vec::new(), Vec::new()), |mut acc, elem| {
|
||||
match elem {
|
||||
|
|
Loading…
Reference in a new issue