macro_rules! safety_comment {
(#[doc = r" SAFETY:"] $($(#[$attr:meta])* $macro:ident!$args:tt;)*) => {
#[allow(clippy::undocumented_unsafe_blocks, unused_attributes)]
const _: () = { $($(#[$attr])* $macro!$args;)* };
}
}
macro_rules! unsafe_impl {
($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident: MaybeAligned<$repr:ty>| $is_bit_valid:expr)?) => {
$(#[$attr])*
unsafe impl $trait for $ty {
unsafe_impl!(@method $trait $(; |$candidate: MaybeAligned<$repr>| $is_bit_valid)?);
}
};
($ty:ty: $($traits:ident),*) => {
$( unsafe_impl!($ty: $traits); )*
};
(
$(#[$attr:meta])*
const $constname:ident : $constty:ident $(,)?
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
unsafe_impl!(
@inner
$(#[$attr])*
@const $constname: $constty,
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
=> $trait for $ty $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)?
);
};
(
$(#[$attr:meta])*
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
unsafe_impl!(
@inner
$(#[$attr])*
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
=> $trait for $ty $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)?
);
};
(
@inner
$(#[$attr:meta])*
$(@const $constname:ident : $constty:ident,)*
$($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
$(#[$attr])*
#[allow(non_local_definitions)]
unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* $(, const $constname: $constty,)*> $trait for $ty {
unsafe_impl!(@method $trait $(; |$candidate: $(MaybeAligned<$ref_repr>)? $(Maybe<$ptr_repr>)?| $is_bit_valid)?);
}
};
(@method TryFromBytes ; |$candidate:ident: MaybeAligned<$repr:ty>| $is_bit_valid:expr) => {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline]
fn is_bit_valid<AA: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(candidate: Maybe<'_, Self, AA>) -> bool {
#[allow(clippy::as_conversions)]
let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
let $candidate = unsafe { candidate.assume_validity::<crate::pointer::invariant::Valid>() };
$is_bit_valid
}
};
(@method TryFromBytes ; |$candidate:ident: Maybe<$repr:ty>| $is_bit_valid:expr) => {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline]
fn is_bit_valid<AA: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(candidate: Maybe<'_, Self, AA>) -> bool {
#[allow(clippy::as_conversions)]
let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
let $candidate = unsafe { $candidate.assume_validity::<crate::pointer::invariant::Initialized>() };
$is_bit_valid
}
};
(@method TryFromBytes) => {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)] fn is_bit_valid<A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(_: Maybe<'_, Self, A>) -> bool { true }
};
(@method $trait:ident) => {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}
};
(@method $trait:ident; |$_candidate:ident $(: &$_ref_repr:ty)? $(: NonNull<$_ptr_repr:ty>)?| $_is_bit_valid:expr) => {
compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
};
}
macro_rules! impl_for_transparent_wrapper {
(
$(#[$attr:meta])*
$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
$(#[$attr])*
#[allow(non_local_definitions)]
unsafe impl<$tyvar: $($(? $optbound +)* $($bound +)*)? $trait> $trait for $ty {
#[allow(dead_code, clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {
use crate::{pointer::invariant::Invariants, util::*};
impl_for_transparent_wrapper!(@is_transparent_wrapper $trait);
fn f<I: Invariants, $tyvar $(: $(? $optbound +)* $($bound +)*)?>() {
is_transparent_wrapper::<I, $tyvar, $ty>();
}
}
impl_for_transparent_wrapper!(
@is_bit_valid
<$tyvar: $($(? $optbound +)* $($bound +)*)?>
$trait for $ty
);
}
};
(
$(#[$attr:meta])*
for $ty:ty [$inner:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {};
(
$(#[$attr:meta])*
$trait:ident $(, $traits:ident)* for $ty:ty [$inner:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
impl_for_transparent_wrapper!(
$(#[$attr])*
$($traits),* for $ty [$inner] $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid:expr)?
);
$(#[$attr])*
#[allow(non_local_definitions)]
unsafe impl $trait for $ty {
#[allow(dead_code, clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {
use crate::{pointer::invariant::Invariants, util::*};
impl_for_transparent_wrapper!(@is_transparent_wrapper $trait);
fn f<I: Invariants>() {
is_transparent_wrapper::<I, $inner, $ty>();
}
}
impl_for_transparent_wrapper!(@is_bit_valid $trait for $ty);
}
};
(@is_transparent_wrapper Immutable) => {
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, UnsafeCellVariance=Covariant> + ?Sized>() {}
};
(@is_transparent_wrapper FromZeros) => {
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, ValidityVariance=Covariant> + ?Sized>() {}
};
(@is_transparent_wrapper FromBytes) => {
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, ValidityVariance=Covariant> + ?Sized>() {}
};
(@is_transparent_wrapper IntoBytes) => {
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, ValidityVariance=Covariant> + ?Sized>() {}
};
(@is_transparent_wrapper Unaligned) => {
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, AlignmentVariance=Covariant> + ?Sized>() {}
};
(@is_transparent_wrapper TryFromBytes) => {
fn is_transparent_wrapper<I: Invariants, T: ?Sized, W: TransparentWrapper<I, Inner=T, ValidityVariance=Covariant> + ?Sized>() {}
};
(
@is_bit_valid
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
TryFromBytes for $ty:ty
) => {
#[inline]
fn is_bit_valid<A: crate::pointer::invariant::Aliasing + crate::pointer::invariant::AtLeast<invariant::Shared>>(candidate: Maybe<'_, Self, A>) -> bool {
TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner())
}
};
(
@is_bit_valid
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
$trait:ident for $ty:ty
) => {
};
}
macro_rules! unsafe_impl_for_power_set {
(
$first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
$(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
unsafe_impl_for_power_set!(
$($rest),* $(-> $ret)? => $trait for $macro!(...)
$(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)?
);
unsafe_impl_for_power_set!(
@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...)
$(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)?
);
};
(
$(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
$(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
unsafe_impl_for_power_set!(
@impl $(-> $ret)? => $trait for $macro!(...)
$(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)?
);
};
(
@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
$(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
unsafe_impl!(
$($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?)
$(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)?
);
};
}
macro_rules! opt_extern_c_fn {
($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
}
macro_rules! opt_fn {
($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
}
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 $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
impl_or_verify!(@impl { unsafe_impl!(
$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
$(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $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)))]
const _: () = { $impl_block };
};
(@verify $trait:ident, $impl_block:tt) => {
#[cfg(any(feature = "derive", test))]
const _: () = {
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);)*
};
($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* };
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => {
const _: () = {
use core::ptr::NonNull;
unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
type PointerMetadata = ();
#[allow(unused_qualifications)]
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: NonNull<Self>) -> () {
}
}
};
};
}
macro_rules! unsafe_impl_known_layout {
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
const _: () = {
use core::ptr::NonNull;
#[allow(non_local_definitions)]
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}
type PointerMetadata = <$repr as KnownLayout>::PointerMetadata;
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
#[inline(always)]
#[allow(unused_qualifications)] 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: NonNull<Self>) -> Self::PointerMetadata {
#[allow(clippy::as_conversions)]
let ptr = unsafe { NonNull::new_unchecked(ptr.as_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(zerocopy_generic_bounds_in_const_fn)]
$(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
#[cfg(not(zerocopy_generic_bounds_in_const_fn))]
$(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
};
}
macro_rules! const_panic {
($fmt:literal) => {{
#[cfg(zerocopy_panic_in_const)]
panic!($fmt);
#[cfg(not(zerocopy_panic_in_const))]
const_panic!(@non_panic $fmt)
}};
(@non_panic $fmt:expr) => {{
let panic: [_; 0] = [];
#[allow(unconditional_panic)]
panic[0]
}}
}
macro_rules! const_assert {
($e:expr) => {{
#[cfg(zerocopy_panic_in_const)]
assert!($e);
#[cfg(not(zerocopy_panic_in_const))]
{
let e = $e;
if !e {
let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e)));
}
}
}}
}
macro_rules! const_debug_assert {
($e:expr $(, $msg:expr)?) => {{
#[cfg(zerocopy_panic_in_const)]
debug_assert!($e $(, $msg)?);
#[cfg(not(zerocopy_panic_in_const))]
{
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(zerocopy_panic_in_const)]
unreachable!();
#[cfg(not(zerocopy_panic_in_const))]
loop {}
}};
}