Provide CStr getters and setters for c_char pointers and arrays (#831)

It is a common operation to read and write NUL-terminated C string in
the Vulkan API, yet the only helpers for that were thus far open-coded
in the `Debug` printing implementations.

Move them to separate functions that are exposed to the user, in hopes
of helping them no longer misunderstand NUL-terminated strings (see
e.g. #830).

Important to note is that the array-copy for a static-sized `c_char`
array has also been replaced with a `CStr` wrapper: this forces the user
and our implementation to have a NUL-terminator at the end of the string,
and the setter returns `Err()` when the given `CStr (with NUL-terminator)
is too large for the static-sized array it has to be written to.
This commit is contained in:
Marijn Suijten 2023-11-29 00:37:21 +01:00 committed by GitHub
parent 5938fd2633
commit 02c7a83592
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 436 additions and 228 deletions

View file

@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `VK_EXT_hdr_metadata` device extension (#804)
- Added `VK_NV_cuda_kernel_launch` device extension (#805)
- Added `descriptor_count()` setter on `ash::vk::WriteDescriptorSet` (#809)
- Added `*_as_c_str()` getters for `c_char` pointers and `c_char` arrays (#831)
### Changed
@ -48,7 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `VK_KHR_device_group_creation`: Take borrow of `Entry` in `fn new()` (#753)
- `VK_KHR_device_group_creation`: Rename `vk::Instance`-returning function from `device()` to `instance()` (#759)
- Windows `HANDLE` types (`HWND`, `HINSTANCE`, `HMONITOR`) are now defined as `isize` instead of `*const c_void` (#797)
- extensions/ext/ray_tracing_pipeline: Pass indirect SBT regions as single item reference. (#829)
- extensions/ext/ray_tracing_pipeline: Pass indirect SBT regions as single item reference (#829)
- Replaced `c_char` array setters with `CStr` setters (#831)
### Removed

View file

@ -817,9 +817,7 @@ impl fmt::Debug for PhysicalDeviceProperties {
.field("vendor_id", &self.vendor_id)
.field("device_id", &self.device_id)
.field("device_type", &self.device_type)
.field("device_name", &unsafe {
::std::ffi::CStr::from_ptr(self.device_name.as_ptr())
})
.field("device_name", &unsafe { self.device_name_as_c_str() })
.field("pipeline_cache_uuid", &self.pipeline_cache_uuid)
.field("limits", &self.limits)
.field("sparse_properties", &self.sparse_properties)
@ -869,9 +867,15 @@ impl PhysicalDeviceProperties {
self
}
#[inline]
pub fn device_name(mut self, device_name: [c_char; MAX_PHYSICAL_DEVICE_NAME_SIZE]) -> Self {
self.device_name = device_name;
self
pub fn device_name(
mut self,
device_name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.device_name, device_name).map(|()| self)
}
#[inline]
pub unsafe fn device_name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.device_name)
}
#[inline]
pub fn pipeline_cache_uuid(mut self, pipeline_cache_uuid: [u8; UUID_SIZE]) -> Self {
@ -900,9 +904,7 @@ pub struct ExtensionProperties {
impl fmt::Debug for ExtensionProperties {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("ExtensionProperties")
.field("extension_name", &unsafe {
::std::ffi::CStr::from_ptr(self.extension_name.as_ptr())
})
.field("extension_name", &unsafe { self.extension_name_as_c_str() })
.field("spec_version", &self.spec_version)
.finish()
}
@ -918,9 +920,15 @@ impl ::std::default::Default for ExtensionProperties {
}
impl ExtensionProperties {
#[inline]
pub fn extension_name(mut self, extension_name: [c_char; MAX_EXTENSION_NAME_SIZE]) -> Self {
self.extension_name = extension_name;
self
pub fn extension_name(
mut self,
extension_name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.extension_name, extension_name).map(|()| self)
}
#[inline]
pub unsafe fn extension_name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.extension_name)
}
#[inline]
pub fn spec_version(mut self, spec_version: u32) -> Self {
@ -941,14 +949,10 @@ pub struct LayerProperties {
impl fmt::Debug for LayerProperties {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("LayerProperties")
.field("layer_name", &unsafe {
::std::ffi::CStr::from_ptr(self.layer_name.as_ptr())
})
.field("layer_name", &unsafe { self.layer_name_as_c_str() })
.field("spec_version", &self.spec_version)
.field("implementation_version", &self.implementation_version)
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("description", &unsafe { self.description_as_c_str() })
.finish()
}
}
@ -965,9 +969,15 @@ impl ::std::default::Default for LayerProperties {
}
impl LayerProperties {
#[inline]
pub fn layer_name(mut self, layer_name: [c_char; MAX_EXTENSION_NAME_SIZE]) -> Self {
self.layer_name = layer_name;
self
pub fn layer_name(
mut self,
layer_name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.layer_name, layer_name).map(|()| self)
}
#[inline]
pub unsafe fn layer_name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.layer_name)
}
#[inline]
pub fn spec_version(mut self, spec_version: u32) -> Self {
@ -980,9 +990,15 @@ impl LayerProperties {
self
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
}
#[repr(C)]
@ -1019,21 +1035,29 @@ unsafe impl<'a> TaggedStructure for ApplicationInfo<'a> {
}
impl<'a> ApplicationInfo<'a> {
#[inline]
pub fn application_name(mut self, application_name: &'a ::std::ffi::CStr) -> Self {
pub fn application_name(mut self, application_name: &'a std::ffi::CStr) -> Self {
self.p_application_name = application_name.as_ptr();
self
}
#[inline]
pub unsafe fn application_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_application_name)
}
#[inline]
pub fn application_version(mut self, application_version: u32) -> Self {
self.application_version = application_version;
self
}
#[inline]
pub fn engine_name(mut self, engine_name: &'a ::std::ffi::CStr) -> Self {
pub fn engine_name(mut self, engine_name: &'a std::ffi::CStr) -> Self {
self.p_engine_name = engine_name.as_ptr();
self
}
#[inline]
pub unsafe fn engine_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_engine_name)
}
#[inline]
pub fn engine_version(mut self, engine_version: u32) -> Self {
self.engine_version = engine_version;
self
@ -3651,11 +3675,15 @@ impl<'a> PipelineShaderStageCreateInfo<'a> {
self
}
#[inline]
pub fn name(mut self, name: &'a ::std::ffi::CStr) -> Self {
pub fn name(mut self, name: &'a std::ffi::CStr) -> Self {
self.p_name = name.as_ptr();
self
}
#[inline]
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_name)
}
#[inline]
pub fn specialization_info(mut self, specialization_info: &'a SpecializationInfo<'a>) -> Self {
self.p_specialization_info = specialization_info;
self
@ -7712,11 +7740,15 @@ impl<'a> DisplayPropertiesKHR<'a> {
self
}
#[inline]
pub fn display_name(mut self, display_name: &'a ::std::ffi::CStr) -> Self {
pub fn display_name(mut self, display_name: &'a std::ffi::CStr) -> Self {
self.display_name = display_name.as_ptr();
self
}
#[inline]
pub unsafe fn display_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.display_name)
}
#[inline]
pub fn physical_dimensions(mut self, physical_dimensions: Extent2D) -> Self {
self.physical_dimensions = physical_dimensions;
self
@ -8985,10 +9017,14 @@ impl<'a> DebugMarkerObjectNameInfoEXT<'a> {
self
}
#[inline]
pub fn object_name(mut self, object_name: &'a ::std::ffi::CStr) -> Self {
pub fn object_name(mut self, object_name: &'a std::ffi::CStr) -> Self {
self.p_object_name = object_name.as_ptr();
self
}
#[inline]
pub unsafe fn object_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_object_name)
}
}
#[repr(C)]
#[cfg_attr(feature = "debug", derive(Debug))]
@ -9073,11 +9109,15 @@ unsafe impl<'a> TaggedStructure for DebugMarkerMarkerInfoEXT<'a> {
}
impl<'a> DebugMarkerMarkerInfoEXT<'a> {
#[inline]
pub fn marker_name(mut self, marker_name: &'a ::std::ffi::CStr) -> Self {
pub fn marker_name(mut self, marker_name: &'a std::ffi::CStr) -> Self {
self.p_marker_name = marker_name.as_ptr();
self
}
#[inline]
pub unsafe fn marker_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_marker_name)
}
#[inline]
pub fn color(mut self, color: [f32; 4]) -> Self {
self.color = color;
self
@ -10908,12 +10948,8 @@ impl fmt::Debug for PhysicalDeviceDriverProperties<'_> {
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("driver_id", &self.driver_id)
.field("driver_name", &unsafe {
::std::ffi::CStr::from_ptr(self.driver_name.as_ptr())
})
.field("driver_info", &unsafe {
::std::ffi::CStr::from_ptr(self.driver_info.as_ptr())
})
.field("driver_name", &unsafe { self.driver_name_as_c_str() })
.field("driver_info", &unsafe { self.driver_info_as_c_str() })
.field("conformance_version", &self.conformance_version)
.finish()
}
@ -10943,14 +10979,26 @@ impl<'a> PhysicalDeviceDriverProperties<'a> {
self
}
#[inline]
pub fn driver_name(mut self, driver_name: [c_char; MAX_DRIVER_NAME_SIZE]) -> Self {
self.driver_name = driver_name;
self
pub fn driver_name(
mut self,
driver_name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.driver_name, driver_name).map(|()| self)
}
#[inline]
pub fn driver_info(mut self, driver_info: [c_char; MAX_DRIVER_INFO_SIZE]) -> Self {
self.driver_info = driver_info;
self
pub unsafe fn driver_name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.driver_name)
}
#[inline]
pub fn driver_info(
mut self,
driver_info: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.driver_info, driver_info).map(|()| self)
}
#[inline]
pub unsafe fn driver_info_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.driver_info)
}
#[inline]
pub fn conformance_version(mut self, conformance_version: ConformanceVersion) -> Self {
@ -18302,10 +18350,14 @@ impl<'a> DebugUtilsObjectNameInfoEXT<'a> {
self
}
#[inline]
pub fn object_name(mut self, object_name: &'a ::std::ffi::CStr) -> Self {
pub fn object_name(mut self, object_name: &'a std::ffi::CStr) -> Self {
self.p_object_name = object_name.as_ptr();
self
}
#[inline]
pub unsafe fn object_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_object_name)
}
}
#[repr(C)]
#[cfg_attr(feature = "debug", derive(Debug))]
@ -18386,11 +18438,15 @@ unsafe impl<'a> TaggedStructure for DebugUtilsLabelEXT<'a> {
}
impl<'a> DebugUtilsLabelEXT<'a> {
#[inline]
pub fn label_name(mut self, label_name: &'a ::std::ffi::CStr) -> Self {
pub fn label_name(mut self, label_name: &'a std::ffi::CStr) -> Self {
self.p_label_name = label_name.as_ptr();
self
}
#[inline]
pub unsafe fn label_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_label_name)
}
#[inline]
pub fn color(mut self, color: [f32; 4]) -> Self {
self.color = color;
self
@ -18525,21 +18581,29 @@ impl<'a> DebugUtilsMessengerCallbackDataEXT<'a> {
self
}
#[inline]
pub fn message_id_name(mut self, message_id_name: &'a ::std::ffi::CStr) -> Self {
pub fn message_id_name(mut self, message_id_name: &'a std::ffi::CStr) -> Self {
self.p_message_id_name = message_id_name.as_ptr();
self
}
#[inline]
pub unsafe fn message_id_name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_message_id_name)
}
#[inline]
pub fn message_id_number(mut self, message_id_number: i32) -> Self {
self.message_id_number = message_id_number;
self
}
#[inline]
pub fn message(mut self, message: &'a ::std::ffi::CStr) -> Self {
pub fn message(mut self, message: &'a std::ffi::CStr) -> Self {
self.p_message = message.as_ptr();
self
}
#[inline]
pub unsafe fn message_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_message)
}
#[inline]
pub fn queue_labels(mut self, queue_labels: &'a [DebugUtilsLabelEXT<'a>]) -> Self {
self.queue_label_count = queue_labels.len() as _;
self.p_queue_labels = queue_labels.as_ptr();
@ -27064,15 +27128,9 @@ impl fmt::Debug for PerformanceCounterDescriptionKHR<'_> {
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("flags", &self.flags)
.field("name", &unsafe {
::std::ffi::CStr::from_ptr(self.name.as_ptr())
})
.field("category", &unsafe {
::std::ffi::CStr::from_ptr(self.category.as_ptr())
})
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("name", &unsafe { self.name_as_c_str() })
.field("category", &unsafe { self.category_as_c_str() })
.field("description", &unsafe { self.description_as_c_str() })
.finish()
}
}
@ -27100,19 +27158,37 @@ impl<'a> PerformanceCounterDescriptionKHR<'a> {
self
}
#[inline]
pub fn name(mut self, name: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.name = name;
self
pub fn name(
mut self,
name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.name, name).map(|()| self)
}
#[inline]
pub fn category(mut self, category: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.category = category;
self
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.name)
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub fn category(
mut self,
category: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.category, category).map(|()| self)
}
#[inline]
pub unsafe fn category_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.category)
}
#[inline]
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
}
#[repr(C)]
@ -28151,12 +28227,8 @@ impl fmt::Debug for PipelineExecutablePropertiesKHR<'_> {
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("stages", &self.stages)
.field("name", &unsafe {
::std::ffi::CStr::from_ptr(self.name.as_ptr())
})
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("name", &unsafe { self.name_as_c_str() })
.field("description", &unsafe { self.description_as_c_str() })
.field("subgroup_size", &self.subgroup_size)
.finish()
}
@ -28185,14 +28257,26 @@ impl<'a> PipelineExecutablePropertiesKHR<'a> {
self
}
#[inline]
pub fn name(mut self, name: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.name = name;
self
pub fn name(
mut self,
name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.name, name).map(|()| self)
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.name)
}
#[inline]
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn subgroup_size(mut self, subgroup_size: u32) -> Self {
@ -28271,12 +28355,8 @@ impl fmt::Debug for PipelineExecutableStatisticKHR<'_> {
fmt.debug_struct("PipelineExecutableStatisticKHR")
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("name", &unsafe {
::std::ffi::CStr::from_ptr(self.name.as_ptr())
})
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("name", &unsafe { self.name_as_c_str() })
.field("description", &unsafe { self.description_as_c_str() })
.field("format", &self.format)
.field("value", &"union")
.finish()
@ -28301,14 +28381,26 @@ unsafe impl<'a> TaggedStructure for PipelineExecutableStatisticKHR<'a> {
}
impl<'a> PipelineExecutableStatisticKHR<'a> {
#[inline]
pub fn name(mut self, name: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.name = name;
self
pub fn name(
mut self,
name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.name, name).map(|()| self)
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.name)
}
#[inline]
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn format(mut self, format: PipelineExecutableStatisticFormatKHR) -> Self {
@ -28340,12 +28432,8 @@ impl fmt::Debug for PipelineExecutableInternalRepresentationKHR<'_> {
fmt.debug_struct("PipelineExecutableInternalRepresentationKHR")
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("name", &unsafe {
::std::ffi::CStr::from_ptr(self.name.as_ptr())
})
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("name", &unsafe { self.name_as_c_str() })
.field("description", &unsafe { self.description_as_c_str() })
.field("is_text", &self.is_text)
.field("data_size", &self.data_size)
.field("p_data", &self.p_data)
@ -28373,14 +28461,26 @@ unsafe impl<'a> TaggedStructure for PipelineExecutableInternalRepresentationKHR<
}
impl<'a> PipelineExecutableInternalRepresentationKHR<'a> {
#[inline]
pub fn name(mut self, name: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.name = name;
self
pub fn name(
mut self,
name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.name, name).map(|()| self)
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.name)
}
#[inline]
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn is_text(mut self, is_text: bool) -> Self {
@ -29848,12 +29948,8 @@ impl fmt::Debug for PhysicalDeviceVulkan12Properties<'_> {
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("driver_id", &self.driver_id)
.field("driver_name", &unsafe {
::std::ffi::CStr::from_ptr(self.driver_name.as_ptr())
})
.field("driver_info", &unsafe {
::std::ffi::CStr::from_ptr(self.driver_info.as_ptr())
})
.field("driver_name", &unsafe { self.driver_name_as_c_str() })
.field("driver_info", &unsafe { self.driver_info_as_c_str() })
.field("conformance_version", &self.conformance_version)
.field(
"denorm_behavior_independence",
@ -30117,14 +30213,26 @@ impl<'a> PhysicalDeviceVulkan12Properties<'a> {
self
}
#[inline]
pub fn driver_name(mut self, driver_name: [c_char; MAX_DRIVER_NAME_SIZE]) -> Self {
self.driver_name = driver_name;
self
pub fn driver_name(
mut self,
driver_name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.driver_name, driver_name).map(|()| self)
}
#[inline]
pub fn driver_info(mut self, driver_info: [c_char; MAX_DRIVER_INFO_SIZE]) -> Self {
self.driver_info = driver_info;
self
pub unsafe fn driver_name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.driver_name)
}
#[inline]
pub fn driver_info(
mut self,
driver_info: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.driver_info, driver_info).map(|()| self)
}
#[inline]
pub unsafe fn driver_info_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.driver_info)
}
#[inline]
pub fn conformance_version(mut self, conformance_version: ConformanceVersion) -> Self {
@ -31204,19 +31312,11 @@ impl fmt::Debug for PhysicalDeviceToolProperties<'_> {
fmt.debug_struct("PhysicalDeviceToolProperties")
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("name", &unsafe {
::std::ffi::CStr::from_ptr(self.name.as_ptr())
})
.field("version", &unsafe {
::std::ffi::CStr::from_ptr(self.version.as_ptr())
})
.field("name", &unsafe { self.name_as_c_str() })
.field("version", &unsafe { self.version_as_c_str() })
.field("purposes", &self.purposes)
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("layer", &unsafe {
::std::ffi::CStr::from_ptr(self.layer.as_ptr())
})
.field("description", &unsafe { self.description_as_c_str() })
.field("layer", &unsafe { self.layer_as_c_str() })
.finish()
}
}
@ -31240,14 +31340,26 @@ unsafe impl<'a> TaggedStructure for PhysicalDeviceToolProperties<'a> {
}
impl<'a> PhysicalDeviceToolProperties<'a> {
#[inline]
pub fn name(mut self, name: [c_char; MAX_EXTENSION_NAME_SIZE]) -> Self {
self.name = name;
self
pub fn name(
mut self,
name: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.name, name).map(|()| self)
}
#[inline]
pub fn version(mut self, version: [c_char; MAX_EXTENSION_NAME_SIZE]) -> Self {
self.version = version;
self
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.name)
}
#[inline]
pub fn version(
mut self,
version: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.version, version).map(|()| self)
}
#[inline]
pub unsafe fn version_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.version)
}
#[inline]
pub fn purposes(mut self, purposes: ToolPurposeFlags) -> Self {
@ -31255,14 +31367,26 @@ impl<'a> PhysicalDeviceToolProperties<'a> {
self
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub fn layer(mut self, layer: [c_char; MAX_EXTENSION_NAME_SIZE]) -> Self {
self.layer = layer;
self
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn layer(
mut self,
layer: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.layer, layer).map(|()| self)
}
#[inline]
pub unsafe fn layer_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.layer)
}
}
#[repr(C)]
@ -41397,10 +41521,14 @@ impl<'a> CuFunctionCreateInfoNVX<'a> {
self
}
#[inline]
pub fn name(mut self, name: &'a ::std::ffi::CStr) -> Self {
pub fn name(mut self, name: &'a std::ffi::CStr) -> Self {
self.p_name = name.as_ptr();
self
}
#[inline]
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_name)
}
}
#[repr(C)]
#[cfg_attr(feature = "debug", derive(Debug))]
@ -43812,10 +43940,14 @@ impl<'a> CudaFunctionCreateInfoNV<'a> {
self
}
#[inline]
pub fn name(mut self, name: &'a ::std::ffi::CStr) -> Self {
pub fn name(mut self, name: &'a std::ffi::CStr) -> Self {
self.p_name = name.as_ptr();
self
}
#[inline]
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_name)
}
}
#[repr(C)]
#[cfg_attr(feature = "debug", derive(Debug))]
@ -45685,9 +45817,7 @@ impl fmt::Debug for RenderPassSubpassFeedbackInfoEXT {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("RenderPassSubpassFeedbackInfoEXT")
.field("subpass_merge_status", &self.subpass_merge_status)
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("description", &unsafe { self.description_as_c_str() })
.field("post_merge_index", &self.post_merge_index)
.finish()
}
@ -45709,9 +45839,15 @@ impl RenderPassSubpassFeedbackInfoEXT {
self
}
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn post_merge_index(mut self, post_merge_index: u32) -> Self {
@ -48456,9 +48592,7 @@ pub struct DeviceFaultVendorInfoEXT {
impl fmt::Debug for DeviceFaultVendorInfoEXT {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("DeviceFaultVendorInfoEXT")
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("description", &unsafe { self.description_as_c_str() })
.field("vendor_fault_code", &self.vendor_fault_code)
.field("vendor_fault_data", &self.vendor_fault_data)
.finish()
@ -48476,9 +48610,15 @@ impl ::std::default::Default for DeviceFaultVendorInfoEXT {
}
impl DeviceFaultVendorInfoEXT {
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn vendor_fault_code(mut self, vendor_fault_code: u64) -> Self {
@ -48554,9 +48694,7 @@ impl fmt::Debug for DeviceFaultInfoEXT<'_> {
fmt.debug_struct("DeviceFaultInfoEXT")
.field("s_type", &self.s_type)
.field("p_next", &self.p_next)
.field("description", &unsafe {
::std::ffi::CStr::from_ptr(self.description.as_ptr())
})
.field("description", &unsafe { self.description_as_c_str() })
.field("p_address_infos", &self.p_address_infos)
.field("p_vendor_infos", &self.p_vendor_infos)
.field("p_vendor_binary_data", &self.p_vendor_binary_data)
@ -48582,9 +48720,15 @@ unsafe impl<'a> TaggedStructure for DeviceFaultInfoEXT<'a> {
}
impl<'a> DeviceFaultInfoEXT<'a> {
#[inline]
pub fn description(mut self, description: [c_char; MAX_DESCRIPTION_SIZE]) -> Self {
self.description = description;
self
pub fn description(
mut self,
description: &std::ffi::CStr,
) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.description, description).map(|()| self)
}
#[inline]
pub unsafe fn description_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.description)
}
#[inline]
pub fn address_infos(mut self, address_infos: &'a mut DeviceFaultAddressInfoEXT) -> Self {
@ -50311,11 +50455,15 @@ impl<'a> ShaderCreateInfoEXT<'a> {
self
}
#[inline]
pub fn name(mut self, name: &'a ::std::ffi::CStr) -> Self {
pub fn name(mut self, name: &'a std::ffi::CStr) -> Self {
self.p_name = name.as_ptr();
self
}
#[inline]
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_name)
}
#[inline]
pub fn set_layouts(mut self, set_layouts: &'a [DescriptorSetLayout]) -> Self {
self.set_layout_count = set_layouts.len() as _;
self.p_set_layouts = set_layouts.as_ptr();
@ -51105,11 +51253,15 @@ unsafe impl<'a> TaggedStructure for PipelineShaderStageNodeCreateInfoAMDX<'a> {
unsafe impl ExtendsPipelineShaderStageCreateInfo for PipelineShaderStageNodeCreateInfoAMDX<'_> {}
impl<'a> PipelineShaderStageNodeCreateInfoAMDX<'a> {
#[inline]
pub fn name(mut self, name: &'a ::std::ffi::CStr) -> Self {
pub fn name(mut self, name: &'a std::ffi::CStr) -> Self {
self.p_name = name.as_ptr();
self
}
#[inline]
pub unsafe fn name_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.p_name)
}
#[inline]
pub fn index(mut self, index: u32) -> Self {
self.index = index;
self

View file

@ -1,3 +1,6 @@
use std::fmt;
use std::os::raw::c_char;
use crate::vk;
/// Holds 24 bits in the least significant bits of memory,
@ -59,3 +62,43 @@ impl From<vk::Extent2D> for vk::Rect2D {
pub unsafe trait TaggedStructure {
const STRUCTURE_TYPE: vk::StructureType;
}
#[inline]
pub(crate) unsafe fn wrap_c_str_slice_until_nul(str: &[c_char]) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(str.as_ptr())
}
#[derive(Debug)]
pub struct CStrTooLargeForStaticArray {
pub static_array_size: usize,
pub c_str_size: usize,
}
impl std::error::Error for CStrTooLargeForStaticArray {}
impl fmt::Display for CStrTooLargeForStaticArray {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"static `c_char` target array of length `{}` is too small to write a `CStr` (with `NUL`-terminator) of length `{}`",
self.static_array_size, self.c_str_size
)
}
}
#[inline]
pub(crate) fn write_c_str_slice_with_nul(
target: &mut [c_char],
str: &std::ffi::CStr,
) -> Result<(), CStrTooLargeForStaticArray> {
let bytes = str.to_bytes_with_nul();
// SAFETY: The cast from c_char to u8 is ok because a c_char is always one byte.
let bytes = unsafe { std::slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len()) };
let static_array_size = target.len();
target
.get_mut(..bytes.len())
.ok_or(CStrTooLargeForStaticArray {
static_array_size,
c_str_size: bytes.len(),
})?
.copy_from_slice(bytes);
Ok(())
}

View file

@ -1822,25 +1822,16 @@ fn derive_debug(
let param_ident = field.param_ident();
let param_str = param_ident.to_string();
let debug_value = if is_static_array(field) && field.basetype == "char" {
quote! {
&unsafe {
::std::ffi::CStr::from_ptr(self.#param_ident.as_ptr())
}
}
let param_ident = format_ident!("{}_as_c_str", param_ident);
quote!(&unsafe { self.#param_ident() })
} else if param_str.contains("pfn") {
quote! {
&(self.#param_ident.map(|x| x as *const ()))
}
quote!(&(self.#param_ident.map(|x| x as *const ())))
} else if union_types.contains(field.basetype.as_str()) {
quote!(&"union")
} else {
quote! {
&self.#param_ident
}
quote!(&self.#param_ident)
};
quote! {
.field(#param_str, #debug_value)
}
quote!(.field(#param_str, #debug_value))
});
let name_str = name.to_string();
let lifetime = has_lifetime.then(|| quote!(<'_>));
@ -1989,83 +1980,103 @@ fn derive_setters(
});
}
// TODO: Improve in future when https://github.com/rust-lang/rust/issues/53667 is merged id:6
if field.reference.is_some() {
if field.basetype == "char" && matches!(field.reference, Some(vkxml::ReferenceType::Pointer)) {
if field.basetype == "char" {
let param_ident_as_c_str = format_ident!("{}_as_c_str", param_ident_short);
if matches!(field.reference, Some(vkxml::ReferenceType::Pointer)) {
assert!(field.null_terminate);
assert_eq!(field.size, None);
return Some(quote!{
return Some(quote! {
#[inline]
#deprecated
pub fn #param_ident_short(mut self, #param_ident_short: &'a ::std::ffi::CStr) -> Self {
pub fn #param_ident_short(mut self, #param_ident_short: &'a std::ffi::CStr) -> Self {
self.#param_ident = #param_ident_short.as_ptr();
self
}
#[inline]
#deprecated
pub unsafe fn #param_ident_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.#param_ident)
}
});
} else if is_static_array(field) {
assert_eq!(field.size, None);
return Some(quote! {
#[inline]
#deprecated
pub fn #param_ident_short(mut self, #param_ident_short: &std::ffi::CStr) -> std::result::Result<Self, CStrTooLargeForStaticArray> {
write_c_str_slice_with_nul(&mut self.#param_ident, #param_ident_short).map(|()| self)
}
#[inline]
#deprecated
pub unsafe fn #param_ident_as_c_str(&self) -> &std::ffi::CStr {
wrap_c_str_slice_until_nul(&self.#param_ident)
}
});
}
}
if matches!(field.array, Some(vkxml::ArrayType::Dynamic)) {
if let Some(ref array_size) = field.size {
let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a), type_lifetime.clone(), None);
// TODO: Improve in future when https://github.com/rust-lang/rust/issues/53667 is merged id:6
if field.reference.is_some() && matches!(field.array, Some(vkxml::ArrayType::Dynamic)) {
if let Some(ref array_size) = field.size {
let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a), type_lifetime.clone(), None);
let mut ptr = if field.is_const {
quote!(.as_ptr())
} else {
quote!(.as_mut_ptr())
};
let mut ptr = if field.is_const {
quote!(.as_ptr())
} else {
quote!(.as_mut_ptr())
};
// Interpret void array as byte array
if field.basetype == "void" && matches!(field.reference, Some(vkxml::ReferenceType::Pointer)) {
slice_param_ty_tokens = quote!([u8]);
// Interpret void array as byte array
if field.basetype == "void" && matches!(field.reference, Some(vkxml::ReferenceType::Pointer)) {
slice_param_ty_tokens = quote!([u8]);
ptr = quote!(#ptr.cast());
};
let set_size_stmt = if field.is_pointer_to_static_sized_array() {
// this is a pointer to a piece of memory with statically known size.
let array_size = field.c_size.as_ref().unwrap();
let c_size = convert_c_expression(array_size, &BTreeMap::new());
let inner_type = field.inner_type_tokens(None, None);
slice_param_ty_tokens = quote!([#inner_type; #c_size]);
ptr = quote!();
quote!()
} 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), type_lifetime.clone(), Some(1));
ptr = quote!(#ptr.cast());
array_size
} else {
array_size
};
let set_size_stmt = if field.is_pointer_to_static_sized_array() {
// this is a pointer to a piece of memory with statically known size.
let array_size = field.c_size.as_ref().unwrap();
let c_size = convert_c_expression(array_size, &BTreeMap::new());
let inner_type = field.inner_type_tokens(None, None);
let array_size_ident = format_ident!("{}", array_size.to_snake_case());
slice_param_ty_tokens = quote!([#inner_type; #c_size]);
ptr = quote!();
let size_field = members.iter().find(|member| member.vkxml_field.name.as_deref() == Some(array_size)).unwrap();
let cast = if size_field.vkxml_field.basetype == "size_t" {
quote!()
} 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), type_lifetime.clone(), Some(1));
ptr = quote!(#ptr.cast());
array_size
} else {
array_size
};
let array_size_ident = format_ident!("{}", array_size.to_snake_case());
let size_field = members.iter().find(|member| member.vkxml_field.name.as_deref() == Some(array_size)).unwrap();
let cast = if size_field.vkxml_field.basetype == "size_t" {
quote!()
} else {
quote!(as _)
};
quote!(self.#array_size_ident = #param_ident_short.len()#cast;)
quote!(as _)
};
let mutable = if field.is_const { quote!() } else { quote!(mut) };
quote!(self.#array_size_ident = #param_ident_short.len()#cast;)
};
return Some(quote! {
#[inline]
#deprecated
pub fn #param_ident_short(mut self, #param_ident_short: &'a #mutable #slice_param_ty_tokens) -> Self {
#set_size_stmt
self.#param_ident = #param_ident_short #ptr;
self
}
});
}
let mutable = if field.is_const { quote!() } else { quote!(mut) };
return Some(quote! {
#[inline]
#deprecated
pub fn #param_ident_short(mut self, #param_ident_short: &'a #mutable #slice_param_ty_tokens) -> Self {
#set_size_stmt
self.#param_ident = #param_ident_short #ptr;
self
}
});
}
}