Skip to content

Make derive macros hygienic #11

@joshlf

Description

@joshlf

Status

Crate name annotation

Sometimes, our derives will be used in a context in which zerocopy isn't called zerocopy. For example, this might happen if zerocopy itself is re-exported from another crate, or if a crate wishes to support deriving zerocopy traits from multiple zerocopy versions (see e.g. #557).

We can take inspiration from Serde, which defines the crate attribute option:

#[serde(crate = "...")]

In other words, we can do:

#[zerocopy(crate = "...")]

However, this isn't enough. For users who wish to invoke derives from multiple versions of zerocopy-derive at once, we need a way of disambiguating which attributes are meant to be consumed by which version of zerocopy-derive. We could provide a disambiguation option like so:

#[zerocopy(crate = "...", derive-version = "...")]

This would let us write code like the following (from #557):

#[cfg_attr(feature = "zerocopy_0_7", derive(zerocopy_0_7::FromBytes))]
#[cfg_attr(feature = "zerocopy_0_8", derive(zerocopy_0_8::FromBytes))]
#[zerocopy(crate = "zerocopy_0_7", derive-version = "0.7")]
#[zerocopy(crate = "zerocopy_0_8", derive-version = "0.8")]
struct Foo {
    ...
}

In this example, each zerocopy-derive would use derive-version to filter out attributes not meant for that version.

Simpler alternative

The above-described design is a bit complex, and requires users to add a new attribute for each zerocopy version. This is especially painful for crates like libc who will have hundreds of uses.

An alternative is to not permit the user to specify the name of the crate, but instead only support a single naming scheme:

#[cfg_attr(feature = "zerocopy_0_7", derive(zerocopy_0_7::FromBytes))]
#[cfg_attr(feature = "zerocopy_0_8", derive(zerocopy_0_8::FromBytes))]
#[zerocopy_rename]
struct Foo {
    ...
}

This has the same semantics as the preceding example, but it assumes that for zerocopy-derive 0.X.Y, the zerocopy crate is imported as zerocopy_X_Y, and for zerocopy-derive X.Y.Z, that zerocopy is imported as zerocopy_X.

Core re-export

We can't rely on core being in scope (or referring to the "real" core crate). However, we can rely on zerocopy being in scope (possibly renamed, as described above). If we re-export core from zerocopy, then we can emit code that doesn't refer to ::core, but instead refers to ::zerocopy::core_reexport.

Mentoring instructions

Interested in contributing? See our contributing guide.

This issue can be tackled in a number of discrete steps. Progress on any one of these would be fantastic, so don't feel like you need to tackle the whole thing!

  • Add support for a #[zerocopy(crate = "...")] annotation similar to serde's
  • Add support for a #[zerocopy_rename] annotation as described above
  • Add support for a #[zerocopy(crate = "...", derive-version = "...")] annotation as described above

Metadata

Metadata

Assignees

No one assigned

    Labels

    compatibility-nonbreakingChanges that are (likely to be) non-breakingexperience-hardThis issue is hard, and requires a lot of experiencegoogle-20%-projectPotential 20% project for a Google employeehelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions