generator: Untangle mismatched parameter/return fn signatures in types (#437)

* generator: Untangle mismatched parameter/return fn signatures in types

With function typedefs for commands having some elements filtered out
(by name) if they were previously defined already, combined with
unfiltered arrays containing the parameter sets and return type for
_all_ commands expanded together in `quote!` macros the wrong array
elements get combined resulting in incorrect signatures.  No-one seems
to use function pointer types (but we should!) which is why this has
gone unnoticed for some time.

* generator: Derive clone for function pointers instead of generating it

* generator: Regroup token generation per command instead of across arrays

This complements the previous commit by avoiding mismatches in array
content altogether, instead of expanding multiple arrays within a single
`#()*` quote expression and assuming they all contain the same data in
the same order, reducing cognitive overhead while reading this code.
This commit is contained in:
Marijn Suijten 2021-05-24 00:13:29 +02:00 committed by GitHub
parent 0ae6e49195
commit 82ca24663f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 550 additions and 2807 deletions

File diff suppressed because it is too large Load diff

View file

@ -5,19 +5,13 @@ use std::os::raw::*;
#[allow(non_camel_case_types)]
pub type PFN_vkGetInstanceProcAddr =
unsafe extern "system" fn(instance: Instance, p_name: *const c_char) -> PFN_vkVoidFunction;
#[derive(Clone)]
pub struct StaticFn {
pub get_instance_proc_addr:
unsafe extern "system" fn(instance: Instance, p_name: *const c_char) -> PFN_vkVoidFunction,
}
unsafe impl Send for StaticFn {}
unsafe impl Sync for StaticFn {}
impl ::std::clone::Clone for StaticFn {
fn clone(&self) -> Self {
StaticFn {
get_instance_proc_addr: self.get_instance_proc_addr,
}
}
}
impl StaticFn {
pub fn load<F>(mut _f: F) -> Self
where
@ -71,6 +65,7 @@ pub type PFN_vkEnumerateInstanceLayerProperties = unsafe extern "system" fn(
p_property_count: *mut u32,
p_properties: *mut LayerProperties,
) -> Result;
#[derive(Clone)]
pub struct EntryFnV1_0 {
pub create_instance: unsafe extern "system" fn(
p_create_info: *const InstanceCreateInfo,
@ -89,15 +84,6 @@ pub struct EntryFnV1_0 {
}
unsafe impl Send for EntryFnV1_0 {}
unsafe impl Sync for EntryFnV1_0 {}
impl ::std::clone::Clone for EntryFnV1_0 {
fn clone(&self) -> Self {
EntryFnV1_0 {
create_instance: self.create_instance,
enumerate_instance_extension_properties: self.enumerate_instance_extension_properties,
enumerate_instance_layer_properties: self.enumerate_instance_layer_properties,
}
}
}
impl EntryFnV1_0 {
pub fn load<F>(mut _f: F) -> Self
where
@ -270,6 +256,7 @@ pub type PFN_vkGetPhysicalDeviceSparseImageFormatProperties = unsafe extern "sys
p_property_count: *mut u32,
p_properties: *mut SparseImageFormatProperties,
);
#[derive(Clone)]
pub struct InstanceFnV1_0 {
pub destroy_instance:
unsafe extern "system" fn(instance: Instance, p_allocator: *const AllocationCallbacks),
@ -341,28 +328,6 @@ pub struct InstanceFnV1_0 {
}
unsafe impl Send for InstanceFnV1_0 {}
unsafe impl Sync for InstanceFnV1_0 {}
impl ::std::clone::Clone for InstanceFnV1_0 {
fn clone(&self) -> Self {
InstanceFnV1_0 {
destroy_instance: self.destroy_instance,
enumerate_physical_devices: self.enumerate_physical_devices,
get_physical_device_features: self.get_physical_device_features,
get_physical_device_format_properties: self.get_physical_device_format_properties,
get_physical_device_image_format_properties: self
.get_physical_device_image_format_properties,
get_physical_device_properties: self.get_physical_device_properties,
get_physical_device_queue_family_properties: self
.get_physical_device_queue_family_properties,
get_physical_device_memory_properties: self.get_physical_device_memory_properties,
get_device_proc_addr: self.get_device_proc_addr,
create_device: self.create_device,
enumerate_device_extension_properties: self.enumerate_device_extension_properties,
enumerate_device_layer_properties: self.enumerate_device_layer_properties,
get_physical_device_sparse_image_format_properties: self
.get_physical_device_sparse_image_format_properties,
}
}
}
impl InstanceFnV1_0 {
pub fn load<F>(mut _f: F) -> Self
where
@ -1575,6 +1540,7 @@ pub type PFN_vkCmdExecuteCommands = unsafe extern "system" fn(
command_buffer_count: u32,
p_command_buffers: *const CommandBuffer,
);
#[derive(Clone)]
pub struct DeviceFnV1_0 {
pub destroy_device:
unsafe extern "system" fn(device: Device, p_allocator: *const AllocationCallbacks),
@ -2253,132 +2219,6 @@ pub struct DeviceFnV1_0 {
}
unsafe impl Send for DeviceFnV1_0 {}
unsafe impl Sync for DeviceFnV1_0 {}
impl ::std::clone::Clone for DeviceFnV1_0 {
fn clone(&self) -> Self {
DeviceFnV1_0 {
destroy_device: self.destroy_device,
get_device_queue: self.get_device_queue,
queue_submit: self.queue_submit,
queue_wait_idle: self.queue_wait_idle,
device_wait_idle: self.device_wait_idle,
allocate_memory: self.allocate_memory,
free_memory: self.free_memory,
map_memory: self.map_memory,
unmap_memory: self.unmap_memory,
flush_mapped_memory_ranges: self.flush_mapped_memory_ranges,
invalidate_mapped_memory_ranges: self.invalidate_mapped_memory_ranges,
get_device_memory_commitment: self.get_device_memory_commitment,
bind_buffer_memory: self.bind_buffer_memory,
bind_image_memory: self.bind_image_memory,
get_buffer_memory_requirements: self.get_buffer_memory_requirements,
get_image_memory_requirements: self.get_image_memory_requirements,
get_image_sparse_memory_requirements: self.get_image_sparse_memory_requirements,
queue_bind_sparse: self.queue_bind_sparse,
create_fence: self.create_fence,
destroy_fence: self.destroy_fence,
reset_fences: self.reset_fences,
get_fence_status: self.get_fence_status,
wait_for_fences: self.wait_for_fences,
create_semaphore: self.create_semaphore,
destroy_semaphore: self.destroy_semaphore,
create_event: self.create_event,
destroy_event: self.destroy_event,
get_event_status: self.get_event_status,
set_event: self.set_event,
reset_event: self.reset_event,
create_query_pool: self.create_query_pool,
destroy_query_pool: self.destroy_query_pool,
get_query_pool_results: self.get_query_pool_results,
create_buffer: self.create_buffer,
destroy_buffer: self.destroy_buffer,
create_buffer_view: self.create_buffer_view,
destroy_buffer_view: self.destroy_buffer_view,
create_image: self.create_image,
destroy_image: self.destroy_image,
get_image_subresource_layout: self.get_image_subresource_layout,
create_image_view: self.create_image_view,
destroy_image_view: self.destroy_image_view,
create_shader_module: self.create_shader_module,
destroy_shader_module: self.destroy_shader_module,
create_pipeline_cache: self.create_pipeline_cache,
destroy_pipeline_cache: self.destroy_pipeline_cache,
get_pipeline_cache_data: self.get_pipeline_cache_data,
merge_pipeline_caches: self.merge_pipeline_caches,
create_graphics_pipelines: self.create_graphics_pipelines,
create_compute_pipelines: self.create_compute_pipelines,
destroy_pipeline: self.destroy_pipeline,
create_pipeline_layout: self.create_pipeline_layout,
destroy_pipeline_layout: self.destroy_pipeline_layout,
create_sampler: self.create_sampler,
destroy_sampler: self.destroy_sampler,
create_descriptor_set_layout: self.create_descriptor_set_layout,
destroy_descriptor_set_layout: self.destroy_descriptor_set_layout,
create_descriptor_pool: self.create_descriptor_pool,
destroy_descriptor_pool: self.destroy_descriptor_pool,
reset_descriptor_pool: self.reset_descriptor_pool,
allocate_descriptor_sets: self.allocate_descriptor_sets,
free_descriptor_sets: self.free_descriptor_sets,
update_descriptor_sets: self.update_descriptor_sets,
create_framebuffer: self.create_framebuffer,
destroy_framebuffer: self.destroy_framebuffer,
create_render_pass: self.create_render_pass,
destroy_render_pass: self.destroy_render_pass,
get_render_area_granularity: self.get_render_area_granularity,
create_command_pool: self.create_command_pool,
destroy_command_pool: self.destroy_command_pool,
reset_command_pool: self.reset_command_pool,
allocate_command_buffers: self.allocate_command_buffers,
free_command_buffers: self.free_command_buffers,
begin_command_buffer: self.begin_command_buffer,
end_command_buffer: self.end_command_buffer,
reset_command_buffer: self.reset_command_buffer,
cmd_bind_pipeline: self.cmd_bind_pipeline,
cmd_set_viewport: self.cmd_set_viewport,
cmd_set_scissor: self.cmd_set_scissor,
cmd_set_line_width: self.cmd_set_line_width,
cmd_set_depth_bias: self.cmd_set_depth_bias,
cmd_set_blend_constants: self.cmd_set_blend_constants,
cmd_set_depth_bounds: self.cmd_set_depth_bounds,
cmd_set_stencil_compare_mask: self.cmd_set_stencil_compare_mask,
cmd_set_stencil_write_mask: self.cmd_set_stencil_write_mask,
cmd_set_stencil_reference: self.cmd_set_stencil_reference,
cmd_bind_descriptor_sets: self.cmd_bind_descriptor_sets,
cmd_bind_index_buffer: self.cmd_bind_index_buffer,
cmd_bind_vertex_buffers: self.cmd_bind_vertex_buffers,
cmd_draw: self.cmd_draw,
cmd_draw_indexed: self.cmd_draw_indexed,
cmd_draw_indirect: self.cmd_draw_indirect,
cmd_draw_indexed_indirect: self.cmd_draw_indexed_indirect,
cmd_dispatch: self.cmd_dispatch,
cmd_dispatch_indirect: self.cmd_dispatch_indirect,
cmd_copy_buffer: self.cmd_copy_buffer,
cmd_copy_image: self.cmd_copy_image,
cmd_blit_image: self.cmd_blit_image,
cmd_copy_buffer_to_image: self.cmd_copy_buffer_to_image,
cmd_copy_image_to_buffer: self.cmd_copy_image_to_buffer,
cmd_update_buffer: self.cmd_update_buffer,
cmd_fill_buffer: self.cmd_fill_buffer,
cmd_clear_color_image: self.cmd_clear_color_image,
cmd_clear_depth_stencil_image: self.cmd_clear_depth_stencil_image,
cmd_clear_attachments: self.cmd_clear_attachments,
cmd_resolve_image: self.cmd_resolve_image,
cmd_set_event: self.cmd_set_event,
cmd_reset_event: self.cmd_reset_event,
cmd_wait_events: self.cmd_wait_events,
cmd_pipeline_barrier: self.cmd_pipeline_barrier,
cmd_begin_query: self.cmd_begin_query,
cmd_end_query: self.cmd_end_query,
cmd_reset_query_pool: self.cmd_reset_query_pool,
cmd_write_timestamp: self.cmd_write_timestamp,
cmd_copy_query_pool_results: self.cmd_copy_query_pool_results,
cmd_push_constants: self.cmd_push_constants,
cmd_begin_render_pass: self.cmd_begin_render_pass,
cmd_next_subpass: self.cmd_next_subpass,
cmd_end_render_pass: self.cmd_end_render_pass,
cmd_execute_commands: self.cmd_execute_commands,
}
}
}
impl DeviceFnV1_0 {
pub fn load<F>(mut _f: F) -> Self
where
@ -5931,18 +5771,12 @@ impl DeviceFnV1_0 {
#[allow(non_camel_case_types)]
pub type PFN_vkEnumerateInstanceVersion =
unsafe extern "system" fn(p_api_version: *mut u32) -> Result;
#[derive(Clone)]
pub struct EntryFnV1_1 {
pub enumerate_instance_version: unsafe extern "system" fn(p_api_version: *mut u32) -> Result,
}
unsafe impl Send for EntryFnV1_1 {}
unsafe impl Sync for EntryFnV1_1 {}
impl ::std::clone::Clone for EntryFnV1_1 {
fn clone(&self) -> Self {
EntryFnV1_1 {
enumerate_instance_version: self.enumerate_instance_version,
}
}
}
impl EntryFnV1_1 {
pub fn load<F>(mut _f: F) -> Self
where
@ -5975,6 +5809,7 @@ impl EntryFnV1_1 {
(self.enumerate_instance_version)(p_api_version)
}
}
#[derive(Clone)]
pub struct InstanceFnV1_1 {
pub enumerate_physical_device_groups: unsafe extern "system" fn(
instance: Instance,
@ -6032,29 +5867,6 @@ pub struct InstanceFnV1_1 {
}
unsafe impl Send for InstanceFnV1_1 {}
unsafe impl Sync for InstanceFnV1_1 {}
impl ::std::clone::Clone for InstanceFnV1_1 {
fn clone(&self) -> Self {
InstanceFnV1_1 {
enumerate_physical_device_groups: self.enumerate_physical_device_groups,
get_physical_device_features2: self.get_physical_device_features2,
get_physical_device_properties2: self.get_physical_device_properties2,
get_physical_device_format_properties2: self.get_physical_device_format_properties2,
get_physical_device_image_format_properties2: self
.get_physical_device_image_format_properties2,
get_physical_device_queue_family_properties2: self
.get_physical_device_queue_family_properties2,
get_physical_device_memory_properties2: self.get_physical_device_memory_properties2,
get_physical_device_sparse_image_format_properties2: self
.get_physical_device_sparse_image_format_properties2,
get_physical_device_external_buffer_properties: self
.get_physical_device_external_buffer_properties,
get_physical_device_external_fence_properties: self
.get_physical_device_external_fence_properties,
get_physical_device_external_semaphore_properties: self
.get_physical_device_external_semaphore_properties,
}
}
}
impl InstanceFnV1_1 {
pub fn load<F>(mut _f: F) -> Self
where
@ -6422,9 +6234,10 @@ impl InstanceFnV1_1 {
#[allow(non_camel_case_types)]
pub type PFN_vkGetDeviceQueue2 = unsafe extern "system" fn(
device: Device,
bind_info_count: u32,
p_bind_infos: *const BindBufferMemoryInfo,
) -> Result;
p_queue_info: *const DeviceQueueInfo2,
p_queue: *mut Queue,
);
#[derive(Clone)]
pub struct DeviceFnV1_1 {
pub bind_buffer_memory2: unsafe extern "system" fn(
device: Device,
@ -6516,28 +6329,6 @@ pub struct DeviceFnV1_1 {
}
unsafe impl Send for DeviceFnV1_1 {}
unsafe impl Sync for DeviceFnV1_1 {}
impl ::std::clone::Clone for DeviceFnV1_1 {
fn clone(&self) -> Self {
DeviceFnV1_1 {
bind_buffer_memory2: self.bind_buffer_memory2,
bind_image_memory2: self.bind_image_memory2,
get_device_group_peer_memory_features: self.get_device_group_peer_memory_features,
cmd_set_device_mask: self.cmd_set_device_mask,
cmd_dispatch_base: self.cmd_dispatch_base,
get_image_memory_requirements2: self.get_image_memory_requirements2,
get_buffer_memory_requirements2: self.get_buffer_memory_requirements2,
get_image_sparse_memory_requirements2: self.get_image_sparse_memory_requirements2,
trim_command_pool: self.trim_command_pool,
get_device_queue2: self.get_device_queue2,
create_sampler_ycbcr_conversion: self.create_sampler_ycbcr_conversion,
destroy_sampler_ycbcr_conversion: self.destroy_sampler_ycbcr_conversion,
create_descriptor_update_template: self.create_descriptor_update_template,
destroy_descriptor_update_template: self.destroy_descriptor_update_template,
update_descriptor_set_with_template: self.update_descriptor_set_with_template,
get_descriptor_set_layout_support: self.get_descriptor_set_layout_support,
}
}
}
impl DeviceFnV1_1 {
pub fn load<F>(mut _f: F) -> Self
where
@ -7048,14 +6839,10 @@ impl DeviceFnV1_1 {
(self.get_descriptor_set_layout_support)(device, p_create_info, p_support)
}
}
#[derive(Clone)]
pub struct EntryFnV1_2 {}
unsafe impl Send for EntryFnV1_2 {}
unsafe impl Sync for EntryFnV1_2 {}
impl ::std::clone::Clone for EntryFnV1_2 {
fn clone(&self) -> Self {
EntryFnV1_2 {}
}
}
impl EntryFnV1_2 {
pub fn load<F>(mut _f: F) -> Self
where
@ -7064,14 +6851,10 @@ impl EntryFnV1_2 {
EntryFnV1_2 {}
}
}
#[derive(Clone)]
pub struct InstanceFnV1_2 {}
unsafe impl Send for InstanceFnV1_2 {}
unsafe impl Sync for InstanceFnV1_2 {}
impl ::std::clone::Clone for InstanceFnV1_2 {
fn clone(&self) -> Self {
InstanceFnV1_2 {}
}
}
impl InstanceFnV1_2 {
pub fn load<F>(mut _f: F) -> Self
where
@ -7080,6 +6863,7 @@ impl InstanceFnV1_2 {
InstanceFnV1_2 {}
}
}
#[derive(Clone)]
pub struct DeviceFnV1_2 {
pub cmd_draw_indirect_count: unsafe extern "system" fn(
command_buffer: CommandBuffer,
@ -7152,25 +6936,6 @@ pub struct DeviceFnV1_2 {
}
unsafe impl Send for DeviceFnV1_2 {}
unsafe impl Sync for DeviceFnV1_2 {}
impl ::std::clone::Clone for DeviceFnV1_2 {
fn clone(&self) -> Self {
DeviceFnV1_2 {
cmd_draw_indirect_count: self.cmd_draw_indirect_count,
cmd_draw_indexed_indirect_count: self.cmd_draw_indexed_indirect_count,
create_render_pass2: self.create_render_pass2,
cmd_begin_render_pass2: self.cmd_begin_render_pass2,
cmd_next_subpass2: self.cmd_next_subpass2,
cmd_end_render_pass2: self.cmd_end_render_pass2,
reset_query_pool: self.reset_query_pool,
get_semaphore_counter_value: self.get_semaphore_counter_value,
wait_semaphores: self.wait_semaphores,
signal_semaphore: self.signal_semaphore,
get_buffer_device_address: self.get_buffer_device_address,
get_buffer_opaque_capture_address: self.get_buffer_opaque_capture_address,
get_device_memory_opaque_capture_address: self.get_device_memory_opaque_capture_address,
}
}
}
impl DeviceFnV1_2 {
pub fn load<F>(mut _f: F) -> Self
where

View file

@ -841,48 +841,37 @@ fn generate_function_pointers<'a>(
.iter()
.unique_by(|cmd| cmd.name.as_str())
.collect::<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| fn_cache.insert(cmd.name.as_str()))
.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);
format_ident!(
"{}",
fn_name.strip_prefix("vk").unwrap().to_snake_case().as_str()
)
};
let names: Vec<_> = commands
.iter()
.map(|cmd| function_name(&cmd.name))
.collect();
let names_ref = &names;
let raw_names: Vec<_> = commands
struct Command {
type_needs_defining: bool,
type_name: Ident,
function_name_c: String,
function_name_rust: Ident,
parameter_names: TokenStream,
parameters: TokenStream,
parameters_unused: TokenStream,
returns: TokenStream,
}
let commands = commands
.iter()
.map(|cmd| {
let byt = std::ffi::CString::new(function_name_raw(cmd.name.as_str())).unwrap();
Literal::byte_string(byt.to_bytes_with_nul())
})
.collect();
let raw_names_ref = &raw_names;
let khronos_links: Vec<_> = commands
.iter()
.map(|cmd| khronos_link(&function_name_raw(cmd.name.as_str())))
.collect();
let type_name = format_ident!("PFN_{}", cmd.name);
let function_name_c = if let Some(alias_name) = aliases.get(&cmd.name) {
alias_name.to_string()
} else {
cmd.name.to_string()
};
let function_name_rust = format_ident!(
"{}",
function_name_c
.strip_prefix("vk")
.unwrap()
.to_snake_case()
.as_str()
);
let params: Vec<Vec<(Ident, TokenStream)>> = commands
.iter()
.map(|cmd| {
let params: Vec<_> = cmd
.param
.iter()
@ -892,131 +881,142 @@ fn generate_function_pointers<'a>(
(name, ty)
})
.collect();
params
})
.collect();
let params_names: Vec<Vec<_>> = params
.iter()
.map(|inner_params| {
inner_params
let params_iter = params.iter().map(|(param_name, _)| param_name);
let parameter_names = quote!(#(#params_iter,)*);
let params_iter = params
.iter()
.map(|(param_name, _)| param_name.clone())
.collect()
})
.collect();
let expanded_params: Vec<_> = params
.iter()
.map(|inner_params| {
let inner_params_iter = inner_params.iter().map(|&(ref param_name, ref param_ty)| {
quote! {#param_name: #param_ty}
});
quote! {
#(#inner_params_iter,)*
}
})
.collect();
let expanded_params_unused: Vec<_> = params
.iter()
.map(|inner_params| {
let inner_params_iter = inner_params.iter().map(|&(ref param_name, ref param_ty)| {
.map(|(param_name, param_ty)| quote!(#param_name: #param_ty));
let parameters = quote!(#(#params_iter,)*);
let params_iter = params.iter().map(|(param_name, param_ty)| {
let unused_name = format_ident!("_{}", param_name);
quote! {#unused_name: #param_ty}
quote!(#unused_name: #param_ty)
});
quote! {
#(#inner_params_iter,)*
let parameters_unused = quote!(#(#params_iter,)*);
Command {
// PFN function pointers are global and can not have duplicates.
// This can happen because there are aliases to commands
type_needs_defining: fn_cache.insert(cmd.name.as_str()),
type_name,
function_name_c,
function_name_rust,
parameter_names,
parameters,
parameters_unused,
returns: if cmd.return_type.is_void() {
quote!()
} else {
let ret_ty_tokens = cmd.return_type.type_tokens(true);
quote!(-> #ret_ty_tokens)
},
}
})
.collect();
let expanded_params_ref = &expanded_params;
.collect::<Vec<_>>();
let pfn_names: Vec<_> = commands_pfn
.iter()
.map(|cmd| format_ident!("PFN_{}", cmd.name))
.collect();
let pfn_names_ref = &pfn_names;
struct CommandToType<'a>(&'a Command);
impl<'a> quote::ToTokens for CommandToType<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let type_name = &self.0.type_name;
let parameters = &self.0.parameters;
let returns = &self.0.returns;
quote!(
#[allow(non_camel_case_types)]
pub type #type_name = unsafe extern "system" fn(#parameters) #returns;
)
.to_tokens(tokens)
}
}
let signature_params: Vec<Vec<_>> = commands
.iter()
.map(|cmd| {
let params: Vec<_> = cmd
.param
.iter()
.map(|field| {
let name = field.param_ident();
let ty = field.type_tokens(true);
quote! { #name: #ty }
})
.collect();
params
})
.collect();
let signature_params_ref = &signature_params;
struct CommandToMember<'a>(&'a Command);
impl<'a> quote::ToTokens for CommandToMember<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let function_name_rust = &self.0.function_name_rust;
let parameters = &self.0.parameters;
let returns = &self.0.returns;
quote!(
pub #function_name_rust: unsafe extern "system" fn(#parameters) #returns
)
.to_tokens(tokens)
}
}
let return_types: Vec<_> = commands
struct CommandToLoader<'a>(&'a Command);
impl<'a> quote::ToTokens for CommandToLoader<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let function_name_rust = &self.0.function_name_rust;
let parameters_unused = &self.0.parameters_unused;
let returns = &self.0.returns;
let byte_function_name =
Literal::byte_string(format!("{}\0", self.0.function_name_c).as_bytes());
quote!(
#function_name_rust: unsafe {
unsafe extern "system" fn #function_name_rust (#parameters_unused) #returns {
panic!(concat!("Unable to load ", stringify!(#function_name_rust)))
}
let cname = ::std::ffi::CStr::from_bytes_with_nul_unchecked(#byte_function_name);
let val = _f(cname);
if val.is_null() {
#function_name_rust
} else {
::std::mem::transmute(val)
}
}
)
.to_tokens(tokens)
}
}
struct CommandToBody<'a>(&'a Command);
impl<'a> quote::ToTokens for CommandToBody<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let function_name_rust = &self.0.function_name_rust;
let parameters = &self.0.parameters;
let parameter_names = &self.0.parameter_names;
let returns = &self.0.returns;
let khronos_link = khronos_link(&self.0.function_name_c);
quote!(
#[doc = #khronos_link]
pub unsafe fn #function_name_rust(&self, #parameters) #returns {
(self.#function_name_rust)(#parameter_names)
}
)
.to_tokens(tokens)
}
}
let pfn_typedefs = commands
.iter()
.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();
let return_types_ref = &return_types;
.filter(|pfn| pfn.type_needs_defining)
.map(|pfn| CommandToType(pfn));
let members = commands.iter().map(|pfn| CommandToMember(pfn));
let loaders = commands.iter().map(|pfn| CommandToLoader(pfn));
let bodies = commands.iter().map(|pfn| CommandToBody(pfn));
quote! {
#(
#[allow(non_camel_case_types)]
pub type #pfn_names_ref = unsafe extern "system" fn(#(#signature_params_ref),*) #return_types_ref;
)*
#(#pfn_typedefs)*
#[derive(Clone)]
pub struct #ident {
#(
pub #names_ref: unsafe extern "system" fn(#expanded_params_ref) #return_types_ref,
)*
#(#members,)*
}
unsafe impl Send for #ident {}
unsafe impl Sync for #ident {}
impl ::std::clone::Clone for #ident {
fn clone(&self) -> Self {
#ident{
#(#names: self.#names,)*
}
}
}
impl #ident {
pub fn load<F>(mut _f: F) -> Self
where F: FnMut(&::std::ffi::CStr) -> *const c_void
{
#ident {
#(
#names_ref: unsafe {
unsafe extern "system" fn #names_ref (#expanded_params_unused) #return_types_ref {
panic!(concat!("Unable to load ", stringify!(#names_ref)))
}
let cname = ::std::ffi::CStr::from_bytes_with_nul_unchecked(#raw_names_ref);
let val = _f(cname);
if val.is_null(){
#names_ref
}
else{
::std::mem::transmute(val)
}
},
)*
#(#loaders,)*
}
}
#(
#[doc = #khronos_links]
pub unsafe fn #names_ref(&self, #expanded_params_ref) #return_types_ref {
(self.#names)(#(#params_names,)*)
}
)*
#(#bodies)*
}
}
}