Macro zerocopy::macros::impl_or_verify
source · macro_rules! impl_or_verify { ( const $constname:ident : $constty:ident $(,)? $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty ) => { ... }; ( $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty ) => { ... }; ( $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty ) => { ... }; (@impl $impl_block:tt) => { ... }; (@verify $trait:ident, $impl_block:tt) => { ... }; }
Expand description
Implements trait(s) for a type or verifies the given implementation by referencing an existing (derived) implementation.
This macro exists so that we can provide zerocopy-derive as an optional dependency and still get the benefit of using its derives to validate that our trait impls are sound.
When compiling without --cfg 'feature = "derive"
and without --cfg test
,
impl_or_verify!
emits the provided trait impl. When compiling with either
of those cfgs, it is expected that the type in question is deriving the
traits instead. In this case, impl_or_verify!
emits code which validates
that the given trait impl is at least as restrictive as the the impl emitted
by the custom derive. This has the effect of confirming that the impl which
is emitted when the derive
feature is disabled is actually sound (on the
assumption that the impl emitted by the custom derive is sound).
The caller is still required to provide a safety comment (e.g. using the
safety_comment!
macro) . The reason for this restriction is that, while
impl_or_verify!
can guarantee that the provided impl is sound when it is
compiled with the appropriate cfgs, there is no way to guarantee that it is
ever compiled with those cfgs. In particular, it would be possible to
accidentally place an impl_or_verify!
call in a context that is only ever
compiled when the derive
feature is disabled. If that were to happen,
there would be nothing to prevent an unsound trait impl from being emitted.
Requiring a safety comment reduces the likelihood of emitting an unsound
impl in this case, and also provides useful documentation for readers of the
code.
§Example
// Note that these derives are gated by `feature = "derive"`
#[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))]
#[repr(transparent)]
struct Wrapper<T>(T);
safety_comment! {
/// SAFETY:
/// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any
/// zerocopy trait if `T` implements that trait.
impl_or_verify!(T: FromZeroes => FromZeroes for Wrapper<T>);
impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>);
impl_or_verify!(T: AsBytes => AsBytes for Wrapper<T>);
impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>);
}