wgpu_types/
macros.rs

1/// Macro for use with [`macro_rules_attribute::derive`] to derive a `const fn default()`
2/// in addition to `impl Default`.
3///
4/// Generics are not supported.
5///
6/// When using this macro on an enum, the default variant must be marked with `#[custom(default)]`,
7/// rather than `#[default]` as the built-in derive macro does. This is a limitation of
8/// [`macro_rules_attribute::derive`].
9macro_rules! ConstDefault {
10    // Simplify by dropping attributes and visibility from an `enum`.
11    (
12        $(#[$attr:meta])+
13        $vis:vis enum $enum_name:ident {
14            $($body:tt)*
15        }
16    ) => {
17        $crate::macros::ConstDefault!(enum $enum_name { $($body)* });
18    };
19
20    // Simplify by dropping attributes and visibility from a `struct`.
21    (
22        $(#[$attr:meta])+
23        $vis:vis struct $struct_name:ident $($rest:tt)*
24    ) => {
25        $crate::macros::ConstDefault!(struct $struct_name $($rest)*);
26    };
27
28    // Base case: match an `enum` with `#[default]` on the first variant.
29    (
30        enum $enum_name:ident {
31            #[custom(default)]
32            $(#[$other_variant_attr:meta])*
33            $variant_name:ident $(= $discriminant:expr)?,
34            $( $rest_of_body:tt )*
35        }
36    ) => {
37        impl $enum_name {
38            /// This function is identical to [`Default::default()`] except that it is a `const fn`.
39            pub const fn default() -> Self {
40                Self::$variant_name
41            }
42        }
43
44        impl $crate::macros::ConstDefaultHelper for $enum_name {
45            const DEFAULT: Self = Self::$variant_name;
46        }
47
48        impl ::core::default::Default for $enum_name {
49            fn default() -> Self {
50                Self::$variant_name
51            }
52        }
53    };
54
55    // Recursive case: remove an irrelevant attribute from the first variant.
56    (
57        enum $enum_name:ident {
58            #[$attr_that_is_not_default:meta]
59            $( $rest_of_body:tt )*
60        }
61    ) => {
62        $crate::macros::ConstDefault!(enum $enum_name { $( $rest_of_body )* });
63    };
64
65
66    // Recursive cases: remove the first variant of an enum (which may or may not have fields),
67    // because we have checked it is not the default.
68    (
69        enum $enum_name:ident {
70            $variant_name:ident $(= $discriminant:expr)?,
71            $( $rest_of_body:tt )*
72        }
73    ) => {
74        $crate::macros::ConstDefault!(enum $enum_name { $( $rest_of_body )* });
75    };
76    (
77        enum $enum_name:ident {
78            $variant_name:ident ( $( $field_tokens:tt )* ),
79            $( $rest_of_body:tt )*
80        }
81    ) => {
82        $crate::macros::ConstDefault!(enum $enum_name { $( $rest_of_body )* });
83    };
84    (
85        enum $enum_name:ident {
86            $variant_name:ident { $( $field_tokens:tt )* },
87            $( $rest_of_body:tt )*
88        }
89    ) => {
90        $crate::macros::ConstDefault!(enum $enum_name { $( $rest_of_body )* });
91    };
92
93    // Struct (without generics)
94    (
95        $(#[$struct_attr:meta])*
96        $vis:vis struct $struct_name:ident {
97            $(
98                $(#[$field_attr:meta])*
99                $field_vis:vis $field_name:ident : $field_type:ty,
100            )*
101        }
102    ) => {
103        impl $struct_name {
104            /// This function is identical to [`Default::default()`] except that it is a `const fn`.
105            pub const fn default() -> Self {
106                <Self as $crate::macros::ConstDefaultHelper>::DEFAULT
107            }
108        }
109
110        impl $crate::macros::ConstDefaultHelper for $struct_name {
111            const DEFAULT: Self = Self {
112                $(
113                    $field_name: <$field_type as $crate::macros::ConstDefaultHelper>::DEFAULT,
114                )*
115            };
116        }
117
118        impl ::core::default::Default for $struct_name {
119            fn default() -> Self {
120                <Self as $crate::macros::ConstDefaultHelper>::DEFAULT
121            }
122        }
123    };
124
125
126    // Tuple struct
127    (
128        $(#[$struct_attr:meta])*
129        $vis:vis struct $struct_name:ident(
130            $(
131                $(#[$field_attr:meta])*
132                $field_vis:vis $field_type:ty
133            ),* $(,)?
134        );
135    ) => {
136        impl $struct_name {
137            /// This function is identical to [`Default::default()`] except that it is a `const fn`.
138            pub const fn default() -> Self {
139                <Self as $crate::macros::ConstDefaultHelper>::DEFAULT
140            }
141        }
142
143        impl $crate::macros::ConstDefaultHelper for $struct_name {
144            const DEFAULT: Self = Self(
145                $(
146                    <$field_type as $crate::macros::ConstDefaultHelper>::DEFAULT,
147                )*
148            );
149        }
150
151        impl ::core::default::Default for $struct_name {
152            fn default() -> Self {
153                <Self as $crate::macros::ConstDefaultHelper>::DEFAULT
154            }
155        }
156    };
157}
158pub(crate) use ConstDefault;
159
160/// Default value of a type, as a `const` item.
161///
162/// This trait is not public and is used solely to help [`ConstDefault`] provide *inherent*
163/// `const fn default()`s.
164///
165/// Specifically, it is implemented both for `wgpu-types` types and `std` types,
166/// so that the macro [`ConstDefault`] can call it without needing to understand the type.
167pub(crate) trait ConstDefaultHelper {
168    const DEFAULT: Self;
169}
170
171impl ConstDefaultHelper for bool {
172    const DEFAULT: Self = false;
173}
174impl ConstDefaultHelper for f32 {
175    const DEFAULT: Self = 0.;
176}
177impl ConstDefaultHelper for f64 {
178    const DEFAULT: Self = 0.;
179}
180impl ConstDefaultHelper for i32 {
181    const DEFAULT: Self = 0;
182}
183impl ConstDefaultHelper for i64 {
184    const DEFAULT: Self = 0;
185}
186impl ConstDefaultHelper for u32 {
187    const DEFAULT: Self = 0;
188}
189impl ConstDefaultHelper for u64 {
190    const DEFAULT: Self = 0;
191}
192
193impl<T> ConstDefaultHelper for Option<T> {
194    const DEFAULT: Self = None;
195}
196
197impl<T: ConstDefaultHelper, const N: usize> ConstDefaultHelper for [T; N] {
198    const DEFAULT: Self = [<T as ConstDefaultHelper>::DEFAULT; N];
199}