use core::ffi::c_char; use core::fmt; use crate::vk; /// Holds 24 bits in the least significant bits of memory, /// and 8 bytes in the most significant bits of that memory, /// occupying a single [`u32`] in total. This is commonly used in /// [acceleration structure instances] such as /// [`vk::AccelerationStructureInstanceKHR`], /// [`vk::AccelerationStructureSRTMotionInstanceNV`] and /// [`vk::AccelerationStructureMatrixMotionInstanceNV`]. /// /// [acceleration structure instances]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureInstanceKHR.html#_description #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] #[repr(transparent)] pub struct Packed24_8(u32); impl Packed24_8 { pub fn new(low_24: u32, high_8: u8) -> Self { Self((low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24)) } /// Extracts the least-significant 24 bits (3 bytes) of this integer pub fn low_24(&self) -> u32 { self.0 & 0xffffff } /// Extracts the most significant 8 bits (single byte) of this integer pub fn high_8(&self) -> u8 { (self.0 >> 24) as u8 } } impl vk::ColorComponentFlags { /// Contraction of [`R`][Self::R] | [`G`][Self::G] | [`B`][Self::B] | [`A`][Self::A] pub const RGBA: Self = Self(Self::R.0 | Self::G.0 | Self::B.0 | Self::A.0); } impl From for vk::Extent3D { fn from(value: vk::Extent2D) -> Self { Self { width: value.width, height: value.height, depth: 1, } } } impl From for vk::Rect2D { fn from(extent: vk::Extent2D) -> Self { Self { offset: Default::default(), extent, } } } /// Structures implementing this trait are layout-compatible with [`vk::BaseInStructure`] and /// [`vk::BaseOutStructure`]. Such structures have an `s_type` field indicating its type, which /// must always match the value of [`TaggedStructure::STRUCTURE_TYPE`]. pub unsafe trait TaggedStructure { const STRUCTURE_TYPE: vk::StructureType; } #[inline] pub(crate) fn wrap_c_str_slice_until_nul( str: &[c_char], ) -> Result<&core::ffi::CStr, core::ffi::FromBytesUntilNulError> { // SAFETY: The cast from c_char to u8 is ok because a c_char is always one byte. let bytes = unsafe { core::slice::from_raw_parts(str.as_ptr().cast(), str.len()) }; core::ffi::CStr::from_bytes_until_nul(bytes) } #[derive(Debug)] pub struct CStrTooLargeForStaticArray { pub static_array_size: usize, pub c_str_size: usize, } #[cfg(feature = "std")] 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: &core::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 { core::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(()) }