generator: Support nested arrays in builders without hardcoding (#666)

Prepare the generator for more struct fields that have nested "dynamic
arrays" with a hardcoded size of `1` (effectively arrays with pointers
to single objects) in `vk.xml`s `len` attribute.  These structs are
introduced by `VK_EXT_opacity_micromap` in 1.3.230.
This commit is contained in:
Marijn Suijten 2022-10-03 12:00:54 +02:00
parent c2f21d2949
commit 812b9bb214
2 changed files with 40 additions and 27 deletions

View file

@ -47837,10 +47837,10 @@ impl<'a> AccelerationStructureBuildGeometryInfoKHRBuilder<'a> {
#[inline] #[inline]
pub fn geometries_ptrs( pub fn geometries_ptrs(
mut self, mut self,
geometries: &'a [&'a AccelerationStructureGeometryKHR], geometries_ptrs: &'a [&'a AccelerationStructureGeometryKHR],
) -> Self { ) -> Self {
self.inner.geometry_count = geometries.len() as _; self.inner.geometry_count = geometries_ptrs.len() as _;
self.inner.pp_geometries = geometries.as_ptr() as *const *const _; self.inner.pp_geometries = geometries_ptrs.as_ptr() as *const *const _;
self self
} }
#[inline] #[inline]

View file

@ -487,11 +487,15 @@ pub trait FieldExt {
fn param_ident(&self) -> Ident; fn param_ident(&self) -> Ident;
/// The inner type of this field, with one level of pointers removed /// The inner type of this field, with one level of pointers removed
fn inner_type_tokens(&self) -> TokenStream; fn inner_type_tokens(
&self,
lifetime: Option<TokenStream>,
inner_length: Option<usize>,
) -> TokenStream;
/// Returns reference-types wrapped in their safe variant. (Dynamic) arrays become /// Returns reference-types wrapped in their safe variant. (Dynamic) arrays become
/// slices, pointers become Rust references. /// slices, pointers become Rust references.
fn safe_type_tokens(&self, lifetime: TokenStream) -> TokenStream; fn safe_type_tokens(&self, lifetime: TokenStream, inner_length: Option<usize>) -> TokenStream;
/// Returns the basetype ident and removes the 'Vk' prefix. When `is_ffi_param` is `true` /// Returns the basetype ident and removes the 'Vk' prefix. When `is_ffi_param` is `true`
/// array types (e.g. `[f32; 3]`) will be converted to pointer types (e.g. `&[f32; 3]`), /// array types (e.g. `[f32; 3]`) will be converted to pointer types (e.g. `&[f32; 3]`),
@ -640,24 +644,34 @@ impl FieldExt for vkxml::Field {
format_ident!("{}", name_corrected.to_snake_case().as_str()) format_ident!("{}", name_corrected.to_snake_case().as_str())
} }
fn inner_type_tokens(&self) -> TokenStream { fn inner_type_tokens(
&self,
lifetime: Option<TokenStream>,
inner_length: Option<usize>,
) -> TokenStream {
assert!(!self.is_void()); assert!(!self.is_void());
let ty = name_to_tokens(&self.basetype); let ty = name_to_tokens(&self.basetype);
let (const_, borrow) = match (lifetime, inner_length) {
// If the nested "dynamic array" has length 1, it's just a pointer which we convert to a safe borrow for convenience
(Some(lifetime), Some(1)) => (quote!(), quote!(&#lifetime)),
_ => (quote!(const), quote!(*)),
};
match self.reference { match self.reference {
Some(vkxml::ReferenceType::PointerToPointer) => quote!(*mut #ty), Some(vkxml::ReferenceType::PointerToPointer) => quote!(#borrow mut #ty),
Some(vkxml::ReferenceType::PointerToConstPointer) => quote!(*const #ty), Some(vkxml::ReferenceType::PointerToConstPointer) => quote!(#borrow #const_ #ty),
_ => quote!(#ty), _ => quote!(#ty),
} }
} }
fn safe_type_tokens(&self, lifetime: TokenStream) -> TokenStream { fn safe_type_tokens(&self, lifetime: TokenStream, inner_length: Option<usize>) -> TokenStream {
assert!(!self.is_void()); assert!(!self.is_void());
match self.array { match self.array {
// The outer type fn type_tokens() returns is [], which fits our "safe" prescription // The outer type fn type_tokens() returns is [], which fits our "safe" prescription
Some(vkxml::ArrayType::Static) => self.type_tokens(false), Some(vkxml::ArrayType::Static) => self.type_tokens(false),
Some(vkxml::ArrayType::Dynamic) => { Some(vkxml::ArrayType::Dynamic) => {
let ty = self.inner_type_tokens(); let ty = self.inner_type_tokens(Some(lifetime), inner_length);
quote!([#ty]) quote!([#ty])
} }
None => { None => {
@ -1585,7 +1599,7 @@ pub fn derive_setters(
let setters = members.clone().filter_map(|field| { let setters = members.clone().filter_map(|field| {
let param_ident = field.param_ident(); let param_ident = field.param_ident();
let param_ty_tokens = field.safe_type_tokens(quote!('a)); let param_ty_tokens = field.safe_type_tokens(quote!('a), None);
let param_ident_string = param_ident.to_string(); let param_ident_string = param_ident.to_string();
if param_ident_string == "s_type" || param_ident_string == "p_next" { if param_ident_string == "s_type" || param_ident_string == "p_next" {
@ -1596,7 +1610,7 @@ pub fn derive_setters(
.strip_prefix("p_") .strip_prefix("p_")
.or_else(|| param_ident_string.strip_prefix("pp_")) .or_else(|| param_ident_string.strip_prefix("pp_"))
.unwrap_or(&param_ident_string); .unwrap_or(&param_ident_string);
let param_ident_short = format_ident!("{}", &param_ident_short); let mut param_ident_short = format_ident!("{}", param_ident_short);
if let Some(name) = field.name.as_ref() { if let Some(name) = field.name.as_ref() {
// Filter // Filter
@ -1634,17 +1648,6 @@ pub fn derive_setters(
} }
}); });
} }
if name == "ppGeometries" {
return Some(quote!{
#[inline]
pub fn geometries_ptrs(mut self, geometries: &'a [&'a AccelerationStructureGeometryKHR]) -> Self {
self.inner.geometry_count = geometries.len() as _;
self.inner.pp_geometries = geometries.as_ptr() as *const *const _;
self
}
});
}
} }
// TODO: Improve in future when https://github.com/rust-lang/rust/issues/53667 is merged id:6 // TODO: Improve in future when https://github.com/rust-lang/rust/issues/53667 is merged id:6
@ -1663,7 +1666,7 @@ pub fn derive_setters(
if matches!(field.array, Some(vkxml::ArrayType::Dynamic)) { if matches!(field.array, Some(vkxml::ArrayType::Dynamic)) {
if let Some(ref array_size) = field.size { if let Some(ref array_size) = field.size {
let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a)); let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a), None);
let mut ptr = if field.is_const { let mut ptr = if field.is_const {
quote!(.as_ptr()) quote!(.as_ptr())
@ -1683,20 +1686,30 @@ pub fn derive_setters(
// this is a pointer to a piece of memory with statically known size. // this is a pointer to a piece of memory with statically known size.
let array_size = field.c_size.as_ref().unwrap(); let array_size = field.c_size.as_ref().unwrap();
let c_size = convert_c_expression(array_size, &BTreeMap::new()); let c_size = convert_c_expression(array_size, &BTreeMap::new());
let inner_type = field.inner_type_tokens(); let inner_type = field.inner_type_tokens(None, None);
slice_param_ty_tokens = quote!([#inner_type; #c_size]); slice_param_ty_tokens = quote!([#inner_type; #c_size]);
ptr = quote!(); ptr = quote!();
quote!() quote!()
} else { } else {
// Deal with a "special" 2D dynamic array with an inner size of 1 (effectively an array containing pointers to single objects)
let array_size = if let Some(array_size) = array_size.strip_suffix(",1") {
param_ident_short = format_ident!("{}_ptrs", param_ident_short);
slice_param_ty_tokens = field.safe_type_tokens(quote!('a), Some(1));
ptr = quote!(#ptr as *const *const _);
array_size
} else {
array_size
};
let array_size_ident = format_ident!("{}", array_size.to_snake_case().as_str()); let array_size_ident = format_ident!("{}", array_size.to_snake_case().as_str());
let size_field = members.clone().find(|m| m.name.as_ref() == Some(array_size)).unwrap(); let size_field = members.clone().find(|m| m.name.as_deref() == Some(array_size)).unwrap();
let cast = if size_field.basetype == "size_t" { let cast = if size_field.basetype == "size_t" {
quote!() quote!()
}else{ } else {
quote!(as _) quote!(as _)
}; };