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>);
}