xref: /linux/rust/zerocopy/src/util/macros.rs (revision 499dc02cd545258b8ebd6f52fac226c6263768e9)
1*499dc02cSMiguel Ojeda // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
2*499dc02cSMiguel Ojeda 
3c3739801SMiguel Ojeda // Copyright 2023 The Fuchsia Authors
4c3739801SMiguel Ojeda //
5c3739801SMiguel Ojeda // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
6c3739801SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
7c3739801SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
8c3739801SMiguel Ojeda // This file may not be copied, modified, or distributed except according to
9c3739801SMiguel Ojeda // those terms.
10c3739801SMiguel Ojeda 
11c3739801SMiguel Ojeda /// Unsafely implements trait(s) for a type.
12c3739801SMiguel Ojeda ///
13c3739801SMiguel Ojeda /// # Safety
14c3739801SMiguel Ojeda ///
15c3739801SMiguel Ojeda /// The trait impl must be sound.
16c3739801SMiguel Ojeda ///
17c3739801SMiguel Ojeda /// When implementing `TryFromBytes`:
18c3739801SMiguel Ojeda /// - If no `is_bit_valid` impl is provided, then it must be valid for
19c3739801SMiguel Ojeda ///   `is_bit_valid` to unconditionally return `true`. In other words, it must
20c3739801SMiguel Ojeda ///   be the case that any initialized sequence of bytes constitutes a valid
21c3739801SMiguel Ojeda ///   instance of `$ty`.
22c3739801SMiguel Ojeda /// - If an `is_bit_valid` impl is provided, then the impl of `is_bit_valid`
23c3739801SMiguel Ojeda ///   must only return `true` if its argument refers to a valid `$ty`.
24c3739801SMiguel Ojeda macro_rules! unsafe_impl {
25c3739801SMiguel Ojeda     // Implement `$trait` for `$ty` with no bounds.
26c3739801SMiguel Ojeda     ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident| $is_bit_valid:expr)?) => {{
27c3739801SMiguel Ojeda         crate::util::macros::__unsafe();
28c3739801SMiguel Ojeda 
29c3739801SMiguel Ojeda         $(#[$attr])*
30c3739801SMiguel Ojeda         // SAFETY: The caller promises that this is sound.
31c3739801SMiguel Ojeda         unsafe impl $trait for $ty {
32c3739801SMiguel Ojeda             unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
33c3739801SMiguel Ojeda         }
34c3739801SMiguel Ojeda     }};
35c3739801SMiguel Ojeda 
36c3739801SMiguel Ojeda     // Implement all `$traits` for `$ty` with no bounds.
37c3739801SMiguel Ojeda     //
38c3739801SMiguel Ojeda     // The 2 arms under this one are there so we can apply
39c3739801SMiguel Ojeda     // N attributes for each one of M trait implementations.
40c3739801SMiguel Ojeda     // The simple solution of:
41c3739801SMiguel Ojeda     //
42c3739801SMiguel Ojeda     // ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => {
43c3739801SMiguel Ojeda     //     $( unsafe_impl!( $(#[$attrs])* $ty: $traits ) );*
44c3739801SMiguel Ojeda     // }
45c3739801SMiguel Ojeda     //
46c3739801SMiguel Ojeda     // Won't work. The macro processor sees that the outer repetition
47c3739801SMiguel Ojeda     // contains both $attrs and $traits and expects them to match the same
48c3739801SMiguel Ojeda     // amount of fragments.
49c3739801SMiguel Ojeda     //
50c3739801SMiguel Ojeda     // To solve this we must:
51c3739801SMiguel Ojeda     // 1. Pack the attributes into a single token tree fragment we can match over.
52c3739801SMiguel Ojeda     // 2. Expand the traits.
53c3739801SMiguel Ojeda     // 3. Unpack and expand the attributes.
54c3739801SMiguel Ojeda     ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => {
55c3739801SMiguel Ojeda         unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*)
56c3739801SMiguel Ojeda     };
57c3739801SMiguel Ojeda 
58c3739801SMiguel Ojeda     (@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => {{
59c3739801SMiguel Ojeda         $( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )*
60c3739801SMiguel Ojeda     }};
61c3739801SMiguel Ojeda 
62c3739801SMiguel Ojeda     (@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => {
63c3739801SMiguel Ojeda         unsafe_impl!($(#[$attrs])* $ty: $traits);
64c3739801SMiguel Ojeda     };
65c3739801SMiguel Ojeda 
66c3739801SMiguel Ojeda     // This arm is identical to the following one, except it contains a
67c3739801SMiguel Ojeda     // preceding `const`. If we attempt to handle these with a single arm, there
68c3739801SMiguel Ojeda     // is an inherent ambiguity between `const` (the keyword) and `const` (the
69c3739801SMiguel Ojeda     // ident match for `$tyvar:ident`).
70c3739801SMiguel Ojeda     //
71c3739801SMiguel Ojeda     // To explain how this works, consider the following invocation:
72c3739801SMiguel Ojeda     //
73c3739801SMiguel Ojeda     //   unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo<T>);
74c3739801SMiguel Ojeda     //
75c3739801SMiguel Ojeda     // In this invocation, here are the assignments to meta-variables:
76c3739801SMiguel Ojeda     //
77c3739801SMiguel Ojeda     //   |---------------|------------|
78c3739801SMiguel Ojeda     //   | Meta-variable | Assignment |
79c3739801SMiguel Ojeda     //   |---------------|------------|
80c3739801SMiguel Ojeda     //   | $constname    |  N         |
81c3739801SMiguel Ojeda     //   | $constty      |  usize     |
82c3739801SMiguel Ojeda     //   | $tyvar        |  T         |
83c3739801SMiguel Ojeda     //   | $optbound     |  Sized     |
84c3739801SMiguel Ojeda     //   | $bound        |  Copy      |
85c3739801SMiguel Ojeda     //   | $trait        |  Clone     |
86c3739801SMiguel Ojeda     //   | $ty           |  Foo<T>    |
87c3739801SMiguel Ojeda     //   |---------------|------------|
88c3739801SMiguel Ojeda     //
89c3739801SMiguel Ojeda     // The following arm has the same behavior with the exception of the lack of
90c3739801SMiguel Ojeda     // support for a leading `const` parameter.
91c3739801SMiguel Ojeda     (
92c3739801SMiguel Ojeda         $(#[$attr:meta])*
93c3739801SMiguel Ojeda         const $constname:ident : $constty:ident $(,)?
94c3739801SMiguel Ojeda         $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
95c3739801SMiguel Ojeda         => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
96c3739801SMiguel Ojeda     ) => {
97c3739801SMiguel Ojeda         unsafe_impl!(
98c3739801SMiguel Ojeda             @inner
99c3739801SMiguel Ojeda             $(#[$attr])*
100c3739801SMiguel Ojeda             @const $constname: $constty,
101c3739801SMiguel Ojeda             $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
102c3739801SMiguel Ojeda             => $trait for $ty $(; |$candidate| $is_bit_valid)?
103c3739801SMiguel Ojeda         );
104c3739801SMiguel Ojeda     };
105c3739801SMiguel Ojeda     (
106c3739801SMiguel Ojeda         $(#[$attr:meta])*
107c3739801SMiguel Ojeda         $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
108c3739801SMiguel Ojeda         => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
109c3739801SMiguel Ojeda     ) => {{
110c3739801SMiguel Ojeda         unsafe_impl!(
111c3739801SMiguel Ojeda             @inner
112c3739801SMiguel Ojeda             $(#[$attr])*
113c3739801SMiguel Ojeda             $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
114c3739801SMiguel Ojeda             => $trait for $ty $(; |$candidate| $is_bit_valid)?
115c3739801SMiguel Ojeda         );
116c3739801SMiguel Ojeda     }};
117c3739801SMiguel Ojeda     (
118c3739801SMiguel Ojeda         @inner
119c3739801SMiguel Ojeda         $(#[$attr:meta])*
120c3739801SMiguel Ojeda         $(@const $constname:ident : $constty:ident,)*
121c3739801SMiguel Ojeda         $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
122c3739801SMiguel Ojeda         => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
123c3739801SMiguel Ojeda     ) => {{
124c3739801SMiguel Ojeda         crate::util::macros::__unsafe();
125c3739801SMiguel Ojeda 
126c3739801SMiguel Ojeda         $(#[$attr])*
127c3739801SMiguel Ojeda         #[allow(non_local_definitions)]
128c3739801SMiguel Ojeda         // SAFETY: The caller promises that this is sound.
129c3739801SMiguel Ojeda         unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* $(, const $constname: $constty,)*> $trait for $ty {
130c3739801SMiguel Ojeda             unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
131c3739801SMiguel Ojeda         }
132c3739801SMiguel Ojeda     }};
133c3739801SMiguel Ojeda 
134c3739801SMiguel Ojeda     (@method TryFromBytes ; |$candidate:ident| $is_bit_valid:expr) => {
135c3739801SMiguel Ojeda         #[allow(clippy::missing_inline_in_public_items, dead_code)]
136c3739801SMiguel Ojeda         #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
137c3739801SMiguel Ojeda         fn only_derive_is_allowed_to_implement_this_trait() {}
138c3739801SMiguel Ojeda 
139c3739801SMiguel Ojeda         #[inline]
140c3739801SMiguel Ojeda         fn is_bit_valid<Alignment>($candidate: Maybe<'_, Self, Alignment>) -> bool
141c3739801SMiguel Ojeda         where
142c3739801SMiguel Ojeda             Alignment: crate::invariant::Alignment,
143c3739801SMiguel Ojeda         {
144c3739801SMiguel Ojeda             $is_bit_valid
145c3739801SMiguel Ojeda         }
146c3739801SMiguel Ojeda     };
147c3739801SMiguel Ojeda     (@method TryFromBytes) => {
148c3739801SMiguel Ojeda         #[allow(clippy::missing_inline_in_public_items)]
149c3739801SMiguel Ojeda         #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
150c3739801SMiguel Ojeda         fn only_derive_is_allowed_to_implement_this_trait() {}
151c3739801SMiguel Ojeda         #[inline(always)]
152c3739801SMiguel Ojeda         fn is_bit_valid<Alignment>(_candidate: Maybe<'_, Self, Alignment>) -> bool
153c3739801SMiguel Ojeda         where
154c3739801SMiguel Ojeda             Alignment: crate::invariant::Alignment,
155c3739801SMiguel Ojeda         {
156c3739801SMiguel Ojeda             true
157c3739801SMiguel Ojeda         }
158c3739801SMiguel Ojeda     };
159c3739801SMiguel Ojeda     (@method $trait:ident) => {
160c3739801SMiguel Ojeda         #[allow(clippy::missing_inline_in_public_items, dead_code)]
161c3739801SMiguel Ojeda         #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
162c3739801SMiguel Ojeda         fn only_derive_is_allowed_to_implement_this_trait() {}
163c3739801SMiguel Ojeda     };
164c3739801SMiguel Ojeda     (@method $trait:ident; |$_candidate:ident| $_is_bit_valid:expr) => {
165c3739801SMiguel Ojeda         compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
166c3739801SMiguel Ojeda     };
167c3739801SMiguel Ojeda }
168c3739801SMiguel Ojeda 
169c3739801SMiguel Ojeda /// Implements `$trait` for `$ty` where `$ty: TransmuteFrom<$repr>` (and
170c3739801SMiguel Ojeda /// vice-versa).
171c3739801SMiguel Ojeda ///
172c3739801SMiguel Ojeda /// Calling this macro is safe; the internals of the macro emit appropriate
173c3739801SMiguel Ojeda /// trait bounds which ensure that the given impl is sound.
174c3739801SMiguel Ojeda macro_rules! impl_for_transmute_from {
175c3739801SMiguel Ojeda     (
176c3739801SMiguel Ojeda         $(#[$attr:meta])*
177c3739801SMiguel Ojeda         $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)?
178c3739801SMiguel Ojeda         => $trait:ident for $ty:ty [$repr:ty]
179c3739801SMiguel Ojeda     ) => {
180c3739801SMiguel Ojeda         const _: () = {
181c3739801SMiguel Ojeda             $(#[$attr])*
182c3739801SMiguel Ojeda             #[allow(non_local_definitions)]
183c3739801SMiguel Ojeda 
184c3739801SMiguel Ojeda             // SAFETY: `is_trait<T, R>` (defined and used below) requires `T:
185c3739801SMiguel Ojeda             // TransmuteFrom<R>`, `R: TransmuteFrom<T>`, and `R: $trait`. It is
186c3739801SMiguel Ojeda             // called using `$ty` and `$repr`, ensuring that `$ty` and `$repr`
187c3739801SMiguel Ojeda             // have equivalent bit validity, and ensuring that `$repr: $trait`.
188c3739801SMiguel Ojeda             // The supported traits - `TryFromBytes`, `FromZeros`, `FromBytes`,
189c3739801SMiguel Ojeda             // and `IntoBytes` - are defined only in terms of the bit validity
190c3739801SMiguel Ojeda             // of a type. Therefore, `$repr: $trait` ensures that `$ty: $trait`
191c3739801SMiguel Ojeda             // is sound.
192c3739801SMiguel Ojeda             unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty {
193c3739801SMiguel Ojeda                 #[allow(dead_code, clippy::missing_inline_in_public_items)]
194c3739801SMiguel Ojeda                 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
195c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait() {
196c3739801SMiguel Ojeda                     use crate::pointer::{*, invariant::Valid};
197c3739801SMiguel Ojeda 
198c3739801SMiguel Ojeda                     impl_for_transmute_from!(@assert_is_supported_trait $trait);
199c3739801SMiguel Ojeda 
200c3739801SMiguel Ojeda                     fn is_trait<T, R>()
201c3739801SMiguel Ojeda                     where
202c3739801SMiguel Ojeda                         T: TransmuteFrom<R, Valid, Valid> + ?Sized,
203c3739801SMiguel Ojeda                         R: TransmuteFrom<T, Valid, Valid> + ?Sized,
204c3739801SMiguel Ojeda                         R: $trait,
205c3739801SMiguel Ojeda                     {
206c3739801SMiguel Ojeda                     }
207c3739801SMiguel Ojeda 
208c3739801SMiguel Ojeda                     #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
209c3739801SMiguel Ojeda                     fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() {
210c3739801SMiguel Ojeda                         is_trait::<$ty, $repr>();
211c3739801SMiguel Ojeda                     }
212c3739801SMiguel Ojeda                 }
213c3739801SMiguel Ojeda 
214c3739801SMiguel Ojeda                 impl_for_transmute_from!(
215c3739801SMiguel Ojeda                     @is_bit_valid
216c3739801SMiguel Ojeda                     $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
217c3739801SMiguel Ojeda                     $trait for $ty [$repr]
218c3739801SMiguel Ojeda                 );
219c3739801SMiguel Ojeda             }
220c3739801SMiguel Ojeda         };
221c3739801SMiguel Ojeda     };
222c3739801SMiguel Ojeda     (@assert_is_supported_trait TryFromBytes) => {};
223c3739801SMiguel Ojeda     (@assert_is_supported_trait FromZeros) => {};
224c3739801SMiguel Ojeda     (@assert_is_supported_trait FromBytes) => {};
225c3739801SMiguel Ojeda     (@assert_is_supported_trait IntoBytes) => {};
226c3739801SMiguel Ojeda     (
227c3739801SMiguel Ojeda         @is_bit_valid
228c3739801SMiguel Ojeda         $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
229c3739801SMiguel Ojeda         TryFromBytes for $ty:ty [$repr:ty]
230c3739801SMiguel Ojeda     ) => {
231c3739801SMiguel Ojeda         #[inline(always)]
232c3739801SMiguel Ojeda         fn is_bit_valid<Alignment>(candidate: $crate::Maybe<'_, Self, Alignment>) -> bool
233c3739801SMiguel Ojeda         where
234c3739801SMiguel Ojeda             Alignment: $crate::invariant::Alignment,
235c3739801SMiguel Ojeda         {
236c3739801SMiguel Ojeda             // SAFETY: This macro ensures that `$repr` and `Self` have the same
237c3739801SMiguel Ojeda             // size and bit validity. Thus, a bit-valid instance of `$repr` is
238c3739801SMiguel Ojeda             // also a bit-valid instance of `Self`.
239c3739801SMiguel Ojeda             <$repr as TryFromBytes>::is_bit_valid(candidate.transmute::<_, _, BecauseImmutable>())
240c3739801SMiguel Ojeda         }
241c3739801SMiguel Ojeda     };
242c3739801SMiguel Ojeda     (
243c3739801SMiguel Ojeda         @is_bit_valid
244c3739801SMiguel Ojeda         $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
245c3739801SMiguel Ojeda         $trait:ident for $ty:ty [$repr:ty]
246c3739801SMiguel Ojeda     ) => {
247c3739801SMiguel Ojeda         // Trait other than `TryFromBytes`; no `is_bit_valid` impl.
248c3739801SMiguel Ojeda     };
249c3739801SMiguel Ojeda }
250c3739801SMiguel Ojeda 
251c3739801SMiguel Ojeda /// Implements a trait for a type, bounding on each member of the power set of
252c3739801SMiguel Ojeda /// a set of type variables. This is useful for implementing traits for tuples
253c3739801SMiguel Ojeda /// or `fn` types.
254c3739801SMiguel Ojeda ///
255c3739801SMiguel Ojeda /// The last argument is the name of a macro which will be called in every
256c3739801SMiguel Ojeda /// `impl` block, and is expected to expand to the name of the type for which to
257c3739801SMiguel Ojeda /// implement the trait.
258c3739801SMiguel Ojeda ///
259c3739801SMiguel Ojeda /// For example, the invocation:
260c3739801SMiguel Ojeda /// ```ignore
261c3739801SMiguel Ojeda /// unsafe_impl_for_power_set!(A, B => Foo for type!(...))
262c3739801SMiguel Ojeda /// ```
263c3739801SMiguel Ojeda /// ...expands to:
264c3739801SMiguel Ojeda /// ```ignore
265c3739801SMiguel Ojeda /// unsafe impl       Foo for type!()     { ... }
266c3739801SMiguel Ojeda /// unsafe impl<B>    Foo for type!(B)    { ... }
267c3739801SMiguel Ojeda /// unsafe impl<A, B> Foo for type!(A, B) { ... }
268c3739801SMiguel Ojeda /// ```
269c3739801SMiguel Ojeda macro_rules! unsafe_impl_for_power_set {
270c3739801SMiguel Ojeda     (
271c3739801SMiguel Ojeda         $first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
272c3739801SMiguel Ojeda         $(; |$candidate:ident| $is_bit_valid:expr)?
273c3739801SMiguel Ojeda     ) => {
274c3739801SMiguel Ojeda         unsafe_impl_for_power_set!(
275c3739801SMiguel Ojeda             $($rest),* $(-> $ret)? => $trait for $macro!(...)
276c3739801SMiguel Ojeda             $(; |$candidate| $is_bit_valid)?
277c3739801SMiguel Ojeda         );
278c3739801SMiguel Ojeda         unsafe_impl_for_power_set!(
279c3739801SMiguel Ojeda             @impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...)
280c3739801SMiguel Ojeda             $(; |$candidate| $is_bit_valid)?
281c3739801SMiguel Ojeda         );
282c3739801SMiguel Ojeda     };
283c3739801SMiguel Ojeda     (
284c3739801SMiguel Ojeda         $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
285c3739801SMiguel Ojeda         $(; |$candidate:ident| $is_bit_valid:expr)?
286c3739801SMiguel Ojeda     ) => {
287c3739801SMiguel Ojeda         unsafe_impl_for_power_set!(
288c3739801SMiguel Ojeda             @impl $(-> $ret)? => $trait for $macro!(...)
289c3739801SMiguel Ojeda             $(; |$candidate| $is_bit_valid)?
290c3739801SMiguel Ojeda         );
291c3739801SMiguel Ojeda     };
292c3739801SMiguel Ojeda     (
293c3739801SMiguel Ojeda         @impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
294c3739801SMiguel Ojeda         $(; |$candidate:ident| $is_bit_valid:expr)?
295c3739801SMiguel Ojeda     ) => {
296c3739801SMiguel Ojeda         unsafe_impl!(
297c3739801SMiguel Ojeda             $($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?)
298c3739801SMiguel Ojeda             $(; |$candidate| $is_bit_valid)?
299c3739801SMiguel Ojeda         );
300c3739801SMiguel Ojeda     };
301c3739801SMiguel Ojeda }
302c3739801SMiguel Ojeda 
303c3739801SMiguel Ojeda /// Expands to an `Option<extern "C" fn>` type with the given argument types and
304c3739801SMiguel Ojeda /// return type. Designed for use with `unsafe_impl_for_power_set`.
305c3739801SMiguel Ojeda macro_rules! opt_extern_c_fn {
306c3739801SMiguel Ojeda     ($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
307c3739801SMiguel Ojeda }
308c3739801SMiguel Ojeda 
309c3739801SMiguel Ojeda /// Expands to an `Option<unsafe extern "C" fn>` type with the given argument
310c3739801SMiguel Ojeda /// types and return type. Designed for use with `unsafe_impl_for_power_set`.
311c3739801SMiguel Ojeda macro_rules! opt_unsafe_extern_c_fn {
312c3739801SMiguel Ojeda     ($($args:ident),* -> $ret:ident) => { Option<unsafe extern "C" fn($($args),*) -> $ret> };
313c3739801SMiguel Ojeda }
314c3739801SMiguel Ojeda 
315c3739801SMiguel Ojeda /// Expands to an `Option<fn>` type with the given argument types and return
316c3739801SMiguel Ojeda /// type. Designed for use with `unsafe_impl_for_power_set`.
317c3739801SMiguel Ojeda macro_rules! opt_fn {
318c3739801SMiguel Ojeda     ($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
319c3739801SMiguel Ojeda }
320c3739801SMiguel Ojeda 
321c3739801SMiguel Ojeda /// Expands to an `Option<unsafe fn>` type with the given argument types and
322c3739801SMiguel Ojeda /// return type. Designed for use with `unsafe_impl_for_power_set`.
323c3739801SMiguel Ojeda macro_rules! opt_unsafe_fn {
324c3739801SMiguel Ojeda     ($($args:ident),* -> $ret:ident) => { Option<unsafe fn($($args),*) -> $ret> };
325c3739801SMiguel Ojeda }
326c3739801SMiguel Ojeda 
327c3739801SMiguel Ojeda // This `allow` is needed because, when testing, we export this macro so it can
328c3739801SMiguel Ojeda // be used in `doctests`.
329c3739801SMiguel Ojeda #[allow(rustdoc::private_intra_doc_links)]
330c3739801SMiguel Ojeda /// Implements trait(s) for a type or verifies the given implementation by
331c3739801SMiguel Ojeda /// referencing an existing (derived) implementation.
332c3739801SMiguel Ojeda ///
333c3739801SMiguel Ojeda /// This macro exists so that we can provide zerocopy-derive as an optional
334c3739801SMiguel Ojeda /// dependency and still get the benefit of using its derives to validate that
335c3739801SMiguel Ojeda /// our trait impls are sound.
336c3739801SMiguel Ojeda ///
337c3739801SMiguel Ojeda /// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`,
338c3739801SMiguel Ojeda /// `impl_or_verify!` emits the provided trait impl. When compiling with either
339c3739801SMiguel Ojeda /// of those cfgs, it is expected that the type in question is deriving the
340c3739801SMiguel Ojeda /// traits instead. In this case, `impl_or_verify!` emits code which validates
341c3739801SMiguel Ojeda /// that the given trait impl is at least as restrictive as the the impl emitted
342c3739801SMiguel Ojeda /// by the custom derive. This has the effect of confirming that the impl which
343c3739801SMiguel Ojeda /// is emitted when the `derive` feature is disabled is actually sound (on the
344c3739801SMiguel Ojeda /// assumption that the impl emitted by the custom derive is sound).
345c3739801SMiguel Ojeda ///
346c3739801SMiguel Ojeda /// The caller is still required to provide a safety comment (e.g. using the
347c3739801SMiguel Ojeda /// `const _: () = unsafe` macro). The reason for this restriction is that,
348c3739801SMiguel Ojeda /// while `impl_or_verify!` can guarantee that the provided impl is sound when
349c3739801SMiguel Ojeda /// it is compiled with the appropriate cfgs, there is no way to guarantee that
350c3739801SMiguel Ojeda /// it is ever compiled with those cfgs. In particular, it would be possible to
351c3739801SMiguel Ojeda /// accidentally place an `impl_or_verify!` call in a context that is only ever
352c3739801SMiguel Ojeda /// compiled when the `derive` feature is disabled. If that were to happen,
353c3739801SMiguel Ojeda /// there would be nothing to prevent an unsound trait impl from being emitted.
354c3739801SMiguel Ojeda /// Requiring a safety comment reduces the likelihood of emitting an unsound
355c3739801SMiguel Ojeda /// impl in this case, and also provides useful documentation for readers of the
356c3739801SMiguel Ojeda /// code.
357c3739801SMiguel Ojeda ///
358c3739801SMiguel Ojeda /// Finally, if a `TryFromBytes::is_bit_valid` impl is provided, it must adhere
359c3739801SMiguel Ojeda /// to the safety preconditions of [`unsafe_impl!`].
360c3739801SMiguel Ojeda ///
361c3739801SMiguel Ojeda /// ## Example
362c3739801SMiguel Ojeda ///
363c3739801SMiguel Ojeda /// ```rust,ignore
364c3739801SMiguel Ojeda /// // Note that these derives are gated by `feature = "derive"`
365c3739801SMiguel Ojeda /// #[cfg_attr(any(feature = "derive", test), derive(FromZeros, FromBytes, IntoBytes, Unaligned))]
366c3739801SMiguel Ojeda /// #[repr(transparent)]
367c3739801SMiguel Ojeda /// struct Wrapper<T>(T);
368c3739801SMiguel Ojeda ///
369c3739801SMiguel Ojeda /// const _: () = unsafe {
370c3739801SMiguel Ojeda ///     /// SAFETY:
371c3739801SMiguel Ojeda ///     /// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any
372c3739801SMiguel Ojeda ///     /// zerocopy trait if `T` implements that trait.
373c3739801SMiguel Ojeda ///     impl_or_verify!(T: FromZeros => FromZeros for Wrapper<T>);
374c3739801SMiguel Ojeda ///     impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>);
375c3739801SMiguel Ojeda ///     impl_or_verify!(T: IntoBytes => IntoBytes for Wrapper<T>);
376c3739801SMiguel Ojeda ///     impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>);
377c3739801SMiguel Ojeda /// }
378c3739801SMiguel Ojeda /// ```
379c3739801SMiguel Ojeda #[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE, macro_export)] // Used in `doctests.rs`
380c3739801SMiguel Ojeda #[doc(hidden)]
381c3739801SMiguel Ojeda macro_rules! impl_or_verify {
382c3739801SMiguel Ojeda     // The following two match arms follow the same pattern as their
383c3739801SMiguel Ojeda     // counterparts in `unsafe_impl!`; see the documentation on those arms for
384c3739801SMiguel Ojeda     // more details.
385c3739801SMiguel Ojeda     (
386c3739801SMiguel Ojeda         const $constname:ident : $constty:ident $(,)?
387c3739801SMiguel Ojeda         $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
388c3739801SMiguel Ojeda         => $trait:ident for $ty:ty
389c3739801SMiguel Ojeda     ) => {
390c3739801SMiguel Ojeda         impl_or_verify!(@impl { unsafe_impl!(
391c3739801SMiguel Ojeda             const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
392c3739801SMiguel Ojeda         ); });
393c3739801SMiguel Ojeda         impl_or_verify!(@verify $trait, {
394c3739801SMiguel Ojeda             impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
395c3739801SMiguel Ojeda         });
396c3739801SMiguel Ojeda     };
397c3739801SMiguel Ojeda     (
398c3739801SMiguel Ojeda         $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
399c3739801SMiguel Ojeda         => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
400c3739801SMiguel Ojeda     ) => {
401c3739801SMiguel Ojeda         impl_or_verify!(@impl { unsafe_impl!(
402c3739801SMiguel Ojeda             $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
403c3739801SMiguel Ojeda             $(; |$candidate| $is_bit_valid)?
404c3739801SMiguel Ojeda         ); });
405c3739801SMiguel Ojeda         impl_or_verify!(@verify $trait, {
406c3739801SMiguel Ojeda             impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
407c3739801SMiguel Ojeda         });
408c3739801SMiguel Ojeda     };
409c3739801SMiguel Ojeda     (@impl $impl_block:tt) => {
410c3739801SMiguel Ojeda         #[cfg(not(any(feature = "derive", test)))]
411c3739801SMiguel Ojeda         { $impl_block };
412c3739801SMiguel Ojeda     };
413c3739801SMiguel Ojeda     (@verify $trait:ident, $impl_block:tt) => {
414c3739801SMiguel Ojeda         #[cfg(any(feature = "derive", test))]
415c3739801SMiguel Ojeda         {
416c3739801SMiguel Ojeda             // On some toolchains, `Subtrait` triggers the `dead_code` lint
417c3739801SMiguel Ojeda             // because it is implemented but never used.
418c3739801SMiguel Ojeda             #[allow(dead_code)]
419c3739801SMiguel Ojeda             trait Subtrait: $trait {}
420c3739801SMiguel Ojeda             $impl_block
421c3739801SMiguel Ojeda         };
422c3739801SMiguel Ojeda     };
423c3739801SMiguel Ojeda }
424c3739801SMiguel Ojeda 
425c3739801SMiguel Ojeda /// Implements `KnownLayout` for a sized type.
426c3739801SMiguel Ojeda macro_rules! impl_known_layout {
427c3739801SMiguel Ojeda     ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
428c3739801SMiguel Ojeda         $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
429c3739801SMiguel Ojeda     };
430c3739801SMiguel Ojeda     ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
431c3739801SMiguel Ojeda         $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
432c3739801SMiguel Ojeda     };
433c3739801SMiguel Ojeda     ($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* };
434c3739801SMiguel Ojeda     (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => {
435c3739801SMiguel Ojeda         const _: () = {
436c3739801SMiguel Ojeda             use core::ptr::NonNull;
437c3739801SMiguel Ojeda 
438c3739801SMiguel Ojeda             #[allow(non_local_definitions)]
439c3739801SMiguel Ojeda             $(#[$attrs])*
440c3739801SMiguel Ojeda             // SAFETY: Delegates safety to `DstLayout::for_type`.
441c3739801SMiguel Ojeda             unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty {
442c3739801SMiguel Ojeda                 #[allow(clippy::missing_inline_in_public_items)]
443c3739801SMiguel Ojeda                 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
444c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
445c3739801SMiguel Ojeda 
446c3739801SMiguel Ojeda                 type PointerMetadata = ();
447c3739801SMiguel Ojeda 
448c3739801SMiguel Ojeda                 // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are
449c3739801SMiguel Ojeda                 // identical because `CoreMaybeUninit<T>` has the same size and
450c3739801SMiguel Ojeda                 // alignment as `T` [1], and `CoreMaybeUninit` admits
451c3739801SMiguel Ojeda                 // uninitialized bytes in all positions.
452c3739801SMiguel Ojeda                 //
453c3739801SMiguel Ojeda                 // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
454c3739801SMiguel Ojeda                 //
455c3739801SMiguel Ojeda                 //   `MaybeUninit<T>` is guaranteed to have the same size,
456c3739801SMiguel Ojeda                 //   alignment, and ABI as `T`
457c3739801SMiguel Ojeda                 type MaybeUninit = core::mem::MaybeUninit<Self>;
458c3739801SMiguel Ojeda 
459c3739801SMiguel Ojeda                 const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>();
460c3739801SMiguel Ojeda 
461c3739801SMiguel Ojeda                 // SAFETY: `.cast` preserves address and provenance.
462c3739801SMiguel Ojeda                 //
463c3739801SMiguel Ojeda                 // FIXME(#429): Add documentation to `.cast` that promises that
464c3739801SMiguel Ojeda                 // it preserves provenance.
465c3739801SMiguel Ojeda                 #[inline(always)]
466c3739801SMiguel Ojeda                 fn raw_from_ptr_len(bytes: NonNull<u8>, _meta: ()) -> NonNull<Self> {
467c3739801SMiguel Ojeda                     bytes.cast::<Self>()
468c3739801SMiguel Ojeda                 }
469c3739801SMiguel Ojeda 
470c3739801SMiguel Ojeda                 #[inline(always)]
471c3739801SMiguel Ojeda                 fn pointer_to_metadata(_ptr: *mut Self) -> () {
472c3739801SMiguel Ojeda                 }
473c3739801SMiguel Ojeda             }
474c3739801SMiguel Ojeda         };
475c3739801SMiguel Ojeda     };
476c3739801SMiguel Ojeda }
477c3739801SMiguel Ojeda 
478c3739801SMiguel Ojeda /// Implements `KnownLayout` for a type in terms of the implementation of
479c3739801SMiguel Ojeda /// another type with the same representation.
480c3739801SMiguel Ojeda ///
481c3739801SMiguel Ojeda /// # Safety
482c3739801SMiguel Ojeda ///
483c3739801SMiguel Ojeda /// - `$ty` and `$repr` must have the same:
484c3739801SMiguel Ojeda ///   - Fixed prefix size
485c3739801SMiguel Ojeda ///   - Alignment
486c3739801SMiguel Ojeda ///   - (For DSTs) trailing slice element size
487c3739801SMiguel Ojeda /// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
488c3739801SMiguel Ojeda ///   and this operation must preserve referent size (ie, `size_of_val_raw`).
489c3739801SMiguel Ojeda macro_rules! unsafe_impl_known_layout {
490c3739801SMiguel Ojeda     ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {{
491c3739801SMiguel Ojeda         use core::ptr::NonNull;
492c3739801SMiguel Ojeda 
493c3739801SMiguel Ojeda         crate::util::macros::__unsafe();
494c3739801SMiguel Ojeda 
495c3739801SMiguel Ojeda         #[allow(non_local_definitions)]
496c3739801SMiguel Ojeda         // SAFETY: The caller promises that this is sound.
497c3739801SMiguel Ojeda         unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
498c3739801SMiguel Ojeda             #[allow(clippy::missing_inline_in_public_items, dead_code)]
499c3739801SMiguel Ojeda             #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
500c3739801SMiguel Ojeda             fn only_derive_is_allowed_to_implement_this_trait() {}
501c3739801SMiguel Ojeda 
502c3739801SMiguel Ojeda             type PointerMetadata = <$repr as KnownLayout>::PointerMetadata;
503c3739801SMiguel Ojeda             type MaybeUninit = <$repr as KnownLayout>::MaybeUninit;
504c3739801SMiguel Ojeda 
505c3739801SMiguel Ojeda             const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
506c3739801SMiguel Ojeda 
507c3739801SMiguel Ojeda             // SAFETY: All operations preserve address and provenance. Caller
508c3739801SMiguel Ojeda             // has promised that the `as` cast preserves size.
509c3739801SMiguel Ojeda             //
510c3739801SMiguel Ojeda             // FIXME(#429): Add documentation to `NonNull::new_unchecked` that
511c3739801SMiguel Ojeda             // it preserves provenance.
512c3739801SMiguel Ojeda             #[inline(always)]
513c3739801SMiguel Ojeda             fn raw_from_ptr_len(bytes: NonNull<u8>, meta: <$repr as KnownLayout>::PointerMetadata) -> NonNull<Self> {
514c3739801SMiguel Ojeda                 #[allow(clippy::as_conversions)]
515c3739801SMiguel Ojeda                 let ptr = <$repr>::raw_from_ptr_len(bytes, meta).as_ptr() as *mut Self;
516c3739801SMiguel Ojeda                 // SAFETY: `ptr` was converted from `bytes`, which is non-null.
517c3739801SMiguel Ojeda                 unsafe { NonNull::new_unchecked(ptr) }
518c3739801SMiguel Ojeda             }
519c3739801SMiguel Ojeda 
520c3739801SMiguel Ojeda             #[inline(always)]
521c3739801SMiguel Ojeda             fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
522c3739801SMiguel Ojeda                 #[allow(clippy::as_conversions)]
523c3739801SMiguel Ojeda                 let ptr = ptr as *mut $repr;
524c3739801SMiguel Ojeda                 <$repr>::pointer_to_metadata(ptr)
525c3739801SMiguel Ojeda             }
526c3739801SMiguel Ojeda         }
527c3739801SMiguel Ojeda     }};
528c3739801SMiguel Ojeda }
529c3739801SMiguel Ojeda 
530c3739801SMiguel Ojeda /// Uses `align_of` to confirm that a type or set of types have alignment 1.
531c3739801SMiguel Ojeda ///
532c3739801SMiguel Ojeda /// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
533c3739801SMiguel Ojeda /// unsized types.
534c3739801SMiguel Ojeda macro_rules! assert_unaligned {
535c3739801SMiguel Ojeda     ($($tys:ty),*) => {
536c3739801SMiguel Ojeda         $(
537c3739801SMiguel Ojeda             // We only compile this assertion under `cfg(test)` to avoid taking
538c3739801SMiguel Ojeda             // an extra non-dev dependency (and making this crate more expensive
539c3739801SMiguel Ojeda             // to compile for our dependents).
540c3739801SMiguel Ojeda             #[cfg(test)]
541c3739801SMiguel Ojeda             static_assertions::const_assert_eq!(core::mem::align_of::<$tys>(), 1);
542c3739801SMiguel Ojeda         )*
543c3739801SMiguel Ojeda     };
544c3739801SMiguel Ojeda }
545c3739801SMiguel Ojeda 
546c3739801SMiguel Ojeda /// Emits a function definition as either `const fn` or `fn` depending on
547c3739801SMiguel Ojeda /// whether the current toolchain version supports `const fn` with generic trait
548c3739801SMiguel Ojeda /// bounds.
549c3739801SMiguel Ojeda macro_rules! maybe_const_trait_bounded_fn {
550c3739801SMiguel Ojeda     // This case handles both `self` methods (where `self` is by value) and
551c3739801SMiguel Ojeda     // non-method functions. Each `$args` may optionally be followed by `:
552c3739801SMiguel Ojeda     // $arg_tys:ty`, which can be omitted for `self`.
553c3739801SMiguel Ojeda     ($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => {
554c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_generic_bounds_in_const_fn_1_61_0))]
555c3739801SMiguel Ojeda         $(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
556c3739801SMiguel Ojeda 
557c3739801SMiguel Ojeda         #[cfg(no_zerocopy_generic_bounds_in_const_fn_1_61_0)]
558c3739801SMiguel Ojeda         $(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
559c3739801SMiguel Ojeda     };
560c3739801SMiguel Ojeda }
561c3739801SMiguel Ojeda 
562c3739801SMiguel Ojeda /// Either panic (if the current Rust toolchain supports panicking in `const
563c3739801SMiguel Ojeda /// fn`) or evaluate a constant that will cause an array indexing error whose
564c3739801SMiguel Ojeda /// error message will include the format string.
565c3739801SMiguel Ojeda ///
566c3739801SMiguel Ojeda /// The type that this expression evaluates to must be `Copy`, or else the
567c3739801SMiguel Ojeda /// non-panicking desugaring will fail to compile.
568c3739801SMiguel Ojeda macro_rules! const_panic {
569c3739801SMiguel Ojeda     (@non_panic $($_arg:tt)+) => {{
570c3739801SMiguel Ojeda         // This will type check to whatever type is expected based on the call
571c3739801SMiguel Ojeda         // site.
572c3739801SMiguel Ojeda         let panic: [_; 0] = [];
573c3739801SMiguel Ojeda         // This will always fail (since we're indexing into an array of size 0.
574c3739801SMiguel Ojeda         #[allow(unconditional_panic)]
575c3739801SMiguel Ojeda         panic[0]
576c3739801SMiguel Ojeda     }};
577c3739801SMiguel Ojeda     ($($arg:tt)+) => {{
578c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
579c3739801SMiguel Ojeda         panic!($($arg)+);
580c3739801SMiguel Ojeda         #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
581c3739801SMiguel Ojeda         const_panic!(@non_panic $($arg)+)
582c3739801SMiguel Ojeda     }};
583c3739801SMiguel Ojeda }
584c3739801SMiguel Ojeda 
585c3739801SMiguel Ojeda /// Either assert (if the current Rust toolchain supports panicking in `const
586c3739801SMiguel Ojeda /// fn`) or evaluate the expression and, if it evaluates to `false`, call
587c3739801SMiguel Ojeda /// `const_panic!`. This is used in place of `assert!` in const contexts to
588c3739801SMiguel Ojeda /// accommodate old toolchains.
589c3739801SMiguel Ojeda macro_rules! const_assert {
590c3739801SMiguel Ojeda     ($e:expr) => {{
591c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
592c3739801SMiguel Ojeda         assert!($e);
593c3739801SMiguel Ojeda         #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
594c3739801SMiguel Ojeda         {
595c3739801SMiguel Ojeda             let e = $e;
596c3739801SMiguel Ojeda             if !e {
597c3739801SMiguel Ojeda                 let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e)));
598c3739801SMiguel Ojeda             }
599c3739801SMiguel Ojeda         }
600c3739801SMiguel Ojeda     }};
601c3739801SMiguel Ojeda     ($e:expr, $($args:tt)+) => {{
602c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
603c3739801SMiguel Ojeda         assert!($e, $($args)+);
604c3739801SMiguel Ojeda         #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
605c3739801SMiguel Ojeda         {
606c3739801SMiguel Ojeda             let e = $e;
607c3739801SMiguel Ojeda             if !e {
608c3739801SMiguel Ojeda                 let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*);
609c3739801SMiguel Ojeda             }
610c3739801SMiguel Ojeda         }
611c3739801SMiguel Ojeda     }};
612c3739801SMiguel Ojeda }
613c3739801SMiguel Ojeda 
614c3739801SMiguel Ojeda /// Like `const_assert!`, but relative to `debug_assert!`.
615c3739801SMiguel Ojeda macro_rules! const_debug_assert {
616c3739801SMiguel Ojeda     ($e:expr $(, $msg:expr)?) => {{
617c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
618c3739801SMiguel Ojeda         debug_assert!($e $(, $msg)?);
619c3739801SMiguel Ojeda         #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
620c3739801SMiguel Ojeda         {
621c3739801SMiguel Ojeda             // Use this (rather than `#[cfg(debug_assertions)]`) to ensure that
622c3739801SMiguel Ojeda             // `$e` is always compiled even if it will never be evaluated at
623c3739801SMiguel Ojeda             // runtime.
624c3739801SMiguel Ojeda             if cfg!(debug_assertions) {
625c3739801SMiguel Ojeda                 let e = $e;
626c3739801SMiguel Ojeda                 if !e {
627c3739801SMiguel Ojeda                     let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?));
628c3739801SMiguel Ojeda                 }
629c3739801SMiguel Ojeda             }
630c3739801SMiguel Ojeda         }
631c3739801SMiguel Ojeda     }}
632c3739801SMiguel Ojeda }
633c3739801SMiguel Ojeda 
634c3739801SMiguel Ojeda /// Either invoke `unreachable!()` or `loop {}` depending on whether the Rust
635c3739801SMiguel Ojeda /// toolchain supports panicking in `const fn`.
636c3739801SMiguel Ojeda macro_rules! const_unreachable {
637c3739801SMiguel Ojeda     () => {{
638c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
639c3739801SMiguel Ojeda         unreachable!();
640c3739801SMiguel Ojeda 
641c3739801SMiguel Ojeda         #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
642c3739801SMiguel Ojeda         loop {}
643c3739801SMiguel Ojeda     }};
644c3739801SMiguel Ojeda }
645c3739801SMiguel Ojeda 
646c3739801SMiguel Ojeda /// Asserts at compile time that `$condition` is true for `Self` or the given
647c3739801SMiguel Ojeda /// `$tyvar`s. Unlike `const_assert`, this is *strictly* a compile-time check;
648c3739801SMiguel Ojeda /// it cannot be evaluated in a runtime context. The condition is checked after
649c3739801SMiguel Ojeda /// monomorphization and, upon failure, emits a compile error.
650c3739801SMiguel Ojeda macro_rules! static_assert {
651c3739801SMiguel Ojeda     (Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{
652c3739801SMiguel Ojeda         trait StaticAssert {
653c3739801SMiguel Ojeda             const ASSERT: bool;
654c3739801SMiguel Ojeda         }
655c3739801SMiguel Ojeda 
656c3739801SMiguel Ojeda         impl<T $(: $(? $optbound +)* $($bound +)*)?> StaticAssert for T {
657c3739801SMiguel Ojeda             const ASSERT: bool = {
658c3739801SMiguel Ojeda                 const_assert!($condition $(, $args)*);
659c3739801SMiguel Ojeda                 $condition
660c3739801SMiguel Ojeda             };
661c3739801SMiguel Ojeda         }
662c3739801SMiguel Ojeda 
663c3739801SMiguel Ojeda         const_assert!(<Self as StaticAssert>::ASSERT);
664c3739801SMiguel Ojeda     }};
665c3739801SMiguel Ojeda     ($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{
666c3739801SMiguel Ojeda         trait StaticAssert {
667c3739801SMiguel Ojeda             const ASSERT: bool;
668c3739801SMiguel Ojeda         }
669c3739801SMiguel Ojeda 
670c3739801SMiguel Ojeda         // NOTE: We use `PhantomData` so we can support unsized types.
671c3739801SMiguel Ojeda         impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($(core::marker::PhantomData<$tyvar>,)*) {
672c3739801SMiguel Ojeda             const ASSERT: bool = {
673c3739801SMiguel Ojeda                 const_assert!($condition $(, $args)*);
674c3739801SMiguel Ojeda                 $condition
675c3739801SMiguel Ojeda             };
676c3739801SMiguel Ojeda         }
677c3739801SMiguel Ojeda 
678c3739801SMiguel Ojeda         const_assert!(<($(core::marker::PhantomData<$tyvar>,)*) as StaticAssert>::ASSERT);
679c3739801SMiguel Ojeda     }};
680c3739801SMiguel Ojeda }
681c3739801SMiguel Ojeda 
682c3739801SMiguel Ojeda /// Assert at compile time that `tyvar` does not have a zero-sized DST
683c3739801SMiguel Ojeda /// component.
684c3739801SMiguel Ojeda macro_rules! static_assert_dst_is_not_zst {
685c3739801SMiguel Ojeda     ($tyvar:ident) => {{
686c3739801SMiguel Ojeda         use crate::KnownLayout;
687c3739801SMiguel Ojeda         static_assert!($tyvar: ?Sized + KnownLayout => {
688c3739801SMiguel Ojeda             let dst_is_zst = match $tyvar::LAYOUT.size_info {
689c3739801SMiguel Ojeda                 crate::SizeInfo::Sized { .. } => false,
690c3739801SMiguel Ojeda                 crate::SizeInfo::SliceDst(TrailingSliceLayout { elem_size, .. }) => {
691c3739801SMiguel Ojeda                     elem_size == 0
692c3739801SMiguel Ojeda                 }
693c3739801SMiguel Ojeda             };
694c3739801SMiguel Ojeda             !dst_is_zst
695c3739801SMiguel Ojeda         }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized");
696c3739801SMiguel Ojeda     }}
697c3739801SMiguel Ojeda }
698c3739801SMiguel Ojeda 
699c3739801SMiguel Ojeda /// Defines a named [`Cast`] implementation.
700c3739801SMiguel Ojeda ///
701c3739801SMiguel Ojeda /// # Safety
702c3739801SMiguel Ojeda ///
703c3739801SMiguel Ojeda /// The caller must ensure that, given `src: *mut $src`, `src as *mut $dst` is a
704c3739801SMiguel Ojeda /// size-preserving or size-shrinking cast.
705c3739801SMiguel Ojeda ///
706c3739801SMiguel Ojeda /// [`Cast`]: crate::pointer::cast::Cast
707c3739801SMiguel Ojeda #[macro_export]
708c3739801SMiguel Ojeda #[doc(hidden)]
709c3739801SMiguel Ojeda macro_rules! define_cast {
710c3739801SMiguel Ojeda     // We require the caller to provide an `unsafe` block as part of the input
711c3739801SMiguel Ojeda     // syntax since a call to `define_cast!` is useless inside of an `unsafe`
712c3739801SMiguel Ojeda     // block (since it would introduce a type which can't be named outside of
713c3739801SMiguel Ojeda     // the context of that block).
714c3739801SMiguel Ojeda     (unsafe { $vis:vis $name:ident $(<$tyvar:ident $(: ?$optbound:ident)?>)? = $src:ty => $dst:ty }) => {
715c3739801SMiguel Ojeda         #[allow(missing_debug_implementations, missing_copy_implementations, unreachable_pub)]
716c3739801SMiguel Ojeda         $vis enum $name {}
717c3739801SMiguel Ojeda 
718c3739801SMiguel Ojeda         // SAFETY: The caller promises that `src as *mut $src` is a size-
719c3739801SMiguel Ojeda         // preserving or size-shrinking cast. All operations preserve
720c3739801SMiguel Ojeda         // provenance.
721c3739801SMiguel Ojeda         unsafe impl $(<$tyvar $(: ?$optbound)?>)? $crate::pointer::cast::Project<$src, $dst> for $name {
722c3739801SMiguel Ojeda             fn project(src: $crate::pointer::PtrInner<'_, $src>) -> *mut $dst {
723c3739801SMiguel Ojeda                 #[allow(clippy::as_conversions)]
724c3739801SMiguel Ojeda                 return src.as_ptr() as *mut $dst;
725c3739801SMiguel Ojeda             }
726c3739801SMiguel Ojeda         }
727c3739801SMiguel Ojeda 
728c3739801SMiguel Ojeda         // SAFETY: The impl of `Project::project` preserves referent address.
729c3739801SMiguel Ojeda         unsafe impl $(<$tyvar $(: ?$optbound)?>)? $crate::pointer::cast::Cast<$src, $dst> for $name {}
730c3739801SMiguel Ojeda     };
731c3739801SMiguel Ojeda }
732c3739801SMiguel Ojeda 
733c3739801SMiguel Ojeda /// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper<T>`.
734c3739801SMiguel Ojeda ///
735c3739801SMiguel Ojeda /// # Safety
736c3739801SMiguel Ojeda ///
737c3739801SMiguel Ojeda /// `T` and `$wrapper<T>` must have the same bit validity, and must have the
738c3739801SMiguel Ojeda /// same size in the sense of `CastExact` (specifically, both a
739c3739801SMiguel Ojeda /// `T`-to-`$wrapper<T>` cast and a `$wrapper<T>`-to-`T` cast must be
740c3739801SMiguel Ojeda /// size-preserving).
741c3739801SMiguel Ojeda macro_rules! unsafe_impl_for_transparent_wrapper {
742c3739801SMiguel Ojeda     ($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident<T>) => {{
743c3739801SMiguel Ojeda         crate::util::macros::__unsafe();
744c3739801SMiguel Ojeda 
745c3739801SMiguel Ojeda         use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::Valid};
746c3739801SMiguel Ojeda         use crate::wrappers::ReadOnly;
747c3739801SMiguel Ojeda 
748c3739801SMiguel Ojeda         // SAFETY: The caller promises that `T` and `$wrapper<T>` have the same
749c3739801SMiguel Ojeda         // bit validity.
750c3739801SMiguel Ojeda         unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, Valid, Valid> for $wrapper<T> {}
751c3739801SMiguel Ojeda         // SAFETY: See previous safety comment.
752c3739801SMiguel Ojeda         unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, Valid, Valid> for T {}
753c3739801SMiguel Ojeda         // SAFETY: The caller promises that a `T` to `$wrapper<T>` cast is
754c3739801SMiguel Ojeda         // size-preserving.
755c3739801SMiguel Ojeda         define_cast!(unsafe { $vis CastToWrapper<T $(: ?$optbound)? > = T => $wrapper<T> });
756c3739801SMiguel Ojeda         // SAFETY: The caller promises that a `T` to `$wrapper<T>` cast is
757c3739801SMiguel Ojeda         // size-preserving.
758c3739801SMiguel Ojeda         unsafe impl<T $(: ?$optbound)?> CastExact<T, $wrapper<T>> for CastToWrapper {}
759c3739801SMiguel Ojeda         // SAFETY: The caller promises that a `$wrapper<T>` to `T` cast is
760c3739801SMiguel Ojeda         // size-preserving.
761c3739801SMiguel Ojeda         define_cast!(unsafe { $vis CastFromWrapper<T $(: ?$optbound)? > = $wrapper<T> => T });
762c3739801SMiguel Ojeda         // SAFETY: The caller promises that a `$wrapper<T>` to `T` cast is
763c3739801SMiguel Ojeda         // size-preserving.
764c3739801SMiguel Ojeda         unsafe impl<T $(: ?$optbound)?> CastExact<$wrapper<T>, T> for CastFromWrapper {}
765c3739801SMiguel Ojeda 
766c3739801SMiguel Ojeda         impl<T $(: ?$optbound)?> SizeEq<T> for $wrapper<T> {
767c3739801SMiguel Ojeda             type CastFrom = CastToWrapper;
768c3739801SMiguel Ojeda         }
769c3739801SMiguel Ojeda         impl<T $(: ?$optbound)?> SizeEq<$wrapper<T>> for T {
770c3739801SMiguel Ojeda             type CastFrom = CastFromWrapper;
771c3739801SMiguel Ojeda         }
772c3739801SMiguel Ojeda 
773c3739801SMiguel Ojeda         impl<T $(: ?$optbound)?> SizeEq<ReadOnly<T>> for $wrapper<T> {
774c3739801SMiguel Ojeda             type CastFrom = TransitiveProject<
775c3739801SMiguel Ojeda                 T,
776c3739801SMiguel Ojeda                 <T as SizeEq<ReadOnly<T>>>::CastFrom,
777c3739801SMiguel Ojeda                 CastToWrapper,
778c3739801SMiguel Ojeda             >;
779c3739801SMiguel Ojeda         }
780c3739801SMiguel Ojeda         impl<T $(: ?$optbound)?> SizeEq<$wrapper<T>> for ReadOnly<T> {
781c3739801SMiguel Ojeda             type CastFrom = TransitiveProject<
782c3739801SMiguel Ojeda                 T,
783c3739801SMiguel Ojeda                 CastFromWrapper,
784c3739801SMiguel Ojeda                 <ReadOnly<T> as SizeEq<T>>::CastFrom,
785c3739801SMiguel Ojeda             >;
786c3739801SMiguel Ojeda         }
787c3739801SMiguel Ojeda 
788c3739801SMiguel Ojeda         impl<T $(: ?$optbound)?> SizeEq<ReadOnly<T>> for ReadOnly<$wrapper<T>> {
789c3739801SMiguel Ojeda             type CastFrom = TransitiveProject<
790c3739801SMiguel Ojeda                 $wrapper<T>,
791c3739801SMiguel Ojeda                 <$wrapper<T> as SizeEq<ReadOnly<T>>>::CastFrom,
792c3739801SMiguel Ojeda                 <ReadOnly<$wrapper<T>> as SizeEq<$wrapper<T>>>::CastFrom,
793c3739801SMiguel Ojeda             >;
794c3739801SMiguel Ojeda         }
795c3739801SMiguel Ojeda         impl<T $(: ?$optbound)?> SizeEq<ReadOnly<$wrapper<T>>> for ReadOnly<T> {
796c3739801SMiguel Ojeda             type CastFrom = TransitiveProject<
797c3739801SMiguel Ojeda                 $wrapper<T>,
798c3739801SMiguel Ojeda                 <$wrapper<T> as SizeEq<ReadOnly<$wrapper<T>>>>::CastFrom,
799c3739801SMiguel Ojeda                 <ReadOnly<T> as SizeEq<$wrapper<T>>>::CastFrom,
800c3739801SMiguel Ojeda             >;
801c3739801SMiguel Ojeda         }
802c3739801SMiguel Ojeda     }};
803c3739801SMiguel Ojeda }
804c3739801SMiguel Ojeda 
805c3739801SMiguel Ojeda macro_rules! impl_transitive_transmute_from {
806c3739801SMiguel Ojeda     ($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => {
807c3739801SMiguel Ojeda         const _: () = {
808c3739801SMiguel Ojeda             use crate::pointer::{TransmuteFrom, SizeEq, invariant::Valid};
809c3739801SMiguel Ojeda 
810c3739801SMiguel Ojeda             impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v
811c3739801SMiguel Ojeda             where
812c3739801SMiguel Ojeda                 $u: SizeEq<$t>,
813c3739801SMiguel Ojeda                 $v: SizeEq<$u>,
814c3739801SMiguel Ojeda             {
815c3739801SMiguel Ojeda                 type CastFrom = cast::TransitiveProject<
816c3739801SMiguel Ojeda                     $u,
817c3739801SMiguel Ojeda                     <$u as SizeEq<$t>>::CastFrom,
818c3739801SMiguel Ojeda                     <$v as SizeEq<$u>>::CastFrom
819c3739801SMiguel Ojeda                 >;
820c3739801SMiguel Ojeda             }
821c3739801SMiguel Ojeda 
822c3739801SMiguel Ojeda             // SAFETY: Since `$u: TransmuteFrom<$t, Valid, Valid>`, it is sound
823c3739801SMiguel Ojeda             // to transmute a bit-valid `$t` to a bit-valid `$u`. Since `$v:
824c3739801SMiguel Ojeda             // TransmuteFrom<$u, Valid, Valid>`, it is sound to transmute that
825c3739801SMiguel Ojeda             // bit-valid `$u` to a bit-valid `$v`.
826c3739801SMiguel Ojeda             unsafe impl<$($tyvar $(: ?$optbound)?)?> TransmuteFrom<$t, Valid, Valid> for $v
827c3739801SMiguel Ojeda             where
828c3739801SMiguel Ojeda                 $u: TransmuteFrom<$t, Valid, Valid>,
829c3739801SMiguel Ojeda                 $v: TransmuteFrom<$u, Valid, Valid>,
830c3739801SMiguel Ojeda             {}
831c3739801SMiguel Ojeda         };
832c3739801SMiguel Ojeda     };
833c3739801SMiguel Ojeda }
834c3739801SMiguel Ojeda 
835c3739801SMiguel Ojeda /// A no-op `unsafe fn` for use in macro expansions.
836c3739801SMiguel Ojeda ///
837c3739801SMiguel Ojeda /// Calling this function in a macro expansion ensures that the macro's caller
838c3739801SMiguel Ojeda /// must wrap the call in `unsafe { ... }`.
839c3739801SMiguel Ojeda #[inline(always)]
840c3739801SMiguel Ojeda pub(crate) const unsafe fn __unsafe() {}
841c3739801SMiguel Ojeda 
842c3739801SMiguel Ojeda /// Extracts the contents of doc comments.
843c3739801SMiguel Ojeda #[allow(unused)]
844c3739801SMiguel Ojeda macro_rules! docstring {
845c3739801SMiguel Ojeda     ($(#[doc = $content:expr])*) => {
846c3739801SMiguel Ojeda         concat!($($content, "\n",)*)
847c3739801SMiguel Ojeda     }
848c3739801SMiguel Ojeda }
849c3739801SMiguel Ojeda 
850c3739801SMiguel Ojeda /// Generate a rustdoc-style header with `$name` as the HTML ID for the 'Code
851c3739801SMiguel Ojeda /// Generation' section of documentation.
852c3739801SMiguel Ojeda #[allow(unused)]
853c3739801SMiguel Ojeda macro_rules! codegen_header {
854c3739801SMiguel Ojeda     ($level:expr, $name:expr) => {
855c3739801SMiguel Ojeda         concat!(
856c3739801SMiguel Ojeda             "
857c3739801SMiguel Ojeda <",
858c3739801SMiguel Ojeda             $level,
859c3739801SMiguel Ojeda             " id='method.",
860c3739801SMiguel Ojeda             $name,
861c3739801SMiguel Ojeda             ".codegen'>
862c3739801SMiguel Ojeda     <a class='doc-anchor' href='#method.",
863c3739801SMiguel Ojeda             $name,
864c3739801SMiguel Ojeda             ".codegen'>§</a>
865c3739801SMiguel Ojeda     Code Generation
866c3739801SMiguel Ojeda </",
867c3739801SMiguel Ojeda             $level,
868c3739801SMiguel Ojeda             ">
869c3739801SMiguel Ojeda "
870c3739801SMiguel Ojeda         )
871c3739801SMiguel Ojeda     };
872c3739801SMiguel Ojeda }
873c3739801SMiguel Ojeda 
874c3739801SMiguel Ojeda /// Generates HTML tabs.
875c3739801SMiguel Ojeda #[rustfmt::skip]
876c3739801SMiguel Ojeda #[allow(unused)]
877c3739801SMiguel Ojeda macro_rules! tabs {
878c3739801SMiguel Ojeda     (
879c3739801SMiguel Ojeda         name = $name:expr,
880c3739801SMiguel Ojeda         arity = $arity:literal,
881c3739801SMiguel Ojeda         $([
882c3739801SMiguel Ojeda             $($open:ident)?
883c3739801SMiguel Ojeda             @index $n:literal
884c3739801SMiguel Ojeda             @title $title:literal
885c3739801SMiguel Ojeda             $(#[doc = $content:expr])*
886c3739801SMiguel Ojeda         ]),*
887c3739801SMiguel Ojeda     ) => {
888c3739801SMiguel Ojeda         concat!("
889c3739801SMiguel Ojeda <div class='codegen-tabs' style='--arity: ", $arity ,"'>", $(concat!("
890c3739801SMiguel Ojeda     <details name='tab-", $name,"' style='--n: ", $n ,"'", $(stringify!($open),)*">
891c3739801SMiguel Ojeda         <summary><h6>", $title, "</h6></summary>
892c3739801SMiguel Ojeda         <div>
893c3739801SMiguel Ojeda 
894c3739801SMiguel Ojeda ", $($content, "\n",)* "
895c3739801SMiguel Ojeda \
896c3739801SMiguel Ojeda         </div>
897c3739801SMiguel Ojeda     </details>"),)*
898c3739801SMiguel Ojeda "</div>")
899c3739801SMiguel Ojeda     }
900c3739801SMiguel Ojeda }
901c3739801SMiguel Ojeda 
902c3739801SMiguel Ojeda /// Generates the HTML for a single benchmark example.
903c3739801SMiguel Ojeda #[allow(unused)]
904c3739801SMiguel Ojeda macro_rules! codegen_example {
905c3739801SMiguel Ojeda     (format = $format:expr, bench = $bench:expr) => {
906c3739801SMiguel Ojeda         tabs!(
907c3739801SMiguel Ojeda             name = $bench,
908c3739801SMiguel Ojeda             arity = 4,
909c3739801SMiguel Ojeda             [
910c3739801SMiguel Ojeda                 @index 1
911c3739801SMiguel Ojeda                 @title "Format"
912c3739801SMiguel Ojeda                 /// ```ignore
913c3739801SMiguel Ojeda                 #[doc = include_str!(concat!("../benches/formats/", $format, ".rs"))]
914c3739801SMiguel Ojeda                 /// ```
915c3739801SMiguel Ojeda             ],
916c3739801SMiguel Ojeda             [
917c3739801SMiguel Ojeda                 @index 2
918c3739801SMiguel Ojeda                 @title "Benchmark"
919c3739801SMiguel Ojeda                 /// ```ignore
920c3739801SMiguel Ojeda                 #[doc = include_str!(concat!("../benches/", $bench, ".rs"))]
921c3739801SMiguel Ojeda                 /// ```
922c3739801SMiguel Ojeda             ],
923c3739801SMiguel Ojeda             [
924c3739801SMiguel Ojeda                 open
925c3739801SMiguel Ojeda                 @index 3
926c3739801SMiguel Ojeda                 @title "Assembly"
927c3739801SMiguel Ojeda                 /// ```plain
928c3739801SMiguel Ojeda                 #[doc = include_str!(concat!("../benches/", $bench, ".x86-64"))]
929c3739801SMiguel Ojeda                 /// ```
930c3739801SMiguel Ojeda             ],
931c3739801SMiguel Ojeda             [
932c3739801SMiguel Ojeda                 @index 4
933c3739801SMiguel Ojeda                 @title "Machine Code Analysis"
934c3739801SMiguel Ojeda                 /// ```plain
935c3739801SMiguel Ojeda                 #[doc = include_str!(concat!("../benches/", $bench, ".x86-64.mca"))]
936c3739801SMiguel Ojeda                 /// ```
937c3739801SMiguel Ojeda             ]
938c3739801SMiguel Ojeda         )
939c3739801SMiguel Ojeda     }
940c3739801SMiguel Ojeda }
941c3739801SMiguel Ojeda 
942c3739801SMiguel Ojeda /// Generate the HTML for a suite of benchmark examples.
943c3739801SMiguel Ojeda #[allow(unused)]
944c3739801SMiguel Ojeda macro_rules! codegen_example_suite {
945c3739801SMiguel Ojeda     (
946c3739801SMiguel Ojeda         bench = $bench:expr,
947c3739801SMiguel Ojeda         format = $format:expr,
948c3739801SMiguel Ojeda         arity = $arity:literal,
949c3739801SMiguel Ojeda         $([
950c3739801SMiguel Ojeda             $($open:ident)?
951c3739801SMiguel Ojeda             @index $index:literal
952c3739801SMiguel Ojeda             @title $title:literal
953c3739801SMiguel Ojeda             @variant $variant:literal
954c3739801SMiguel Ojeda         ]),*
955c3739801SMiguel Ojeda     ) => {
956c3739801SMiguel Ojeda         tabs!(
957c3739801SMiguel Ojeda             name = $bench,
958c3739801SMiguel Ojeda             arity = $arity,
959c3739801SMiguel Ojeda             $([
960c3739801SMiguel Ojeda                 $($open)*
961c3739801SMiguel Ojeda                 @index $index
962c3739801SMiguel Ojeda                 @title $title
963c3739801SMiguel Ojeda                 #[doc = codegen_example!(
964c3739801SMiguel Ojeda                     format = concat!($format, "_", $variant),
965c3739801SMiguel Ojeda                     bench = concat!($bench, "_", $variant)
966c3739801SMiguel Ojeda                 )]
967c3739801SMiguel Ojeda             ]),*
968c3739801SMiguel Ojeda         )
969c3739801SMiguel Ojeda     }
970c3739801SMiguel Ojeda }
971c3739801SMiguel Ojeda 
972c3739801SMiguel Ojeda /// Generates the string for code generation preamble.
973c3739801SMiguel Ojeda #[allow(unused)]
974c3739801SMiguel Ojeda macro_rules! codegen_preamble {
975c3739801SMiguel Ojeda     () => {
976c3739801SMiguel Ojeda         docstring!(
977c3739801SMiguel Ojeda             ///
978c3739801SMiguel Ojeda             /// This abstraction is safe and cheap, but does not necessarily
979c3739801SMiguel Ojeda             /// have zero runtime cost. The codegen you experience in practice
980c3739801SMiguel Ojeda             /// will depend on optimization level, the layout of the destination
981c3739801SMiguel Ojeda             /// type, and what the compiler can prove about the source.
982c3739801SMiguel Ojeda             ///
983c3739801SMiguel Ojeda         )
984c3739801SMiguel Ojeda     }
985c3739801SMiguel Ojeda }
986c3739801SMiguel Ojeda 
987c3739801SMiguel Ojeda /// Stub for rendering codegen documentation; used to break build dependency
988c3739801SMiguel Ojeda /// between benches and zerocopy when re-blessing codegen tests.
989c3739801SMiguel Ojeda #[allow(unused)]
990c3739801SMiguel Ojeda #[cfg(not(doc))]
991c3739801SMiguel Ojeda macro_rules! codegen_section {
992c3739801SMiguel Ojeda     (
993c3739801SMiguel Ojeda         header = $level:expr,
994c3739801SMiguel Ojeda         bench = $bench:expr,
995c3739801SMiguel Ojeda         format = $format:expr,
996c3739801SMiguel Ojeda         arity = $arity:literal,
997c3739801SMiguel Ojeda         $([
998c3739801SMiguel Ojeda             $($open:ident)?
999c3739801SMiguel Ojeda             @index $index:literal
1000c3739801SMiguel Ojeda             @title $title:literal
1001c3739801SMiguel Ojeda             @variant $variant:literal
1002c3739801SMiguel Ojeda         ]),*
1003c3739801SMiguel Ojeda     ) => {
1004c3739801SMiguel Ojeda         ""
1005c3739801SMiguel Ojeda     };
1006c3739801SMiguel Ojeda     (
1007c3739801SMiguel Ojeda         header = $level:expr,
1008c3739801SMiguel Ojeda         bench = $bench:expr,
1009c3739801SMiguel Ojeda         format = $format:expr,
1010c3739801SMiguel Ojeda     ) => {
1011c3739801SMiguel Ojeda         ""
1012c3739801SMiguel Ojeda     };
1013c3739801SMiguel Ojeda }
1014c3739801SMiguel Ojeda 
1015c3739801SMiguel Ojeda /// Generates the HTML for code generation documentation.
1016c3739801SMiguel Ojeda #[allow(unused)]
1017c3739801SMiguel Ojeda #[cfg(doc)]
1018c3739801SMiguel Ojeda macro_rules! codegen_section {
1019c3739801SMiguel Ojeda     (
1020c3739801SMiguel Ojeda         header = $level:expr,
1021c3739801SMiguel Ojeda         bench = $bench:expr,
1022c3739801SMiguel Ojeda         format = $format:expr,
1023c3739801SMiguel Ojeda         arity = $arity:literal,
1024c3739801SMiguel Ojeda         $([
1025c3739801SMiguel Ojeda             $($open:ident)?
1026c3739801SMiguel Ojeda             @index $index:literal
1027c3739801SMiguel Ojeda             @title $title:literal
1028c3739801SMiguel Ojeda             @variant $variant:literal
1029c3739801SMiguel Ojeda         ]),*
1030c3739801SMiguel Ojeda     ) => {
1031c3739801SMiguel Ojeda         concat!(
1032c3739801SMiguel Ojeda             codegen_header!($level, $bench),
1033c3739801SMiguel Ojeda             codegen_preamble!(),
1034c3739801SMiguel Ojeda             docstring!(
1035c3739801SMiguel Ojeda                 ///
1036c3739801SMiguel Ojeda                 /// The below examples illustrate typical codegen for
1037c3739801SMiguel Ojeda                 /// increasingly complex types:
1038c3739801SMiguel Ojeda                 ///
1039c3739801SMiguel Ojeda             ),
1040c3739801SMiguel Ojeda             codegen_example_suite!(
1041c3739801SMiguel Ojeda                 bench = $bench,
1042c3739801SMiguel Ojeda                 format = $format,
1043c3739801SMiguel Ojeda                 arity = $arity,
1044c3739801SMiguel Ojeda                 $([
1045c3739801SMiguel Ojeda                     $($open)*
1046c3739801SMiguel Ojeda                     @index $index
1047c3739801SMiguel Ojeda                     @title $title
1048c3739801SMiguel Ojeda                     @variant $variant
1049c3739801SMiguel Ojeda                 ]),*
1050c3739801SMiguel Ojeda             )
1051c3739801SMiguel Ojeda         )
1052c3739801SMiguel Ojeda     };
1053c3739801SMiguel Ojeda     (
1054c3739801SMiguel Ojeda         header = $level:expr,
1055c3739801SMiguel Ojeda         bench = $bench:expr,
1056c3739801SMiguel Ojeda         format = $format:expr,
1057c3739801SMiguel Ojeda     ) => {
1058c3739801SMiguel Ojeda         concat!(
1059c3739801SMiguel Ojeda             codegen_header!($level, $bench),
1060c3739801SMiguel Ojeda             codegen_preamble!(),
1061c3739801SMiguel Ojeda             codegen_example!(
1062c3739801SMiguel Ojeda                 format = $format,
1063c3739801SMiguel Ojeda                 bench = $bench
1064c3739801SMiguel Ojeda             )
1065c3739801SMiguel Ojeda         )
1066c3739801SMiguel Ojeda     }
1067c3739801SMiguel Ojeda }
1068