aboutsummaryrefslogtreecommitdiff
path: root/src/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/macros.rs')
-rw-r--r--src/macros.rs947
1 files changed, 947 insertions, 0 deletions
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..ee57133
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,947 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+macro_rules! vulkan_bitflags {
+ {
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident,
+ )+
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, PartialEq, Eq, Hash)]
+ pub struct $ty($repr);
+
+ impl $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ pub const $flag_name: Self = Self(ash::vk::$ty_ffi::$flag_name_ffi.as_raw());
+ )*
+
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+
+ #[doc = concat!("Returns a `", stringify!($ty), "` with all of the flags set.")]
+ #[inline]
+ pub const fn all() -> Self {
+ Self(Self::all_raw())
+ }
+
+ const fn all_raw() -> $repr {
+ 0
+ $(
+ | ash::vk::$ty_ffi::$flag_name_ffi.as_raw()
+ )*
+ }
+
+ /// Returns whether no flags are set in `self`.
+ #[inline]
+ pub const fn is_empty(self) -> bool {
+ self.0 == 0
+ }
+
+ /// Returns whether any flags are set in both `self` and `other`.
+ #[inline]
+ pub const fn intersects(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 != 0
+ }
+
+ /// Returns whether all flags in `other` are set in `self`.
+ #[inline]
+ pub const fn contains(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 == other.0
+ }
+
+ /// Returns the union of `self` and `other`.
+ #[inline]
+ pub const fn union(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 | other.0)
+ }
+
+ /// Returns the intersection of `self` and `other`.
+ #[inline]
+ pub const fn intersection(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & other.0)
+ }
+
+ /// Returns `self` without the flags set in `other`.
+ #[inline]
+ pub const fn difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & !other.0)
+ }
+
+ /// Returns the flags that are set in `self` or `other`, but not in both.
+ #[inline]
+ pub const fn symmetric_difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 ^ other.0)
+ }
+
+ /// Returns the flags not in `self`.
+ #[inline]
+ pub const fn complement(self) -> Self {
+ Self(!self.0 & Self::all_raw())
+ }
+
+ $( $($impls)* )?
+ }
+
+ impl Default for $ty {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+ }
+
+ impl std::fmt::Debug for $ty {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ #[allow(unused_mut)]
+ let mut written = false;
+
+ $(
+ if self.intersects(Self::$flag_name) {
+ if written {
+ write!(f, " | ")?;
+ }
+
+ write!(f, stringify!($flag_name))?;
+ written = true;
+ }
+ )*
+
+ if !written {
+ write!(f, "empty()")?;
+ }
+
+ Ok(())
+ }
+ }
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val.0)
+ }
+ }
+
+ impl From<ash::vk::$ty_ffi> for $ty {
+ #[inline]
+ fn from(val: ash::vk::$ty_ffi) -> Self {
+ Self(val.as_raw() & Self::all_raw())
+ }
+ }
+
+ impl std::ops::BitAnd for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ self.intersection(rhs)
+ }
+ }
+
+ impl std::ops::BitAndAssign for $ty {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(rhs);
+ }
+ }
+
+ impl std::ops::BitOr for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ self.union(rhs)
+ }
+ }
+
+ impl std::ops::BitOrAssign for $ty {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(rhs);
+ }
+ }
+
+ impl std::ops::BitXor for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self {
+ self.symmetric_difference(rhs)
+ }
+ }
+
+ impl std::ops::BitXorAssign for $ty {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(rhs);
+ }
+ }
+
+ impl std::ops::Sub for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ self.difference(rhs)
+ }
+ }
+
+ impl std::ops::SubAssign for $ty {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(rhs);
+ }
+ }
+
+ impl std::ops::Not for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn not(self) -> Self {
+ self.complement()
+ }
+ }
+ };
+
+ {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident
+ $({
+ $(api_version: $api_version:ident,)?
+ $(features: [$($feature:ident),+ $(,)?],)?
+ $(device_extensions: [$($device_extension:ident),+ $(,)?],)?
+ $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
+ })?
+ ,
+ )*
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, PartialEq, Eq, Hash)]
+ pub struct $ty($repr);
+
+ impl $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ pub const $flag_name: Self = Self(ash::vk::$ty_ffi::$flag_name_ffi.as_raw());
+ )*
+
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+
+ const fn all_raw() -> $repr {
+ 0
+ $(
+ | ash::vk::$ty_ffi::$flag_name_ffi.as_raw()
+ )*
+ }
+
+ /// Returns the number of flags set in self.
+ #[inline]
+ pub const fn count(self) -> u32 {
+ self.0.count_ones()
+ }
+
+ /// Returns whether no flags are set in `self`.
+ #[inline]
+ pub const fn is_empty(self) -> bool {
+ self.0 == 0
+ }
+
+ /// Returns whether any flags are set in both `self` and `other`.
+ #[inline]
+ pub const fn intersects(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 != 0
+ }
+
+ /// Returns whether all flags in `other` are set in `self`.
+ #[inline]
+ pub const fn contains(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 == other.0
+ }
+
+ /// Returns the union of `self` and `other`.
+ #[inline]
+ pub const fn union(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 | other.0)
+ }
+
+ /// Returns the intersection of `self` and `other`.
+ #[inline]
+ pub const fn intersection(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & other.0)
+ }
+
+ /// Returns `self` without the flags set in `other`.
+ #[inline]
+ pub const fn difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & !other.0)
+ }
+
+ /// Returns the flags that are set in `self` or `other`, but not in both.
+ #[inline]
+ pub const fn symmetric_difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 ^ other.0)
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_device(
+ self,
+ #[allow(unused_variables)] device: &crate::device::Device,
+ ) -> Result<(), crate::RequirementNotMet> {
+ $(
+ $(
+ if self.intersects(Self::$flag_name) && ![
+ $(
+ device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ device.enabled_features().$feature,
+ )+)?
+ $($(
+ device.enabled_extensions().$device_extension,
+ )+)?
+ $($(
+ device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ )?
+ )*
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_physical_device(
+ self,
+ #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
+ ) -> Result<(), crate::RequirementNotMet> {
+ $(
+ $(
+ if self.intersects(Self::$flag_name) && ![
+ $(
+ physical_device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ physical_device.supported_features().$feature,
+ )+)?
+ $($(
+ physical_device.supported_extensions().$device_extension,
+ )+)?
+ $($(
+ physical_device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ )?
+ )*
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_instance(
+ self,
+ #[allow(unused_variables)] instance: &crate::instance::Instance,
+ ) -> Result<(), crate::RequirementNotMet> {
+ $(
+ $(
+ if self.intersects(Self::$flag_name) && ![
+ $(
+ instance.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ instance.enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ )?
+ )*
+
+ Ok(())
+ }
+
+ $( $($impls)* )?
+ }
+
+ impl Default for $ty {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+ }
+
+ impl std::fmt::Debug for $ty {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ #[allow(unused_mut)]
+ let mut written = false;
+
+ $(
+ if self.intersects(Self::$flag_name) {
+ if written {
+ write!(f, " | ")?;
+ }
+
+ write!(f, stringify!($flag_name))?;
+ written = true;
+ }
+ )*
+
+ if !written {
+ write!(f, "empty()")?;
+ }
+
+ Ok(())
+ }
+ }
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val.0)
+ }
+ }
+
+ impl From<ash::vk::$ty_ffi> for $ty {
+ #[inline]
+ fn from(val: ash::vk::$ty_ffi) -> Self {
+ Self(val.as_raw() & Self::all_raw())
+ }
+ }
+
+ impl std::ops::BitAnd for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ self.intersection(rhs)
+ }
+ }
+
+ impl std::ops::BitAndAssign for $ty {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(rhs);
+ }
+ }
+
+ impl std::ops::BitOr for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ self.union(rhs)
+ }
+ }
+
+ impl std::ops::BitOrAssign for $ty {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(rhs);
+ }
+ }
+
+ impl std::ops::BitXor for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self {
+ self.symmetric_difference(rhs)
+ }
+ }
+
+ impl std::ops::BitXorAssign for $ty {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(rhs);
+ }
+ }
+
+ impl std::ops::Sub for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ self.difference(rhs)
+ }
+ }
+
+ impl std::ops::SubAssign for $ty {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(rhs);
+ }
+ }
+ };
+}
+
+macro_rules! vulkan_enum {
+ {
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident,
+ )+
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[repr($repr)]
+ pub enum $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
+ )+
+ }
+
+ $(
+ impl $ty {
+ $($impls)*
+ }
+ )?
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val as $repr)
+ }
+ }
+
+ impl TryFrom<ash::vk::$ty_ffi> for $ty {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
+ Ok(match val {
+ $(
+ ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
+ )+
+ _ => return Err(()),
+ })
+ }
+ }
+ };
+
+ {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident
+ $({
+ $(api_version: $api_version:ident,)?
+ $(features: [$($feature:ident),+ $(,)?],)?
+ $(device_extensions: [$($device_extension:ident),+ $(,)?],)?
+ $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
+ })?
+ ,
+ )+
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[non_exhaustive]
+ #[repr($repr)]
+ pub enum $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
+ )+
+ }
+
+ impl $ty {
+ #[allow(dead_code)]
+ pub(crate) fn validate_device(
+ self,
+ #[allow(unused_variables)] device: &crate::device::Device,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ $(
+ $(
+ Self::$flag_name => {
+ if ![
+ $(
+ device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ device.enabled_features().$feature,
+ )+)?
+ $($(
+ device.enabled_extensions().$device_extension,
+ )+)?
+ $($(
+ device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ },
+ )?
+ )+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_physical_device(
+ self,
+ #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ $(
+ $(
+ Self::$flag_name => {
+ if ![
+ $(
+ physical_device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ physical_device.supported_features().$feature,
+ )+)?
+ $($(
+ physical_device.supported_extensions().$device_extension,
+ )+)?
+ $($(
+ physical_device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ },
+ )?
+ )+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_instance(
+ self,
+ #[allow(unused_variables)] instance: &crate::instance::Instance,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ $(
+ $(
+ Self::$flag_name => {
+ if ![
+ $(
+ instance.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ instance.enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ },
+ )?
+ )+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ $(
+ $($impls)*
+ )?
+ }
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val as $repr)
+ }
+ }
+
+ impl TryFrom<ash::vk::$ty_ffi> for $ty {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
+ Ok(match val {
+ $(
+ ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
+ )+
+ _ => return Err(()),
+ })
+ }
+ }
+ };
+}
+
+macro_rules! vulkan_bitflags_enum {
+ {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_bitflags_doc:literal])*
+ $ty_bitflags:ident
+ $( impl { $($impls_bitflags:item)* } )?
+ ,
+
+ $(#[doc = $ty_enum_doc:literal])*
+ $ty_enum:ident
+ $( impl { $($impls_enum:item)* } )?
+ ,
+
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name_bitflags:ident, $flag_name_enum:ident = $flag_name_ffi:ident
+ $({
+ $(api_version: $api_version:ident,)?
+ $(features: [$($feature:ident),+ $(,)?],)?
+ $(device_extensions: [$($device_extension:ident),+ $(,)?],)?
+ $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
+ })?
+ ,
+ )*
+ } => {
+ crate::macros::vulkan_bitflags! {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_bitflags_doc])*
+ $ty_bitflags
+ impl {
+ /// Returns whether `self` contains the flag corresponding to `val`.
+ #[inline]
+ pub fn contains_enum(self, val: $ty_enum) -> bool {
+ self.intersects(val.into())
+ }
+
+ $( $($impls_bitflags)* )?
+ }
+ = $ty_ffi($repr);
+
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name_bitflags = $flag_name_ffi
+ $({
+ $(api_version: $api_version,)?
+ $(features: [$($feature),+],)?
+ $(device_extensions: [$($device_extension),+],)?
+ $(instance_extensions: [$($instance_extension),+],)?
+ })?
+ ,
+ )*
+ }
+
+ crate::macros::vulkan_enum! {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_enum_doc])*
+ $ty_enum
+ $( impl { $($impls_enum)* } )?
+ = $ty_ffi($repr);
+
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name_enum = $flag_name_ffi
+ $({
+ $(api_version: $api_version,)?
+ $(features: [$($feature),+],)?
+ $(device_extensions: [$($device_extension),+],)?
+ $(instance_extensions: [$($instance_extension),+],)?
+ })?
+ ,
+ )*
+ }
+
+ impl From<$ty_enum> for $ty_bitflags {
+ #[inline]
+ fn from(val: $ty_enum) -> Self {
+ Self(val as $repr)
+ }
+ }
+
+ impl FromIterator<$ty_enum> for $ty_bitflags {
+ #[inline]
+ fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = $ty_enum> {
+ iter.into_iter().map(|item| Self::from(item)).fold(Self::empty(), |r, i| r.union(i))
+ }
+ }
+
+ impl IntoIterator for $ty_bitflags {
+ type Item = $ty_enum;
+ type IntoIter = std::iter::Flatten<
+ std::array::IntoIter<
+ Option<Self::Item>,
+ { $ty_bitflags::all_raw().count_ones() as usize },
+ >
+ >;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [
+ $(
+ self.intersects(Self::$flag_name_bitflags)
+ .then_some($ty_enum::$flag_name_enum),
+ )*
+ ].into_iter().flatten()
+ }
+ }
+ }
+}
+
+macro_rules! impl_id_counter {
+ ($type:ident $(< $($param:ident $(: $bound:ident $(+ $bounds:ident)* )?),+ >)?) => {
+ $crate::macros::impl_id_counter!(
+ @inner $type $(< $($param),+ >)?, $( $($param $(: $bound $(+ $bounds)* )?),+)?
+ );
+ };
+ ($type:ident $(< $($param:ident $(: $bound:ident $(+ $bounds:ident)* )? + ?Sized),+ >)?) => {
+ $crate::macros::impl_id_counter!(
+ @inner $type $(< $($param),+ >)?, $( $($param $(: $bound $(+ $bounds)* )? + ?Sized),+)?
+ );
+ };
+ (@inner $type:ident $(< $($param:ident),+ >)?, $($bounds:tt)*) => {
+ impl< $($bounds)* > $type $(< $($param),+ >)? {
+ fn next_id() -> std::num::NonZeroU64 {
+ use std::{
+ num::NonZeroU64,
+ sync::atomic::{AtomicU64, Ordering},
+ };
+
+ static COUNTER: AtomicU64 = AtomicU64::new(1);
+
+ NonZeroU64::new(COUNTER.fetch_add(1, Ordering::Relaxed)).unwrap_or_else(|| {
+ println!("an ID counter has overflown ...somehow");
+ std::process::abort();
+ })
+ }
+ }
+
+ impl< $($bounds)* > PartialEq for $type $(< $($param),+ >)? {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.id == other.id
+ }
+ }
+
+ impl< $($bounds)* > Eq for $type $(< $($param),+ >)? {}
+
+ impl< $($bounds)* > std::hash::Hash for $type $(< $($param),+ >)? {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.id.hash(state);
+ }
+ }
+ };
+}
+
+// TODO: Replace with the `?` operator once its constness is stabilized.
+macro_rules! try_opt {
+ ($e:expr) => {
+ if let Some(val) = $e {
+ val
+ } else {
+ return None;
+ }
+ };
+}
+
+pub(crate) use {impl_id_counter, try_opt, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum};