Skip to main content

wgpu_types/
bitflags_array.rs

1macro_rules! bitflags_array_impl {
2        ($impl_name:ident $inner_name:ident $name:ident $op:tt $($struct_names:ident)*) => (
3            impl core::ops::$impl_name for $name {
4                type Output = Self;
5
6                #[inline]
7                fn $inner_name(self, other: Self) -> Self {
8                    Self {
9                        $($struct_names: self.$struct_names $op other.$struct_names,)*
10                    }
11                }
12            }
13        )
14    }
15pub(crate) use bitflags_array_impl;
16
17macro_rules! bitflags_array_impl_assign {
18        ($impl_name:ident $inner_name:ident $name:ident $op:tt $($struct_names:ident)*) => (
19            impl core::ops::$impl_name for $name {
20                #[inline]
21                fn $inner_name(&mut self, other: Self) {
22                    $(self.$struct_names $op other.$struct_names;)*
23                }
24            }
25        )
26    }
27pub(crate) use bitflags_array_impl_assign;
28
29macro_rules! bit_array_impl {
30        ($impl_name:ident $inner_name:ident $name:ident $op:tt) => (
31            impl core::ops::$impl_name for $name {
32                type Output = Self;
33
34                #[inline]
35                fn $inner_name(mut self, other: Self) -> Self {
36                    for (inner, other) in self.0.iter_mut().zip(other.0.iter()) {
37                        *inner $op *other;
38                    }
39                    self
40                }
41            }
42        )
43    }
44pub(crate) use bit_array_impl;
45
46macro_rules! bitflags_independent_two_arg {
47        ($(#[$meta:meta])* $func_name:ident $($struct_names:ident)*) => (
48            $(#[$meta])*
49            pub const fn $func_name(self, other:Self) -> Self {
50                Self { $($struct_names: self.$struct_names.$func_name(other.$struct_names),)* }
51            }
52        )
53    }
54pub(crate) use bitflags_independent_two_arg;
55
56// For the most part this macro should not be modified, most configuration should be possible
57// without changing this macro.
58/// Macro for creating sets of bitflags, we need this because there are almost more flags than bits
59/// in a u64, we can't use a u128 because of FFI, and the number of flags is increasing.
60///
61/// Alternatively we also want to separate WebGPU features from native WGPU features.
62macro_rules! bitflags_array {
63        (
64            $(#[$outer:meta])*
65            pub struct ($name:ident, $name_bits:ident): [$T:ty; $Len:expr];
66
67            $(
68                $(#[$bit_outer:meta])*
69                $vis:vis struct $inner_name:ident $lower_inner_name:ident {
70                    $(
71                        $(#[doc $($args:tt)*])*
72                        #[name($str_name:literal $(, $alias:literal)*)]
73                        const $Flag:tt = $value:expr;
74                    )*
75                }
76            )*
77        ) => {
78            crate::bitflags_array! {
79                $(#[$outer])*
80                pub struct ($name, $name_bits): [$T; $Len];
81
82                $(
83                    $(#[$bit_outer])*
84                    $vis struct $inner_name $lower_inner_name {
85                        $(
86                            $(#[doc $($args)*])*
87                            const $Flag = $value;
88                        )*
89                    }
90                )*
91            }
92
93            // Parses kebab-case feature names (i.e. the names given in the spec, for features
94            // in FeaturesWebGPU, and otherwise the `wgpu-` prefixed names).
95            impl FromStr for $name {
96                type Err = ();
97
98                fn from_str(s: &str) -> Result<Self, Self::Err> {
99                    Ok(match s {
100                        $($($str_name $(| $alias)* => Self::$Flag,)*)*
101                        _ => return Err(()),
102                    })
103                }
104            }
105
106            impl $name {
107                #[doc = concat!("If the argument is a single [`", stringify!($name), "`] flag,")]
108                /// returns the corresponding `kebab-case` flag name, otherwise `None`.
109                #[must_use]
110                pub fn as_str(&self) -> Option<&'static str> {
111                    Some(match *self {
112                        $($(Self::$Flag => $str_name,)*)*
113                        _ => return None,
114                    })
115                }
116            }
117        };
118        (
119            $(#[$outer:meta])*
120            pub struct ($name:ident, $name_bits:ident): [$T:ty; $Len:expr];
121
122            $(
123                $(#[$bit_outer:meta])*
124                $vis:vis struct $inner_name:ident $lower_inner_name:ident {
125                    $(
126                        $(#[doc $($args:tt)*])*
127                        const $Flag:tt = $value:expr;
128                    )*
129                }
130            )*
131        ) => {
132            $(
133                bitflags::bitflags! {
134                    $(#[$bit_outer])*
135                    $vis struct $inner_name: $T {
136                        $(
137                            $(#[doc $($args)*])*
138                            const $Flag = $value;
139                        )*
140                    }
141                }
142            )*
143
144            $(#[$outer])*
145            pub struct $name {
146                $(
147                    #[allow(missing_docs)]
148                    $vis $lower_inner_name: $inner_name,
149                )*
150            }
151
152            #[doc = concat!("Bits from [`", stringify!($name), "`] in array form")]
153            #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
154            #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
155            pub struct $name_bits(pub [$T; $Len]);
156
157            $crate::bitflags_array_impl! { BitOr bitor $name | $($lower_inner_name)* }
158            $crate::bitflags_array_impl! { BitAnd bitand $name & $($lower_inner_name)* }
159            $crate::bitflags_array_impl! { BitXor bitxor $name ^ $($lower_inner_name)* }
160            impl core::ops::Not for $name {
161                type Output = Self;
162
163                #[inline]
164                fn not(self) -> Self {
165                    Self {
166                    $($lower_inner_name: !self.$lower_inner_name,)*
167                    }
168                }
169            }
170            $crate::bitflags_array_impl! { Sub sub $name - $($lower_inner_name)* }
171
172            #[cfg(feature = "serde")]
173            impl Serialize for $name {
174                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
175                where
176                    S: serde::Serializer,
177                {
178                    bitflags::serde::serialize(self, serializer)
179                }
180            }
181
182            #[cfg(feature = "serde")]
183            impl<'de> Deserialize<'de> for $name {
184                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
185                where
186                    D: serde::Deserializer<'de>,
187                {
188                    bitflags::serde::deserialize(deserializer)
189                }
190            }
191
192            impl core::fmt::Display for $name {
193                fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194                    let mut iter = self.iter_names();
195                    // simple look ahead
196                    let mut next = iter.next();
197                    while let Some((name, _)) = next {
198                        f.write_str(name)?;
199                        next = iter.next();
200                        if next.is_some() {
201                            f.write_str(" | ")?;
202                        }
203                    }
204                    Ok(())
205                }
206            }
207
208            $crate::bitflags_array_impl_assign! { BitOrAssign bitor_assign $name |= $($lower_inner_name)* }
209            $crate::bitflags_array_impl_assign! { BitAndAssign bitand_assign $name &= $($lower_inner_name)* }
210            $crate::bitflags_array_impl_assign! { BitXorAssign bitxor_assign $name ^= $($lower_inner_name)* }
211
212            $crate::bit_array_impl! { BitOr bitor $name_bits |= }
213            $crate::bit_array_impl! { BitAnd bitand $name_bits &= }
214            $crate::bit_array_impl! { BitXor bitxor $name_bits ^= }
215
216            impl core::ops::Not for $name_bits {
217                type Output = Self;
218
219                #[inline]
220                fn not(self) -> Self {
221                    let [$($lower_inner_name,)*] = self.0;
222                    Self([$(!$lower_inner_name,)*])
223                }
224            }
225
226            #[cfg(feature = "serde")]
227            impl bitflags::parser::WriteHex for $name_bits {
228                fn write_hex<W: core::fmt::Write>(&self, mut writer: W) -> core::fmt::Result {
229                    let [$($lower_inner_name,)*] = self.0;
230                    let mut wrote = false;
231                    let mut stager = alloc::string::String::with_capacity(size_of::<$T>() * 2);
232                    // we don't want to write it if it's just zero as there may be multiple zeros
233                    // resulting in something like "00" being written out. We do want to write it if
234                    // there has already been something written though.
235                    $(if ($lower_inner_name != 0) || wrote {
236                        // First we write to a staging string, then we add any zeros (e.g if #1
237                        // is f and a u8 and #2 is a then the two combined would be f0a which requires
238                        // a 0 inserted)
239                        $lower_inner_name.write_hex(&mut stager)?;
240                        if (stager.len() != size_of::<$T>() * 2) && wrote {
241                            let zeros_to_write = (size_of::<$T>() * 2) - stager.len();
242                            for _ in 0..zeros_to_write {
243                                writer.write_char('0')?
244                            }
245                        }
246                        writer.write_str(&stager)?;
247                        stager.clear();
248                        wrote = true;
249                    })*
250                    if !wrote {
251                        writer.write_str("0")?;
252                    }
253                    Ok(())
254                }
255            }
256
257            #[cfg(feature = "serde")]
258            impl bitflags::parser::ParseHex for $name_bits {
259                fn parse_hex(input: &str) -> Result<Self, bitflags::parser::ParseError> {
260                    use bitflags::Bits;
261
262                    let mut unset = Self::EMPTY;
263                    let mut end = input.len();
264                    if end == 0 {
265                        return Err(bitflags::parser::ParseError::empty_flag())
266                    }
267                    // we iterate starting at the least significant places and going up
268                    for (idx, _) in [$(stringify!($lower_inner_name),)*].iter().enumerate().rev() {
269                        // A byte is two hex places - u8 (1 byte) = 0x00 (2 hex places).
270                        let checked_start = end.checked_sub(size_of::<$T>() * 2);
271                        let start = checked_start.unwrap_or(0);
272
273                        let cur_input = &input[start..end];
274                        unset.0[idx] = <$T>::from_str_radix(cur_input, 16)
275                            .map_err(|_|bitflags::parser::ParseError::invalid_hex_flag(cur_input))?;
276
277                        end = start;
278
279                        if let None = checked_start {
280                            break;
281                        }
282                    }
283                    Ok(unset)
284                }
285            }
286
287            impl bitflags::Bits for $name_bits {
288                const EMPTY: Self = $name::empty().bits();
289
290                const ALL: Self = $name::all().bits();
291            }
292
293            impl bitflags::Flags for $name {
294                const FLAGS: &'static [bitflags::Flag<Self>] = $name::FLAGS;
295
296                type Bits = $name_bits;
297
298                fn bits(&self) -> $name_bits {
299                    $name_bits([
300                        $(self.$lower_inner_name.bits(),)*
301                    ])
302                }
303
304                fn from_bits_retain(bits: $name_bits) -> Self {
305                    let [$($lower_inner_name,)*] = bits.0;
306                    Self {
307                        $($lower_inner_name: $inner_name::from_bits_retain($lower_inner_name),)*
308                    }
309                }
310
311                fn empty() -> Self {
312                    Self::empty()
313                }
314
315                fn all() -> Self {
316                    Self::all()
317                }
318            }
319
320            impl $name {
321                pub(crate) const FLAGS: &'static [bitflags::Flag<Self>] = &[
322                    $(
323                        $(
324                            bitflags::Flag::new(stringify!($Flag), $name::$Flag),
325                        )*
326                    )*
327                ];
328
329                /// Gets the set flags as a container holding an array of bits.
330                pub const fn bits(&self) -> $name_bits {
331                    $name_bits([
332                        $(self.$lower_inner_name.bits(),)*
333                    ])
334                }
335
336                /// Returns self with no flags set.
337                pub const fn empty() -> Self {
338                    Self {
339                        $($lower_inner_name: $inner_name::empty(),)*
340                    }
341                }
342
343                /// Returns self with all flags set.
344                pub const fn all() -> Self {
345                    Self {
346                        $($lower_inner_name: $inner_name::all(),)*
347                    }
348                }
349
350                /// Whether all the bits set in `other` are all set in `self`
351                pub const fn contains(self, other:Self) -> bool {
352                    // we need an annoying true to catch the last && >:(
353                    $(self.$lower_inner_name.contains(other.$lower_inner_name) &&)* true
354                }
355
356                /// Returns whether any bit set in `self` matched any bit set in `other`.
357                pub const fn intersects(self, other:Self) -> bool {
358                    $(self.$lower_inner_name.intersects(other.$lower_inner_name) ||)* false
359                }
360
361                /// Returns whether there is no flag set.
362                pub const fn is_empty(self) -> bool {
363                    $(self.$lower_inner_name.is_empty() &&)* true
364                }
365
366                /// Returns whether the struct has all flags set.
367                pub const fn is_all(self) -> bool {
368                    $(self.$lower_inner_name.is_all() &&)* true
369                }
370
371                $crate::bitflags_independent_two_arg! {
372                    /// Bitwise or - `self | other`
373                    union $($lower_inner_name)*
374                }
375
376                $crate::bitflags_independent_two_arg! {
377                    /// Bitwise and - `self & other`
378                    intersection $($lower_inner_name)*
379                }
380
381                $crate::bitflags_independent_two_arg! {
382                    /// Bitwise and of the complement of other - `self & !other`
383                    difference $($lower_inner_name)*
384                }
385
386                $crate::bitflags_independent_two_arg! {
387                    /// Bitwise xor - `self ^ other`
388                    symmetric_difference $($lower_inner_name)*
389                }
390
391                /// Bitwise not - `!self`
392                pub const fn complement(self) -> Self {
393                    Self {
394                        $($lower_inner_name: self.$lower_inner_name.complement(),)*
395                    }
396                }
397
398                /// Calls [`Self::insert`] if `set` is true and otherwise calls [`Self::remove`].
399                pub fn set(&mut self, other:Self, set: bool) {
400                    $(self.$lower_inner_name.set(other.$lower_inner_name, set);)*
401                }
402
403                /// Inserts specified flag(s) into self
404                pub fn insert(&mut self, other:Self) {
405                    $(self.$lower_inner_name.insert(other.$lower_inner_name);)*
406                }
407
408                /// Removes specified flag(s) from self
409                pub fn remove(&mut self, other:Self) {
410                    $(self.$lower_inner_name.remove(other.$lower_inner_name);)*
411                }
412
413                /// Toggles specified flag(s) in self
414                pub fn toggle(&mut self, other:Self) {
415                    $(self.$lower_inner_name.toggle(other.$lower_inner_name);)*
416                }
417
418                #[doc = concat!("Takes in [`", stringify!($name_bits), "`] and returns")]
419                /// None if there are invalid bits or otherwise Self with those bits set
420                pub const fn from_bits(bits: $name_bits) -> Option<Self> {
421                    let [$($lower_inner_name,)*] = bits.0;
422                    // The ? operator does not work in a const context.
423                    Some(Self {
424                        $(
425                            $lower_inner_name: match $inner_name::from_bits($lower_inner_name) {
426                                Some(some) => some,
427                                None => return None,
428                            },
429                        )*
430                    })
431                }
432
433                #[doc = concat!("Takes in [`", stringify!($name_bits), "`] and returns Self with only valid bits (all other bits removed)")]
434                pub const fn from_bits_truncate(bits: $name_bits) -> Self {
435                    let [$($lower_inner_name,)*] = bits.0;
436                    Self { $($lower_inner_name: $inner_name::from_bits_truncate($lower_inner_name),)* }
437                }
438
439                #[doc = concat!("Takes in [`", stringify!($name_bits), "`] and returns Self with all bits that were set without removing invalid bits")]
440                pub const fn from_bits_retain(bits: $name_bits) -> Self {
441                    let [$($lower_inner_name,)*] = bits.0;
442                    Self { $($lower_inner_name: $inner_name::from_bits_retain($lower_inner_name),)* }
443                }
444
445                /// Takes in a bitflags flag name (in `SCREAMING_SNAKE_CASE`) and returns Self
446                /// if it matches or none if the name does not match the name of any of the
447                /// flags. Name is capitalisation dependent.
448                ///
449                /// [`impl FromStr`] can be used to recognize kebab-case names, like are used in
450                /// the WebGPU spec.
451                pub fn from_name(name: &str) -> Option<Self> {
452                    match name {
453                        $(
454                            $(
455                                stringify!($Flag) => Some(Self::$Flag),
456                            )*
457                        )*
458                        _ => None,
459                    }
460                }
461
462                /// Combines the flags from the internal flags into the entire flags struct
463                pub fn from_internal_flags($($lower_inner_name: $inner_name,)*) -> Self {
464                    Self {
465                        $($lower_inner_name,)*
466                    }
467                }
468
469                /// Returns an iterator over the set flags.
470                pub const fn iter(&self) -> bitflags::iter::Iter<$name> {
471                    bitflags::iter::Iter::__private_const_new($name::FLAGS, *self, *self)
472                }
473
474                /// Returns an iterator over the set flags and their names.
475                ///
476                /// These are bitflags names in `SCREAMING_SNAKE_CASE`.
477                pub const fn iter_names(&self) -> bitflags::iter::IterNames<$name> {
478                    bitflags::iter::IterNames::__private_const_new($name::FLAGS, *self, *self)
479                }
480
481                $(
482                    $(
483                        $(#[doc $($args)*])*
484                        #[allow(clippy::needless_update, reason = "only useless if there is 1 member")]
485                        pub const $Flag: Self = Self {
486                            $lower_inner_name: $inner_name::from_bits_truncate($value),
487                            ..Self::empty()
488                        };
489                    )*
490                )*
491            }
492
493            $(
494                impl From<$inner_name> for $name {
495                    #[allow(clippy::needless_update, reason = "only useless if there is 1 member")]
496                    fn from($lower_inner_name: $inner_name) -> Self {
497                        Self {
498                            $lower_inner_name,
499                            ..Self::empty()
500                        }
501                    }
502                }
503            )*
504        };
505    }
506pub(crate) use bitflags_array;