generator: Turn c_void-returning functions into Rust () (#362)

`c_void` is not the same as Rust's void type, `()`, making function
pointers like `PFN_vkFreeFunction` pretty much impossible to implement
without casting. Instead of just turning this into `-> ()`, remove the
return type altogether, and add some asserts to prevent types of this
kind from being accidentally generated.
This commit is contained in:
Marijn Suijten 2021-02-28 16:50:24 +01:00 committed by GitHub
parent dd2849450f
commit e8b369db7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 962 additions and 1085 deletions

View file

@ -383,7 +383,7 @@ pub type PFN_vkInternalAllocationNotification = Option<
size: usize, size: usize,
allocation_type: InternalAllocationType, allocation_type: InternalAllocationType,
allocation_scope: SystemAllocationScope, allocation_scope: SystemAllocationScope,
) -> c_void, ),
>; >;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkInternalFreeNotification.html>"] #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkInternalFreeNotification.html>"]
@ -393,7 +393,7 @@ pub type PFN_vkInternalFreeNotification = Option<
size: usize, size: usize,
allocation_type: InternalAllocationType, allocation_type: InternalAllocationType,
allocation_scope: SystemAllocationScope, allocation_scope: SystemAllocationScope,
) -> c_void, ),
>; >;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkReallocationFunction.html>"] #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkReallocationFunction.html>"]
@ -419,10 +419,10 @@ pub type PFN_vkAllocationFunction = Option<
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkFreeFunction.html>"] #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkFreeFunction.html>"]
pub type PFN_vkFreeFunction = pub type PFN_vkFreeFunction =
Option<unsafe extern "system" fn(p_user_data: *mut c_void, p_memory: *mut c_void) -> c_void>; Option<unsafe extern "system" fn(p_user_data: *mut c_void, p_memory: *mut c_void)>;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkVoidFunction.html>"] #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkVoidFunction.html>"]
pub type PFN_vkVoidFunction = Option<unsafe extern "system" fn() -> c_void>; pub type PFN_vkVoidFunction = Option<unsafe extern "system" fn()>;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkDebugReportCallbackEXT.html>"] #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/PFN_vkDebugReportCallbackEXT.html>"]
pub type PFN_vkDebugReportCallbackEXT = Option< pub type PFN_vkDebugReportCallbackEXT = Option<
@ -453,7 +453,7 @@ pub type PFN_vkDeviceMemoryReportCallbackEXT = Option<
unsafe extern "system" fn( unsafe extern "system" fn(
p_callback_data: *const DeviceMemoryReportCallbackDataEXT, p_callback_data: *const DeviceMemoryReportCallbackDataEXT,
p_user_data: *mut c_void, p_user_data: *mut c_void,
) -> c_void, ),
>; >;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -623,6 +623,9 @@ pub trait FieldExt {
/// which is needed for `C` function parameters. Set to `false` for struct definitions. /// which is needed for `C` function parameters. Set to `false` for struct definitions.
fn type_tokens(&self, is_ffi_param: bool) -> TokenStream; fn type_tokens(&self, is_ffi_param: bool) -> TokenStream;
fn is_clone(&self) -> bool; fn is_clone(&self) -> bool;
/// Whether this is C's `void` type (not to be mistaken with a void _pointer_!)
fn is_void(&self) -> bool;
} }
pub trait ToTokens { pub trait ToTokens {
@ -729,6 +732,7 @@ impl FieldExt for vkxml::Field {
} }
fn inner_type_tokens(&self) -> TokenStream { fn inner_type_tokens(&self) -> TokenStream {
assert!(!self.is_void());
let ty = name_to_tokens(&self.basetype); let ty = name_to_tokens(&self.basetype);
match self.reference { match self.reference {
@ -739,6 +743,7 @@ impl FieldExt for vkxml::Field {
} }
fn safe_type_tokens(&self, lifetime: TokenStream) -> TokenStream { fn safe_type_tokens(&self, lifetime: TokenStream) -> TokenStream {
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),
@ -758,6 +763,7 @@ impl FieldExt for vkxml::Field {
} }
fn type_tokens(&self, is_ffi_param: bool) -> TokenStream { fn type_tokens(&self, is_ffi_param: bool) -> TokenStream {
assert!(!self.is_void());
let ty = name_to_tokens(&self.basetype); let ty = name_to_tokens(&self.basetype);
match self.array { match self.array {
@ -784,6 +790,10 @@ impl FieldExt for vkxml::Field {
} }
} }
} }
fn is_void(&self) -> bool {
self.basetype == "void" && self.reference.is_none()
}
} }
pub type CommandMap<'a> = HashMap<vkxml::Identifier, &'a vkxml::Command>; pub type CommandMap<'a> = HashMap<vkxml::Identifier, &'a vkxml::Command>;
@ -901,12 +911,6 @@ fn generate_function_pointers<'a>(
.collect(); .collect();
let expanded_params_ref = &expanded_params; let expanded_params_ref = &expanded_params;
let return_types: Vec<_> = commands
.iter()
.map(|cmd| cmd.return_type.type_tokens(true))
.collect();
let return_types_ref = &return_types;
let pfn_names: Vec<_> = commands_pfn let pfn_names: Vec<_> = commands_pfn
.iter() .iter()
.map(|cmd| format_ident!("{}", format!("PFN_{}", cmd.name.as_str()))) .map(|cmd| format_ident!("{}", format!("PFN_{}", cmd.name.as_str())))
@ -930,21 +934,28 @@ fn generate_function_pointers<'a>(
.collect(); .collect();
let signature_params_ref = &signature_params; let signature_params_ref = &signature_params;
let pfn_return_types: Vec<_> = commands let return_types: Vec<_> = commands
.iter() .iter()
.map(|cmd| cmd.return_type.type_tokens(true)) .map(|cmd| {
if cmd.return_type.is_void() {
quote!()
} else {
let ret_ty_tokens = cmd.return_type.type_tokens(true);
quote!(-> #ret_ty_tokens)
}
})
.collect(); .collect();
let pfn_return_types_ref = &pfn_return_types; let return_types_ref = &return_types;
quote! { quote! {
#( #(
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type #pfn_names_ref = extern "system" fn(#(#signature_params_ref),*) -> #pfn_return_types_ref; pub type #pfn_names_ref = extern "system" fn(#(#signature_params_ref),*) #return_types_ref;
)* )*
pub struct #ident { pub struct #ident {
#( #(
pub #names_ref: extern "system" fn(#expanded_params_ref) -> #return_types_ref, pub #names_ref: extern "system" fn(#expanded_params_ref) #return_types_ref,
)* )*
} }
@ -966,7 +977,7 @@ fn generate_function_pointers<'a>(
#( #(
#names_ref: unsafe { #names_ref: unsafe {
extern "system" fn #names_ref1 (#expanded_params_unused) -> #return_types_ref { extern "system" fn #names_ref1 (#expanded_params_unused) #return_types_ref {
panic!(concat!("Unable to load ", stringify!(#names_ref2))) panic!(concat!("Unable to load ", stringify!(#names_ref2)))
} }
let raw_name = stringify!(#raw_names_ref); let raw_name = stringify!(#raw_names_ref);
@ -984,7 +995,7 @@ fn generate_function_pointers<'a>(
} }
#( #(
#[doc = #khronos_links] #[doc = #khronos_links]
pub unsafe fn #names_ref(&self, #expanded_params_ref) -> #return_types_ref { pub unsafe fn #names_ref(&self, #expanded_params_ref) #return_types_ref {
(self.#names_left)(#(#params_names,)*) (self.#names_left)(#(#params_names,)*)
} }
)* )*
@ -2060,7 +2071,12 @@ pub fn generate_handle(handle: &vkxml::Handle) -> Option<TokenStream> {
} }
fn generate_funcptr(fnptr: &vkxml::FunctionPointer) -> TokenStream { fn generate_funcptr(fnptr: &vkxml::FunctionPointer) -> TokenStream {
let name = format_ident!("{}", fnptr.name.as_str()); let name = format_ident!("{}", fnptr.name.as_str());
let ret_ty_tokens = fnptr.return_type.type_tokens(true); let ret_ty_tokens = if fnptr.return_type.is_void() {
quote!()
} else {
let ret_ty_tokens = fnptr.return_type.type_tokens(true);
quote!(-> #ret_ty_tokens)
};
let params = fnptr.param.iter().map(|field| { let params = fnptr.param.iter().map(|field| {
let ident = field.param_ident(); let ident = field.param_ident();
let type_tokens = field.type_tokens(true); let type_tokens = field.type_tokens(true);
@ -2072,7 +2088,7 @@ fn generate_funcptr(fnptr: &vkxml::FunctionPointer) -> TokenStream {
quote! { quote! {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = #khronos_link] #[doc = #khronos_link]
pub type #name = Option<unsafe extern "system" fn(#(#params),*) -> #ret_ty_tokens>; pub type #name = Option<unsafe extern "system" fn(#(#params),*) #ret_ty_tokens>;
} }
} }