macro_rules! unsafe_impl {
($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident| $is_bit_valid:expr)?) => {{
crate::util::macros::__unsafe();
$(#[$attr])*
unsafe impl $trait for $ty {
unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
}
}};
($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => {
unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*)
};
(@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => {{
$( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )*
}};
(@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => {
unsafe_impl!($(#[$attrs])* $ty: $traits);
};
(
$(#[$attr:meta])*
const $constname:ident : $constty:ident $(,)?
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
=> $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
) => {
unsafe_impl!(
@inner
$(#[$attr])*
@const $constname: $constty,
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
=> $trait for $ty $(; |$candidate| $is_bit_valid)?
);
};
(
$(#[$attr:meta])*
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
=> $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
) => {{
unsafe_impl!(
@inner
$(#[$attr])*
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
=> $trait for $ty $(; |$candidate| $is_bit_valid)?
);
}};
(
@inner
$(#[$attr:meta])*
$(@const $constname:ident : $constty:ident,)*
$($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
=> $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
) => {{
crate::util::macros::__unsafe();
$(#[$attr])*
#[allow(non_local_definitions)]
unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* $(, const $constname: $constty,)*> $trait for $ty {
unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
}
}};
(@method TryFromBytes ; |$candidate:ident| $is_bit_valid:expr) => {
#[allow(clippy::missing_inline_in_public_items, dead_code)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline]
fn is_bit_valid<Alignment>($candidate: Maybe<'_, Self, Alignment>) -> bool
where
Alignment: crate::invariant::Alignment,
{
$is_bit_valid
}
};
(@method TryFromBytes) => {
#[allow(clippy::missing_inline_in_public_items)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)]
fn is_bit_valid<Alignment>(_candidate: Maybe<'_, Self, Alignment>) -> bool
where
Alignment: crate::invariant::Alignment,
{
true
}
};
(@method $trait:ident) => {
#[allow(clippy::missing_inline_in_public_items, dead_code)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {}
};
(@method $trait:ident; |$_candidate:ident| $_is_bit_valid:expr) => {
compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
};
}
macro_rules! impl_for_transmute_from {
(
$(#[$attr:meta])*
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)?
=> $trait:ident for $ty:ty [$repr:ty]
) => {
const _: () = {
$(#[$attr])*
#[allow(non_local_definitions)]
unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty {
#[allow(dead_code, clippy::missing_inline_in_public_items)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {
use crate::pointer::{*, invariant::Valid};
impl_for_transmute_from!(@assert_is_supported_trait $trait);
fn is_trait<T, R>()
where
T: TransmuteFrom<R, Valid, Valid> + ?Sized,
R: TransmuteFrom<T, Valid, Valid> + ?Sized,
R: $trait,
{
}
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() {
is_trait::<$ty, $repr>();
}
}
impl_for_transmute_from!(
@is_bit_valid
$(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
$trait for $ty [$repr]
);
}
};
};
(@assert_is_supported_trait TryFromBytes) => {};
(@assert_is_supported_trait FromZeros) => {};
(@assert_is_supported_trait FromBytes) => {};
(@assert_is_supported_trait IntoBytes) => {};
(
@is_bit_valid
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
TryFromBytes for $ty:ty [$repr:ty]
) => {
#[inline(always)]
fn is_bit_valid<Alignment>(candidate: $crate::Maybe<'_, Self, Alignment>) -> bool
where
Alignment: $crate::invariant::Alignment,
{
<$repr as TryFromBytes>::is_bit_valid(candidate.transmute::<_, _, BecauseImmutable>())
}
};
(
@is_bit_valid
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
$trait:ident for $ty:ty [$repr:ty]
) => {
};
}
macro_rules! unsafe_impl_for_power_set {
(
$first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
$(; |$candidate:ident| $is_bit_valid:expr)?
) => {
unsafe_impl_for_power_set!(
$($rest),* $(-> $ret)? => $trait for $macro!(...)
$(; |$candidate| $is_bit_valid)?
);
unsafe_impl_for_power_set!(
@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...)
$(; |$candidate| $is_bit_valid)?
);
};
(
$(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
$(; |$candidate:ident| $is_bit_valid:expr)?
) => {
unsafe_impl_for_power_set!(
@impl $(-> $ret)? => $trait for $macro!(...)
$(; |$candidate| $is_bit_valid)?
);
};
(
@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
$(; |$candidate:ident| $is_bit_valid:expr)?
) => {
unsafe_impl!(
$($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?)
$(; |$candidate| $is_bit_valid)?
);
};
}
macro_rules! opt_extern_c_fn {
($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
}
macro_rules! opt_unsafe_extern_c_fn {
($($args:ident),* -> $ret:ident) => { Option<unsafe extern "C" fn($($args),*) -> $ret> };
}
macro_rules! opt_fn {
($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
}
macro_rules! opt_unsafe_fn {
($($args:ident),* -> $ret:ident) => { Option<unsafe fn($($args),*) -> $ret> };
}
#[allow(rustdoc::private_intra_doc_links)]
#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE, macro_export)] #[doc(hidden)]
macro_rules! impl_or_verify {
(
const $constname:ident : $constty:ident $(,)?
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
=> $trait:ident for $ty:ty
) => {
impl_or_verify!(@impl { unsafe_impl!(
const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
); });
impl_or_verify!(@verify $trait, {
impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
});
};
(
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
=> $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
) => {
impl_or_verify!(@impl { unsafe_impl!(
$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
$(; |$candidate| $is_bit_valid)?
); });
impl_or_verify!(@verify $trait, {
impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
});
};
(@impl $impl_block:tt) => {
#[cfg(not(any(feature = "derive", test)))]
{ $impl_block };
};
(@verify $trait:ident, $impl_block:tt) => {
#[cfg(any(feature = "derive", test))]
{
#[allow(dead_code)]
trait Subtrait: $trait {}
$impl_block
};
};
}
macro_rules! impl_known_layout {
($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
$(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
};
($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
$(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
};
($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* };
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => {
const _: () = {
use core::ptr::NonNull;
#[allow(non_local_definitions)]
$(#[$attrs])*
unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty {
#[allow(clippy::missing_inline_in_public_items)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
type PointerMetadata = ();
type MaybeUninit = core::mem::MaybeUninit<Self>;
const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>();
#[inline(always)]
fn raw_from_ptr_len(bytes: NonNull<u8>, _meta: ()) -> NonNull<Self> {
bytes.cast::<Self>()
}
#[inline(always)]
fn pointer_to_metadata(_ptr: *mut Self) -> () {
}
}
};
};
}
macro_rules! unsafe_impl_known_layout {
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {{
use core::ptr::NonNull;
crate::util::macros::__unsafe();
#[allow(non_local_definitions)]
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
#[allow(clippy::missing_inline_in_public_items, dead_code)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {}
type PointerMetadata = <$repr as KnownLayout>::PointerMetadata;
type MaybeUninit = <$repr as KnownLayout>::MaybeUninit;
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
#[inline(always)]
fn raw_from_ptr_len(bytes: NonNull<u8>, meta: <$repr as KnownLayout>::PointerMetadata) -> NonNull<Self> {
#[allow(clippy::as_conversions)]
let ptr = <$repr>::raw_from_ptr_len(bytes, meta).as_ptr() as *mut Self;
unsafe { NonNull::new_unchecked(ptr) }
}
#[inline(always)]
fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
#[allow(clippy::as_conversions)]
let ptr = ptr as *mut $repr;
<$repr>::pointer_to_metadata(ptr)
}
}
}};
}
macro_rules! assert_unaligned {
($($tys:ty),*) => {
$(
#[cfg(test)]
static_assertions::const_assert_eq!(core::mem::align_of::<$tys>(), 1);
)*
};
}
macro_rules! maybe_const_trait_bounded_fn {
($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => {
#[cfg(not(no_zerocopy_generic_bounds_in_const_fn_1_61_0))]
$(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
#[cfg(no_zerocopy_generic_bounds_in_const_fn_1_61_0)]
$(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
};
}
macro_rules! const_panic {
(@non_panic $($_arg:tt)+) => {{
let panic: [_; 0] = [];
#[allow(unconditional_panic)]
panic[0]
}};
($($arg:tt)+) => {{
#[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
panic!($($arg)+);
#[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
const_panic!(@non_panic $($arg)+)
}};
}
macro_rules! const_assert {
($e:expr) => {{
#[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
assert!($e);
#[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
{
let e = $e;
if !e {
let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e)));
}
}
}};
($e:expr, $($args:tt)+) => {{
#[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
assert!($e, $($args)+);
#[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
{
let e = $e;
if !e {
let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*);
}
}
}};
}
macro_rules! const_debug_assert {
($e:expr $(, $msg:expr)?) => {{
#[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
debug_assert!($e $(, $msg)?);
#[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
{
if cfg!(debug_assertions) {
let e = $e;
if !e {
let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?));
}
}
}
}}
}
macro_rules! const_unreachable {
() => {{
#[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
unreachable!();
#[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
loop {}
}};
}
macro_rules! static_assert {
(Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{
trait StaticAssert {
const ASSERT: bool;
}
impl<T $(: $(? $optbound +)* $($bound +)*)?> StaticAssert for T {
const ASSERT: bool = {
const_assert!($condition $(, $args)*);
$condition
};
}
const_assert!(<Self as StaticAssert>::ASSERT);
}};
($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{
trait StaticAssert {
const ASSERT: bool;
}
impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($(core::marker::PhantomData<$tyvar>,)*) {
const ASSERT: bool = {
const_assert!($condition $(, $args)*);
$condition
};
}
const_assert!(<($(core::marker::PhantomData<$tyvar>,)*) as StaticAssert>::ASSERT);
}};
}
macro_rules! static_assert_dst_is_not_zst {
($tyvar:ident) => {{
use crate::KnownLayout;
static_assert!($tyvar: ?Sized + KnownLayout => {
let dst_is_zst = match $tyvar::LAYOUT.size_info {
crate::SizeInfo::Sized { .. } => false,
crate::SizeInfo::SliceDst(TrailingSliceLayout { elem_size, .. }) => {
elem_size == 0
}
};
!dst_is_zst
}, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized");
}}
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_cast {
(unsafe { $vis:vis $name:ident $(<$tyvar:ident $(: ?$optbound:ident)?>)? = $src:ty => $dst:ty }) => {
#[allow(missing_debug_implementations, missing_copy_implementations, unreachable_pub)]
$vis enum $name {}
unsafe impl $(<$tyvar $(: ?$optbound)?>)? $crate::pointer::cast::Project<$src, $dst> for $name {
fn project(src: $crate::pointer::PtrInner<'_, $src>) -> *mut $dst {
#[allow(clippy::as_conversions)]
return src.as_ptr() as *mut $dst;
}
}
unsafe impl $(<$tyvar $(: ?$optbound)?>)? $crate::pointer::cast::Cast<$src, $dst> for $name {}
};
}
macro_rules! unsafe_impl_for_transparent_wrapper {
($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident<T>) => {{
crate::util::macros::__unsafe();
use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::Valid};
use crate::wrappers::ReadOnly;
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, Valid, Valid> for $wrapper<T> {}
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, Valid, Valid> for T {}
define_cast!(unsafe { $vis CastToWrapper<T $(: ?$optbound)? > = T => $wrapper<T> });
unsafe impl<T $(: ?$optbound)?> CastExact<T, $wrapper<T>> for CastToWrapper {}
define_cast!(unsafe { $vis CastFromWrapper<T $(: ?$optbound)? > = $wrapper<T> => T });
unsafe impl<T $(: ?$optbound)?> CastExact<$wrapper<T>, T> for CastFromWrapper {}
impl<T $(: ?$optbound)?> SizeEq<T> for $wrapper<T> {
type CastFrom = CastToWrapper;
}
impl<T $(: ?$optbound)?> SizeEq<$wrapper<T>> for T {
type CastFrom = CastFromWrapper;
}
impl<T $(: ?$optbound)?> SizeEq<ReadOnly<T>> for $wrapper<T> {
type CastFrom = TransitiveProject<
T,
<T as SizeEq<ReadOnly<T>>>::CastFrom,
CastToWrapper,
>;
}
impl<T $(: ?$optbound)?> SizeEq<$wrapper<T>> for ReadOnly<T> {
type CastFrom = TransitiveProject<
T,
CastFromWrapper,
<ReadOnly<T> as SizeEq<T>>::CastFrom,
>;
}
impl<T $(: ?$optbound)?> SizeEq<ReadOnly<T>> for ReadOnly<$wrapper<T>> {
type CastFrom = TransitiveProject<
$wrapper<T>,
<$wrapper<T> as SizeEq<ReadOnly<T>>>::CastFrom,
<ReadOnly<$wrapper<T>> as SizeEq<$wrapper<T>>>::CastFrom,
>;
}
impl<T $(: ?$optbound)?> SizeEq<ReadOnly<$wrapper<T>>> for ReadOnly<T> {
type CastFrom = TransitiveProject<
$wrapper<T>,
<$wrapper<T> as SizeEq<ReadOnly<$wrapper<T>>>>::CastFrom,
<ReadOnly<T> as SizeEq<$wrapper<T>>>::CastFrom,
>;
}
}};
}
macro_rules! impl_transitive_transmute_from {
($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => {
const _: () = {
use crate::pointer::{TransmuteFrom, SizeEq, invariant::Valid};
impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v
where
$u: SizeEq<$t>,
$v: SizeEq<$u>,
{
type CastFrom = cast::TransitiveProject<
$u,
<$u as SizeEq<$t>>::CastFrom,
<$v as SizeEq<$u>>::CastFrom
>;
}
unsafe impl<$($tyvar $(: ?$optbound)?)?> TransmuteFrom<$t, Valid, Valid> for $v
where
$u: TransmuteFrom<$t, Valid, Valid>,
$v: TransmuteFrom<$u, Valid, Valid>,
{}
};
};
}
#[inline(always)]
pub(crate) const unsafe fn __unsafe() {}
#[allow(unused)]
macro_rules! docstring {
($(#[doc = $content:expr])*) => {
concat!($($content, "\n",)*)
}
}
#[allow(unused)]
macro_rules! codegen_header {
($level:expr, $name:expr) => {
concat!(
"
<",
$level,
" id='method.",
$name,
".codegen'>
<a class='doc-anchor' href='#method.",
$name,
".codegen'>ยง</a>
Code Generation
</",
$level,
">
"
)
};
}
#[rustfmt::skip]
#[allow(unused)]
macro_rules! tabs {
(
name = $name:expr,
arity = $arity:literal,
$([
$($open:ident)?
@index $n:literal
@title $title:literal
$(#[doc = $content:expr])*
]),*
) => {
concat!("
<div class='codegen-tabs' style='--arity: ", $arity ,"'>", $(concat!("
<details name='tab-", $name,"' style='--n: ", $n ,"'", $(stringify!($open),)*">
<summary><h6>", $title, "</h6></summary>
<div>
", $($content, "\n",)* "
\
</div>
</details>"),)*
"</div>")
}
}
#[allow(unused)]
macro_rules! codegen_example {
(format = $format:expr, bench = $bench:expr) => {
tabs!(
name = $bench,
arity = 4,
[
@index 1
@title "Format"
#[doc = include_str!(concat!("../benches/formats/", $format, ".rs"))]
],
[
@index 2
@title "Benchmark"
#[doc = include_str!(concat!("../benches/", $bench, ".rs"))]
],
[
open
@index 3
@title "Assembly"
#[doc = include_str!(concat!("../benches/", $bench, ".x86-64"))]
],
[
@index 4
@title "Machine Code Analysis"
#[doc = include_str!(concat!("../benches/", $bench, ".x86-64.mca"))]
]
)
}
}
#[allow(unused)]
macro_rules! codegen_example_suite {
(
bench = $bench:expr,
format = $format:expr,
arity = $arity:literal,
$([
$($open:ident)?
@index $index:literal
@title $title:literal
@variant $variant:literal
]),*
) => {
tabs!(
name = $bench,
arity = $arity,
$([
$($open)*
@index $index
@title $title
#[doc = codegen_example!(
format = concat!($format, "_", $variant),
bench = concat!($bench, "_", $variant)
)]
]),*
)
}
}
#[allow(unused)]
macro_rules! codegen_preamble {
() => {
docstring!(
)
}
}
#[allow(unused)]
macro_rules! codegen_section {
(
header = $level:expr,
bench = $bench:expr,
format = $format:expr,
arity = $arity:literal,
$([
$($open:ident)?
@index $index:literal
@title $title:literal
@variant $variant:literal
]),*
) => {
concat!(
codegen_header!($level, $bench),
codegen_preamble!(),
docstring!(
///
/// The below examples illustrate typical codegen for
/// increasingly complex types:
///
),
codegen_example_suite!(
bench = $bench,
format = $format,
arity = $arity,
$([
$($open)*
@index $index
@title $title
@variant $variant
]),*
)
)
};
(
header = $level:expr,
bench = $bench:expr,
format = $format:expr,
) => {
concat!(
codegen_header!($level, $bench),
codegen_preamble!(),
codegen_example!(
format = $format,
bench = $bench
)
)
}
}